about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--company-sql.el93
1 files changed, 75 insertions, 18 deletions
diff --git a/company-sql.el b/company-sql.el
index c19182f9174d..58c57dde80e5 100644
--- a/company-sql.el
+++ b/company-sql.el
@@ -38,9 +38,6 @@
                               :port (number-to-string company-sql-db-port))))
   company-sql/connection)
 
-(defun company-sql/query (&rest args)
-  (apply 'emacsql (cons (company-sql/connect) args)))
-
 ;;; Utils
 
 (defmacro comment (&rest _))
@@ -50,23 +47,29 @@
    ((stringp x) x)
    ((symbolp x) (symbol-name x))))
 
+(defun alist-get-equal (key alist)
+  "Like `alist-get', but uses `equal' instead of `eq' for comparing keys"
+  (->> alist
+       (-find (lambda (pair) (equal key (car pair))))
+       (cdr)))
+
 ;;; Listing relations
 
-(defun company-sql/list-tables ()
+(cl-defun company-sql/list-tables (conn)
   (-map (-compose 'symbol-name 'car)
-        (company-sql/query
+        (emacsql conn
          [:select [tablename]
           :from pg_catalog:pg_tables
           :where (and (!= schemaname '"information_schema")
                       (!= schemaname '"pg_catalog"))])))
 
-(defun company-sql/list-columns ()
+(cl-defun company-sql/list-columns (conn)
   (-map
    (lambda (row)
      (propertize (symbol-name (nth 0 row))
                  'table-name (nth 1 row)
                  'data-type  (nth 2 row)))
-   (company-sql/query
+   (emacsql conn
     [:select [column_name
               table_name
               data_type]
@@ -187,12 +190,12 @@
 
 ;;; Company backend
 
-(defun company-postgresql/candidates (prefix)
+(cl-defun company-postgresql/candidates (prefix conn)
   (-filter
    (apply-partially #'s-starts-with? prefix)
    (append (-map (lambda (s)
                    (propertize s 'company-postgresql-annotation "table"))
-                 (company-sql/list-tables))
+                 (company-sql/list-tables conn))
            (-map (lambda (s)
                    (propertize s 'company-postgresql-annotation
                                (format "%s.%s %s"
@@ -202,7 +205,7 @@
                                         (get-text-property 0 'data-type s)
                                         (->string)
                                         (upcase)))))
-                 (company-sql/list-columns))
+                 (company-sql/list-columns conn))
            (-map (lambda (s)
                    (propertize s 'company-postgresql-annotation "keyword"))
                  company-postgresql/keywords))))
@@ -212,31 +215,85 @@
   (cl-case command
     (interactive (company-begin-backend 'company-postgresql))
     (init (company-sql/connect))
-    (prefix (if (bound-and-true-p org-mode)
-                (when (company-sql/in-sql-source-block-p)
-                  (company-grab-symbol))
-              (company-grab-symbol)))
+    (prefix (company-grab-symbol))
     (annotation
      (get-text-property 0 'company-postgresql-annotation arg))
-    (candidates (company-postgresql/candidates arg))
+    (candidates (company-postgresql/candidates
+                 arg
+                 (company-sql/connect)))
     (duplicates t)
     (ignore-case t)))
 
 ;;; org-babel company sql
 
-(defvar-local org-company-sql/connections)
+(defvar-local org-company-sql/connections
+  ())
+
+(defun org-company-sql/connect (conn-params)
+  (car                                  ; ???
+   (or (alist-get-equal conn-params org-company-sql/connections)
+       (let ((conn (apply 'emacsql-psql conn-params)))
+         (add-to-list 'org-company-sql/connections (cons conn-params conn))
+         conn))))
 
-(defun company-sql/in-sql-source-block-p ()
+(defun org-company-sql/in-sql-source-block-p ()
   (let ((org-elt (org-element-at-point)))
     (and (eq 'src-block (car org-elt))
          (equal "sql" (plist-get (cadr org-elt)
                                  :language)))))
 
+(defun org-company-sql/parse-cmdline (cmdline)
+  (let* ((lexed (s-split (rx (one-or-more blank)) cmdline))
+         (go (lambda (state tokens)
+               (if (null tokens) ()
+                 (let ((token (car tokens))
+                       (tokens (cdr tokens)))
+                   (if (null state)
+                       (if (s-starts-with? "-" token)
+                           (funcall go token tokens)
+                         (cons token (funcall go state tokens)))
+                     (cons (cons state token)  ; ("-h" . "localhost")
+                           (funcall go nil tokens)))))))
+         (opts (funcall go nil lexed)))
+    opts))
+
+(defun org-company-sql/source-block-conn-params ()
+  (let* ((block-info (org-babel-get-src-block-info))
+         (params (caddr block-info))
+         (cmdline (alist-get :cmdline params))
+         (parsed (org-company-sql/parse-cmdline cmdline))
+         (opts (-filter #'listp parsed))
+         (positional (-filter #'stringp parsed))
+         (host (alist-get-equal "-h" opts))
+         (port (or (alist-get-equal "-p" opts)
+                   "5432"))
+         (dbname (or (alist-get-equal "-d" opts)
+                     (car positional)))
+         (username (or (alist-get-equal "-U" opts)
+                       (cadr positional))))
+    (list dbname
+          :hostname host
+          :username username
+          :port port)))
+
+(defun org-company-sql/connection-for-source-block ()
+  (org-company-sql/connect
+   (org-company-sql/source-block-conn-params)))
+
+
 (defun company-ob-postgresql (command &optional arg &rest _)
   (interactive (list 'interactive))
   (cl-case command
     (interactive (company-begin-backend 'company-ob-postgresql))
-    (init (company-sql/connect))))
+    (prefix (and (org-company-sql/in-sql-source-block-p)
+                 (company-grab-symbol)))
+    (annotation (get-text-property 0 'company-postgresql-annotation arg))
+    (candidates
+     (company-postgresql/candidates
+      arg
+      (org-company-sql/connection-for-source-block)))
+    (duplicates t)
+    (ignore-case t)))
 
 ;;;