From 8d32838442481118c2a26f18b9e1e86553575980 Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Tue, 22 Jan 2019 15:14:24 +0100 Subject: [PATCH] Update ejc-sql. Signed-off-by: Andreas Gerler --- .../ejc-autocomplete.el | 112 +++--------- .../ejc-direx.el | 0 .../ejc-doc.el | 0 elpa/ejc-sql-20190121.1043/ejc-flx.el | 103 +++++++++++ .../ejc-format.el | 81 ++++++--- .../ejc-interaction.el | 7 +- .../ejc-lib.el | 0 .../ejc-result-mode.el | 0 .../ejc-sql-autoloads.el | 12 ++ .../ejc-sql-pkg.el | 2 +- .../ejc-sql.el | 167 ++++++++++++++---- .../project.clj | 2 +- .../snippets/sql-mode/begin.snippet | 7 + .../snippets/sql-mode/delete.yasnippet | 5 + .../snippets/sql-mode/insert.yasnippet | 6 + .../snippets/sql-mode/select.yasnippet | 7 + .../snippets/sql-mode/update.yasnippet | 7 + .../snippets/sql-mode/where.yasnippet | 5 + .../src/ejc_sql/connect.clj | 78 +++++--- .../src/ejc_sql/jpa.clj | 0 .../src/ejc_sql/lib.clj | 0 .../src/ejc_sql/output.clj | 12 +- .../src/ejc_sql/structure.clj | 155 ++++++++++------ elpa/ejc-sql-readme.txt | 4 - 24 files changed, 530 insertions(+), 242 deletions(-) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/ejc-autocomplete.el (61%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/ejc-direx.el (100%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/ejc-doc.el (100%) create mode 100644 elpa/ejc-sql-20190121.1043/ejc-flx.el rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/ejc-format.el (74%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/ejc-interaction.el (98%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/ejc-lib.el (100%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/ejc-result-mode.el (100%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/ejc-sql-autoloads.el (92%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/ejc-sql-pkg.el (85%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/ejc-sql.el (80%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/project.clj (91%) create mode 100644 elpa/ejc-sql-20190121.1043/snippets/sql-mode/begin.snippet create mode 100644 elpa/ejc-sql-20190121.1043/snippets/sql-mode/delete.yasnippet create mode 100644 elpa/ejc-sql-20190121.1043/snippets/sql-mode/insert.yasnippet create mode 100644 elpa/ejc-sql-20190121.1043/snippets/sql-mode/select.yasnippet create mode 100644 elpa/ejc-sql-20190121.1043/snippets/sql-mode/update.yasnippet create mode 100644 elpa/ejc-sql-20190121.1043/snippets/sql-mode/where.yasnippet rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/src/ejc_sql/connect.clj (77%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/src/ejc_sql/jpa.clj (100%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/src/ejc_sql/lib.clj (100%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/src/ejc_sql/output.clj (97%) rename elpa/{ejc-sql-20181111.2343 => ejc-sql-20190121.1043}/src/ejc_sql/structure.clj (82%) delete mode 100644 elpa/ejc-sql-readme.txt diff --git a/elpa/ejc-sql-20181111.2343/ejc-autocomplete.el b/elpa/ejc-sql-20190121.1043/ejc-autocomplete.el similarity index 61% rename from elpa/ejc-sql-20181111.2343/ejc-autocomplete.el rename to elpa/ejc-sql-20190121.1043/ejc-autocomplete.el index 9c830050..6b06177e 100644 --- a/elpa/ejc-sql-20181111.2343/ejc-autocomplete.el +++ b/elpa/ejc-sql-20190121.1043/ejc-autocomplete.el @@ -24,6 +24,7 @@ (require 'ejc-interaction) (require 'ejc-doc) (require 'ejc-format) +(require 'ejc-flx) (defcustom ejc-candidates-uppercase t "Use uppercase candidates or downcase. @@ -32,21 +33,6 @@ Uppercase by default, set to nil to use downcase candidates." :safe #'booleanp :group 'ejc-sql) -(defcustom ejc-use-flx nil - "Non-nil enables `flx' fuzzy matching engine autocompletion." - :group 'ejc-sql - :type 'boolean) - -(defcustom ejc-flx-threshold 3 - "The minimum number of typed chars required to use `flx' for autocompletion." - :group 'ejc-sql - :type 'integer) - -(defface ejc-flx-highlight-face - '((t :inherit popup-isearch-match)) - "Face used by flx for highlighting flx match characters in `ejc-sql' buffers." - :group 'ejc-sql) - (defun ejc-get-prefix-word () "Return the word preceding dot before the typing." (save-excursion @@ -78,8 +64,8 @@ Uppercase by default, set to nil to use downcase candidates." `(if (ejc-buffer-connected-p) (let* ((prefix-1 (ejc-get-prefix-word)) (prefix-2 (save-excursion - (search-backward "." nil t) - (ejc-get-prefix-word))) + (search-backward "." nil t) + (ejc-get-prefix-word))) (result (funcall ,cand-fn ejc-db (apply @@ -90,7 +76,9 @@ Uppercase by default, set to nil to use downcase candidates." (pending (car result)) (candidates-cache (cdr result))) (if (ejc-not-nil-str pending) - (message "Receiving database structure...") + (progn + (message "Receiving database structure...") + (list)) candidates-cache)))) ;;;###autoload @@ -118,13 +106,11 @@ Uppercase by default, set to nil to use downcase candidates." (defun ejc-get-ansi-sql-words () (unless (or (ejc-return-point) (ejc-get-prefix-word)) - (progn - (if ejc-candidates-uppercase - (append (mapcar 'upcase ejc-ansi-sql-words) - (mapcar 'upcase ejc-auxulary-sql-words)) - (append ejc-ansi-sql-words - ejc-auxulary-sql-words))) - nil)) + (if ejc-candidates-uppercase + (append (mapcar 'upcase ejc-ansi-sql-words) + (mapcar 'upcase ejc-auxulary-sql-words)) + (append ejc-ansi-sql-words + ejc-auxulary-sql-words)))) (defun ac-ejc-documentation (symbol-name) "Return a documentation string for SYMBOL-NAME." @@ -190,7 +176,7 @@ something#" (defun ejc-ac-hook () (if ejc-use-flx - (if (functionp 'flx-flex-match) + (if (require 'flx-ido nil 'noerror) (setq-local ac-match-function 'ejc-flx-match-internal) (error (concat "Please install flx.el and flx-ido.el " "if you use fuzzy completion")))) @@ -200,69 +186,17 @@ something#" (add-hook 'ejc-sql-minor-mode-hook 'ejc-ac-hook) -(defun ejc-flx-propertize (obj score &optional add-score) - "Return propertized copy of obj according to score. - -SCORE of nil means to clear the properties." - (let ((block-started (cadr score)) - (last-char nil) - (str (if (consp obj) - (substring-no-properties (car obj)) - (substring-no-properties obj)))) - - (when score - (dolist (char (cdr score)) - (when (and last-char - (not (= (1+ last-char) char))) - (put-text-property block-started (1+ last-char) 'face 'ejc-flx-highlight-face str) - (setq block-started char)) - (setq last-char char)) - (put-text-property block-started (1+ last-char) 'face 'ejc-flx-highlight-face str) - (when add-score - (setq str (format "%s [%s]" str (car score))))) - (if (consp obj) - (cons str (cdr obj)) - str))) - -(defun ejc-flx-decorate (things &optional clear) - "Add ido text properties to THINGS. -If CLEAR is specified, clear them instead." - (if flx-ido-use-faces - (let ((decorate-count (min ido-max-prospects - (length things)))) - (nconc - (cl-loop for thing in things - for i from 0 below decorate-count - collect (if clear - (ejc-flx-propertize thing nil) - (ejc-flx-propertize (car thing) (cdr thing)))) - (if clear - (nthcdr decorate-count things) - (mapcar 'car (nthcdr decorate-count things))))) - (if clear - things - (mapcar 'car things)))) - -(defun ejc-flx-match-internal (query items) - "Match QUERY against ITEMS using flx scores. - -If filtered item count is still greater than `flx-ido-threshold', then use flex." - (if (< (length query) ejc-flx-threshold) - (all-completions query items) - (let ((flex-result (flx-flex-match query items))) - (if (< (length flex-result) flx-ido-threshold) - (let* ((matches (cl-loop for item in flex-result - for string = (ido-name item) - for score = (flx-score string query flx-file-cache) - if score - collect (cons item score) - into matches - finally return matches))) - (ejc-flx-decorate (delete-consecutive-dups - (sort matches - (lambda (x y) (> (cadr x) (cadr y)))) - t))) - flex-result)))) +(when (require 'yasnippet nil 'noerror) + (setq yas-snippet-dirs + (nconc yas-snippet-dirs + (list (expand-file-name "snippets" + (file-name-directory + (locate-library "ejc-sql")))))) + (defun ejc-yas-downcase-key (args) + (if ejc-sql-mode + (cl-callf downcase (nth 1 args))) + args) + (advice-add 'yas--fetch :filter-args #'ejc-yas-downcase-key)) (provide 'ejc-autocomplete) diff --git a/elpa/ejc-sql-20181111.2343/ejc-direx.el b/elpa/ejc-sql-20190121.1043/ejc-direx.el similarity index 100% rename from elpa/ejc-sql-20181111.2343/ejc-direx.el rename to elpa/ejc-sql-20190121.1043/ejc-direx.el diff --git a/elpa/ejc-sql-20181111.2343/ejc-doc.el b/elpa/ejc-sql-20190121.1043/ejc-doc.el similarity index 100% rename from elpa/ejc-sql-20181111.2343/ejc-doc.el rename to elpa/ejc-sql-20190121.1043/ejc-doc.el diff --git a/elpa/ejc-sql-20190121.1043/ejc-flx.el b/elpa/ejc-sql-20190121.1043/ejc-flx.el new file mode 100644 index 00000000..2bb98a38 --- /dev/null +++ b/elpa/ejc-sql-20190121.1043/ejc-flx.el @@ -0,0 +1,103 @@ +;;; ejc-flx.el -- Customization flx for ejc (the part of ejc-sql). + +;;; Copyright © 2018 - Kostafey + +;;; This program is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 2, or (at your option) +;;; any later version. +;;; +;;; This program is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program; if not, write to the Free Software Foundation, +;;; Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + +;;; Code: + +(defcustom ejc-use-flx nil + "Non-nil enables `flx' fuzzy matching engine autocompletion." + :group 'ejc-sql + :type 'boolean) + +(defcustom ejc-flx-threshold 2 + "The minimum number of typed chars required to use `flx' for autocompletion. +When 1, enables `flx' usage from the first typed char." + :group 'ejc-sql + :type 'integer) + +(defface ejc-flx-highlight-face + '((t :inherit popup-isearch-match)) + "Face used by flx for highlighting flx match characters in `ejc-sql' buffers." + :group 'ejc-sql) + +(defun ejc-flx-propertize (obj score &optional add-score) + "Return propertized copy of obj according to score. + +SCORE of nil means to clear the properties." + (let ((block-started (cadr score)) + (last-char nil) + (str (if (consp obj) + (substring-no-properties (car obj)) + (substring-no-properties obj)))) + + (when score + (dolist (char (cdr score)) + (when (and last-char + (not (= (1+ last-char) char))) + (put-text-property block-started (1+ last-char) 'face 'ejc-flx-highlight-face str) + (setq block-started char)) + (setq last-char char)) + (put-text-property block-started (1+ last-char) 'face 'ejc-flx-highlight-face str) + (when add-score + (setq str (format "%s [%s]" str (car score))))) + (if (consp obj) + (cons str (cdr obj)) + str))) + +(defun ejc-flx-decorate (things &optional clear) + "Add ido text properties to THINGS. +If CLEAR is specified, clear them instead." + (if flx-ido-use-faces + (let ((decorate-count (min ido-max-prospects + (length things)))) + (nconc + (cl-loop for thing in things + for i from 0 below decorate-count + collect (if clear + (ejc-flx-propertize thing nil) + (ejc-flx-propertize (car thing) (cdr thing)))) + (if clear + (nthcdr decorate-count things) + (mapcar 'car (nthcdr decorate-count things))))) + (if clear + things + (mapcar 'car things)))) + +(defun ejc-flx-match-internal (query items) + "Match QUERY against ITEMS using flx scores. + +If filtered item count is still greater than `flx-ido-threshold', then use flex." + (if (< (length query) ejc-flx-threshold) + (all-completions query items) + (let ((flex-result (flx-flex-match query items))) + (if (< (length flex-result) flx-ido-threshold) + (let* ((matches (cl-loop for item in flex-result + for string = (ido-name item) + for score = (flx-score string query flx-file-cache) + if score + collect (cons item score) + into matches + finally return matches))) + (ejc-flx-decorate (delete-consecutive-dups + (sort matches + (lambda (x y) (> (cadr x) (cadr y)))) + t))) + flex-result)))) + +(provide 'ejc-flx) + +;;; ejc-flx.el ends here diff --git a/elpa/ejc-sql-20181111.2343/ejc-format.el b/elpa/ejc-sql-20190121.1043/ejc-format.el similarity index 74% rename from elpa/ejc-sql-20181111.2343/ejc-format.el rename to elpa/ejc-sql-20190121.1043/ejc-format.el index b7fb04a1..70b35c1f 100644 --- a/elpa/ejc-sql-20181111.2343/ejc-format.el +++ b/elpa/ejc-sql-20190121.1043/ejc-format.el @@ -1,6 +1,6 @@ ;;; ejc-format.el -- SQL formatting library (the part of ejc-sql). -;;; Copyright © 2012-2018 - Kostafey +;;; Copyright © 2012-2019 - Kostafey ;;; This program is free software; you can redistribute it and/or modify ;;; it under the terms of the GNU General Public License as published by @@ -28,29 +28,68 @@ (defun ejc-sql-separator-re () (format "^\\s-*%s\\s-*" ejc-sql-separator)) -(defun ejc-get-sql-boundaries-at-point () +(defun ejc-get-border-top () + "Get top position of batch statement(s) seperator `ejc-sql-separator'. +Upper position of this batch statement(s)." + (save-excursion + (if (re-search-backward (ejc-sql-separator-re) nil t nil) + (forward-char) + (beginning-of-buffer)) + (point))) + +(defun ejc-get-border-bottom () + "Get bottom position of batch statements seperator `ejc-sql-separator' +Bottom position of this batch statement(s)." + (save-excursion + (if (re-search-forward (ejc-sql-separator-re) nil t nil) + (backward-char) + (end-of-buffer)) + (if (equal (string (preceding-char)) "\n") + (backward-char 1)) + (let ((sep-len (length ejc-sql-separator))) + (if (equal (buffer-substring (- (point) sep-len) (point)) + ejc-sql-separator) + (backward-char sep-len))) + (point))) + +(defun ejc-get-org-begin () + "Obtain position for begin of code snippet in `org-mode' buffers." + (save-excursion + (if (and (derived-mode-p 'org-mode) + (re-search-backward "^\\s-*#\\+begin_[(src)(example)].*" + nil t nil)) + (line-end-position) + (point-min)))) + +(defun ejc-get-org-end () + "Obtain position for end of code snippet in `org-mode' buffers." + (save-excursion + (if (and (derived-mode-p 'org-mode) + (re-search-forward "^\\s-*#\\+end_[(src)(example)]" + nil t nil)) + (line-beginning-position) + (point-max)))) + +(cl-defun ejc-get-sql-boundaries-at-point (&optional beg end) "Returns list of the boundaries of the current SQL expression. The current SQL expression is the expression under the point. The boundaries are marked by `ejc-sql-separator's. If the top or bottom boundary is absent - it returns beginning or end of the -buffer." - (save-excursion - (let* ((beg (progn - (if (re-search-backward (ejc-sql-separator-re) nil t nil) - (forward-char) - (beginning-of-buffer)) - (point))) - (end (progn - (if (re-search-forward (ejc-sql-separator-re) nil t nil) - (backward-char) - (end-of-buffer)) - (point)))) - (list beg end)))) +buffer. Set BEG and END parameters to add manual boundaries restrictions." + (let* ((beg (max (or beg (point-min)) + (ejc-get-border-top) + (ejc-get-org-begin))) + (end (min (or end (point-max)) + (ejc-get-border-bottom) + (ejc-get-org-end)))) + (list beg end))) (defmacro ejc--in-sql-boundaries (beg end &rest body) "Inject `beg' and `end' local variables to the `body' scope. `beg' and `end' are the boundaries of the current sql expression." - `(let* ((boundaries (ejc-get-sql-boundaries-at-point)) + `(let* ((boundaries (if (and (boundp ',beg) (boundp ',end)) + (ejc-get-sql-boundaries-at-point ,beg ,end) + (ejc-get-sql-boundaries-at-point))) (,beg (car boundaries)) (,end (car (cdr boundaries)))) ,@body)) @@ -89,10 +128,12 @@ buffer." (ejc--in-sql-boundaries beg end (apply func (list beg end)))) -(defun ejc-get-sql-at-point () +(cl-defun ejc-get-sql-at-point (&key beg end) "Return SQL around the point." - (ejc--in-sql-boundaries beg end - (let ((sql (ejc-strip-text-properties (buffer-substring beg end)))) + (ejc--in-sql-boundaries + beg end + (let ((sql (ejc-strip-text-properties + (buffer-substring beg end)))) sql))) (defmacro ejc-ensure-sql-mode (&rest body) @@ -223,7 +264,7 @@ boundaries." (overlay-put overlay 'face 'secondary-selection) (run-with-timer (or timeout 0.2) nil 'delete-overlay overlay))) -(defun ejc-flash-this-sql () +(cl-defun ejc-flash-this-sql (&key beg end) "Select (mark) SQL around the point." (interactive) (ejc--in-sql-boundaries diff --git a/elpa/ejc-sql-20181111.2343/ejc-interaction.el b/elpa/ejc-sql-20190121.1043/ejc-interaction.el similarity index 98% rename from elpa/ejc-sql-20181111.2343/ejc-interaction.el rename to elpa/ejc-sql-20190121.1043/ejc-interaction.el index 124f1a04..3f1fb529 100644 --- a/elpa/ejc-sql-20181111.2343/ejc-interaction.el +++ b/elpa/ejc-sql-20190121.1043/ejc-interaction.el @@ -23,11 +23,9 @@ (require 'clomacs) (clomacs-create-httpd-start ejc-httpd-start - :lib-prefix "ejc" :lib-name "ejc-sql") (clomacs-create-httpd-stop ejc-httpd-stop - :lib-prefix "ejc" :lib-name "ejc-sql") (clomacs-defun ejc-sql-set-db @@ -99,6 +97,11 @@ :lib-name "ejc-sql" :namespace ejc-sql.connect) +(clomacs-defun ejc--get-result-file-path + get-result-file-path + :lib-name "ejc-sql" + :namespace ejc-sql.output) + (clomacs-defun ejc-print clojure.core/print :lib-name "ejc-sql" diff --git a/elpa/ejc-sql-20181111.2343/ejc-lib.el b/elpa/ejc-sql-20190121.1043/ejc-lib.el similarity index 100% rename from elpa/ejc-sql-20181111.2343/ejc-lib.el rename to elpa/ejc-sql-20190121.1043/ejc-lib.el diff --git a/elpa/ejc-sql-20181111.2343/ejc-result-mode.el b/elpa/ejc-sql-20190121.1043/ejc-result-mode.el similarity index 100% rename from elpa/ejc-sql-20181111.2343/ejc-result-mode.el rename to elpa/ejc-sql-20190121.1043/ejc-result-mode.el diff --git a/elpa/ejc-sql-20181111.2343/ejc-sql-autoloads.el b/elpa/ejc-sql-20190121.1043/ejc-sql-autoloads.el similarity index 92% rename from elpa/ejc-sql-20181111.2343/ejc-sql-autoloads.el rename to elpa/ejc-sql-20190121.1043/ejc-sql-autoloads.el index f20e684a..7bab6a44 100644 --- a/elpa/ejc-sql-20181111.2343/ejc-sql-autoloads.el +++ b/elpa/ejc-sql-20190121.1043/ejc-sql-autoloads.el @@ -62,6 +62,13 @@ something# (if (fboundp 'register-definition-prefixes) (register-definition-prefixes "ejc-doc" '("ejc-"))) +;;;*** + +;;;### (autoloads nil "ejc-flx" "ejc-flx.el" (0 0 0 0)) +;;; Generated autoloads from ejc-flx.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "ejc-flx" '("ejc-"))) + ;;;*** ;;;### (autoloads nil "ejc-format" "ejc-format.el" (0 0 0 0)) @@ -122,6 +129,11 @@ any SQL buffer to connect to exact database, as always. \(fn)" t nil) +(autoload 'ejc-version "ejc-sql" "\ +Get the ejc-sql version as string. + +\(fn)" t nil) + (if (fboundp 'register-definition-prefixes) (register-definition-prefixes "ejc-sql" '("ejc-"))) ;;;*** diff --git a/elpa/ejc-sql-20181111.2343/ejc-sql-pkg.el b/elpa/ejc-sql-20190121.1043/ejc-sql-pkg.el similarity index 85% rename from elpa/ejc-sql-20181111.2343/ejc-sql-pkg.el rename to elpa/ejc-sql-20190121.1043/ejc-sql-pkg.el index 020b3b8f..bc818d77 100644 --- a/elpa/ejc-sql-20181111.2343/ejc-sql-pkg.el +++ b/elpa/ejc-sql-20190121.1043/ejc-sql-pkg.el @@ -1,4 +1,4 @@ -(define-package "ejc-sql" "20181111.2343" "Emacs SQL client uses Clojure JDBC." +(define-package "ejc-sql" "20190121.1043" "Emacs SQL client uses Clojure JDBC." '((emacs "25.1") (clomacs "0.0.3") (dash "2.12.1") diff --git a/elpa/ejc-sql-20181111.2343/ejc-sql.el b/elpa/ejc-sql-20190121.1043/ejc-sql.el similarity index 80% rename from elpa/ejc-sql-20181111.2343/ejc-sql.el rename to elpa/ejc-sql-20190121.1043/ejc-sql.el index 7de87065..8b7a9a9c 100644 --- a/elpa/ejc-sql-20181111.2343/ejc-sql.el +++ b/elpa/ejc-sql-20190121.1043/ejc-sql.el @@ -1,6 +1,6 @@ ;;; ejc-sql.el --- Emacs SQL client uses Clojure JDBC. -*- lexical-binding: t -*- -;;; Copyright © 2012-2018 - Kostafey +;;; Copyright © 2012-2019 - Kostafey ;; Author: Kostafey ;; URL: https://github.com/kostafey/ejc-sql @@ -81,6 +81,13 @@ :group 'ejc-sql :type 'integer) +(defcustom ejc-org-mode-show-results t + "When t show SQL query results of `org-mode' code snippet in the same buffer. +An expected behaviour for `org-mode' users. Disable popup window with SQL +results. When nil, otherwise, provide `ejc-sql' users expected behaviour." + :group 'ejc-sql + :type 'boolean) + (defvar ejc-sql-mode-keymap (make-keymap) "ejc-sql-mode keymap.") (define-key ejc-sql-mode-keymap (kbd "C-c C-c") 'ejc-eval-user-sql-at-point) (define-key ejc-sql-mode-keymap (kbd "C-h t") 'ejc-describe-table) @@ -261,7 +268,7 @@ For more details about parameters see `get-connection' function in jdbc.clj: (cons :subname subname) (cons :user user) (cons :password password) - (cons :classpath classpath) + (cons :classpath (file-truename classpath)) (cons :separator separator) (cons :classname classname))) new-connection)) @@ -274,18 +281,19 @@ For more details about parameters see `get-connection' function in jdbc.clj: ejc-connections)) (defvar ejc-product-assoc - '((sqlserver . ms))) + '((sqlserver . ms) + (oracle:sid . oracle))) (defun ejc-configure-sql-buffer (product-name) - (unless (org-src-edit-buffer-p) + (unless (or (derived-mode-p 'org-mode) (org-src-edit-buffer-p)) (sql-mode)) (sql-set-product (or (cdr (assoc-string product-name ejc-product-assoc)) (car (assoc-string product-name sql-product-alist)) "ansi")) (auto-complete-mode t) (auto-fill-mode t) - (ejc-sql-mode) - (ejc-sql-mode t)) + (unless (derived-mode-p 'org-mode) + (ejc-sql-mode t))) (defun ejc-load-conn-statistics () "Load connection usage statistics to `ejc-conn-statistics' var." @@ -312,6 +320,60 @@ For more details about parameters see `get-connection' function in jdbc.clj: (prin1 ejc-conn-statistics (current-buffer)) (insert ")"))) +(defun ejc-set-mode-name (connection-name) + "Show CONNECTION-NAME as part of `mode-name' in `mode-line'." + (setq mode-name (format "%s->[%s]" + (car (split-string mode-name "->\\[.+\\]")) + connection-name))) + +(defun ejc-add-connection (product-name connection-name db) + "Add ejc connection information to current buffer. +Prepare buffer to operate as `ejc-sql-mode' buffer." + (ejc-configure-sql-buffer product-name) + (setq-local ejc-connection-name connection-name) + (setq-local ejc-db db) + (ejc-set-mode-name connection-name)) + +(defun ejc-get-result-file-path () + (or ejc-result-file-path + (setq ejc-result-file-path + (ejc--get-result-file-path)))) + +(defun ejc-eval-org-snippet (body params) + "Used to eval SQL code in `org-mode' code snippets." + (let* ((beg (save-excursion + (goto-char (nth 5 (org-babel-get-src-block-info))) + (end-of-line) + (right-char 1) + (point))) + (end (save-excursion + (goto-char beg) + (+ beg (length body) (skip-chars-forward "\t "))))) + (ejc-eval-user-sql-at-point + :beg beg + :end end + :sync ejc-org-mode-show-results + :display-result (not ejc-org-mode-show-results)) + (if ejc-org-mode-show-results + (with-temp-buffer + (insert-file-contents (ejc-get-result-file-path)) + (buffer-string))))) + +(defun ejc-get-product-name (db) + (or (alist-get :subprotocol db) + (alist-get :dbtype db))) + +(defun ejc-org-edit-special (orig-fun &rest args) + (if (and (equal "sql" (car (org-babel-get-src-block-info))) + (boundp 'ejc-db) ejc-db + (boundp 'ejc-connection-name) ejc-connection-name) + (let* ((db ejc-db) + (connection-name ejc-connection-name) + (product-name (ejc-get-product-name db))) + (apply orig-fun args) + (ejc-add-connection product-name connection-name db)) + (apply orig-fun args))) + ;;;###autoload (defun ejc-connect (connection-name) "Connect to selected db." @@ -325,17 +387,20 @@ For more details about parameters see `get-connection' function in jdbc.clj: (> (or (lax-plist-get conn-statistics c1) 0) (or (lax-plist-get conn-statistics c2) 0))) conn-list))))) - (let ((db (cdr (ejc-find-connection connection-name)))) + (let* ((db (cdr (ejc-find-connection connection-name))) + (product-name (ejc-get-product-name db))) (ejc-update-conn-statistics connection-name) - (ejc-configure-sql-buffer (or (alist-get :subprotocol db) - (alist-get :dbtype db))) + (ejc-configure-sql-buffer product-name) + (when (derived-mode-p 'org-mode) + (defalias 'org-babel-execute:sql 'ejc-eval-org-snippet) + (advice-add 'org-edit-special :around #'ejc-org-edit-special)) (setq-local ejc-connection-name connection-name) (setq-local ejc-db db) (message "Connection started...") (ejc-connect-to-db db) (when (ejc-validate-connection :db ejc-db :timeout ejc-connection-validate-timeout) - (setq mode-name (format "%s->[%s]" mode-name connection-name)) + (ejc-set-mode-name connection-name) (message "Connected.")))) ;;;###autoload @@ -396,8 +461,14 @@ any SQL buffer to connect to exact database, as always. " (unless (ejc-buffer-connected-p) (error "Run M-x ejc-connect first!"))) -(cl-defun ejc-eval-sql-and-log (db sql - &key start-time rows-limit append sync) +(cl-defun ejc-eval-sql-and-log (db + sql + &key + start-time + rows-limit + append + sync + display-result) (when sql (spinner-start 'rotating-line) (setq ejc-current-buffer-query (current-buffer)) @@ -408,7 +479,8 @@ any SQL buffer to connect to exact database, as always. " :start-time start-time :rows-limit rows-limit :append append - :sync sync)))) + :sync sync + :display-result display-result)))) (defun ejc-message-query-done (start-time result) (message @@ -421,11 +493,21 @@ any SQL buffer to connect to exact database, as always. " (current-time)) (float-time (time-since start-time)))) -(cl-defun ejc-complete-query (result-file-path &key start-time result) - (setq ejc-result-file-path result-file-path) +(defun ejc-spinner-stop () + "Stop spinner indicating current running query." (with-current-buffer ejc-current-buffer-query - (spinner-stop)) - (ejc-show-last-result nil :result-file-path ejc-result-file-path) + (spinner-stop))) + +(cl-defun ejc-complete-query (result-file-path + &key + start-time + result + display-result) + (if result-file-path + (setq ejc-result-file-path result-file-path)) + (ejc-spinner-stop) + (if display-result + (ejc-show-last-result)) (if (and start-time result) (ejc-message-query-done start-time result)) nil) @@ -437,8 +519,7 @@ Unsafe for INSERT/UPDATE/CREATE/ALTER queries." (if (and (clomacs-get-connection "ejc-sql") (ejc--is-query-running-p)) (let ((start-time (ejc--cancel-query))) - (with-current-buffer ejc-current-buffer-query - (spinner-stop)) + (ejc-spinner-stop) (ejc-message-query-done start-time :terminated)) (keyboard-quit))) @@ -485,14 +566,15 @@ Unsafe for INSERT/UPDATE/CREATE/ALTER queries." (ejc-select-db-meta-script ejc-db :view :entity-name entity-name)))))) -(cl-defun ejc-eval-user-sql (sql &key rows-limit sync) +(cl-defun ejc-eval-user-sql (sql &key rows-limit sync display-result) "Evaluate SQL by user: reload and show query results buffer, update log." (message "Processing SQL query...") (ejc-eval-sql-and-log ejc-db sql :rows-limit rows-limit :start-time (current-time) - :sync sync)) + :sync sync + :display-result display-result)) (defun ejc-eval-user-sql-region (beg end) "Evaluate SQL bounded by the selection area." @@ -501,13 +583,20 @@ Unsafe for INSERT/UPDATE/CREATE/ALTER queries." (let ((sql (buffer-substring beg end))) (ejc-eval-user-sql sql))) -(cl-defun ejc-eval-user-sql-at-point (&key sync) +(cl-defun ejc-eval-user-sql-at-point (&key + sync + beg + end + (display-result t)) "Evaluate SQL bounded by the `ejc-sql-separator' or/and buffer boundaries." (interactive) (ejc-check-connection) - (ejc-flash-this-sql) - (ejc-eval-user-sql (ejc-get-sql-at-point) :sync sync)) + (ejc-flash-this-sql :beg beg + :end end) + (ejc-eval-user-sql (ejc-get-sql-at-point :beg beg :end end) + :sync sync + :display-result display-result)) (defun ejc-show-tables-list () "Output tables list." @@ -515,7 +604,8 @@ boundaries." (ejc-check-connection) (ejc-eval-user-sql (ejc-select-db-meta-script ejc-db :all-tables) - :rows-limit 0)) + :rows-limit 0 + :display-result t)) (defun ejc-show-user-types-list (&optional owner) "Output user types list." @@ -563,24 +653,17 @@ If this buffer is not exists or it was killed - create buffer via ejc-results-buffer (ejc-create-output-buffer))) -(cl-defun ejc-show-last-result - (&optional result - &key - (result-file-path ejc-result-file-path)) +(cl-defun ejc-show-last-result (&optional result) "Popup buffer with last SQL execution result output." (interactive) (let ((output-buffer (ejc-get-output-buffer)) (old-split split-width-threshold)) (set-buffer output-buffer) - (if (or result result-file-path) - (progn - (read-only-mode -1) - (erase-buffer) - (if (and result (not result-file-path)) - ;; result only - (insert result) - ;; result-file-path only - (insert-file-contents result-file-path)))) + (read-only-mode -1) + (erase-buffer) + (if result + (insert result) + (insert-file-contents (ejc-get-result-file-path))) (read-only-mode 1) (beginning-of-buffer) (setq split-width-threshold nil) @@ -607,6 +690,14 @@ Buffer can be saved to file with `ejc-temp-editor-file' path." (find-file-read-only (ejc-get-log-file-path)) (end-of-buffer)) +;;;###autoload +(defun ejc-version () + "Get the ejc-sql version as string." + (interactive) + (if (require 'pkg-info nil t) + (message "ejc-sql %s" (pkg-info-version-info 'ejc-sql)) + (error "Cannot determine version without package pkg-info"))) + (provide 'ejc-sql) ;;; ejc-sql.el ends here diff --git a/elpa/ejc-sql-20181111.2343/project.clj b/elpa/ejc-sql-20190121.1043/project.clj similarity index 91% rename from elpa/ejc-sql-20181111.2343/project.clj rename to elpa/ejc-sql-20190121.1043/project.clj index f5f550a1..b2115745 100644 --- a/elpa/ejc-sql-20181111.2343/project.clj +++ b/elpa/ejc-sql-20190121.1043/project.clj @@ -5,7 +5,7 @@ :url "http://www.gnu.org/licenses/old-licenses/gpl-2.0.html"} :dependencies [[org.clojure/clojure "1.9.0"] [org.clojure/clojure-contrib "1.2.0"] - [org.clojure/java.jdbc "0.7.8"] + [org.clojars.kostafey/java.jdbc "0.7.9-SNAPSHOT"] [org.apache.openjpa/openjpa-all "2.2.2"] [org.hibernate/hibernate-core "5.2.3.Final"] [com.cemerick/pomegranate "0.3.0"] diff --git a/elpa/ejc-sql-20190121.1043/snippets/sql-mode/begin.snippet b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/begin.snippet new file mode 100644 index 00000000..346dff8b --- /dev/null +++ b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/begin.snippet @@ -0,0 +1,7 @@ +# -*- mode: snippet -*- +# name: begin +# key: begin +# -- +BEGIN + $0 +END; \ No newline at end of file diff --git a/elpa/ejc-sql-20190121.1043/snippets/sql-mode/delete.yasnippet b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/delete.yasnippet new file mode 100644 index 00000000..27cc2af9 --- /dev/null +++ b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/delete.yasnippet @@ -0,0 +1,5 @@ +# -*- mode: snippet -*- +# name: delete +# key: delete +# -- +DELETE FROM ${1:table_name} WHERE ${2:where_stmt} \ No newline at end of file diff --git a/elpa/ejc-sql-20190121.1043/snippets/sql-mode/insert.yasnippet b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/insert.yasnippet new file mode 100644 index 00000000..b38c3ebb --- /dev/null +++ b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/insert.yasnippet @@ -0,0 +1,6 @@ +# -*- mode: snippet -*- +# name: insert +# key: insert +# -- +INSERT INTO ${1:table_name} (${2:column1}, ${3:column2}) +VALUES ($0value1, value2) \ No newline at end of file diff --git a/elpa/ejc-sql-20190121.1043/snippets/sql-mode/select.yasnippet b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/select.yasnippet new file mode 100644 index 00000000..4e5fe935 --- /dev/null +++ b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/select.yasnippet @@ -0,0 +1,7 @@ +# -*- mode: snippet -*- +# name: select +# key: select +# -- +SELECT `(if (eq sql-product 'sqlserver) "first 20 ")`* +FROM ${1:table_name} +WHERE `(if (eq sql-product 'oracle) "rownum < 20\n AND ")`${2:where_stmt} \ No newline at end of file diff --git a/elpa/ejc-sql-20190121.1043/snippets/sql-mode/update.yasnippet b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/update.yasnippet new file mode 100644 index 00000000..5f15e73f --- /dev/null +++ b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/update.yasnippet @@ -0,0 +1,7 @@ +# -*- mode: snippet -*- +# name: update +# key: update +# -- +UPDATE ${1:table_name} +SET ${2:column1} = ${3:value}, ${4:column2} = ${5:value} +WHERE ${6:some_column} = ${7:some_value} \ No newline at end of file diff --git a/elpa/ejc-sql-20190121.1043/snippets/sql-mode/where.yasnippet b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/where.yasnippet new file mode 100644 index 00000000..13d87f2f --- /dev/null +++ b/elpa/ejc-sql-20190121.1043/snippets/sql-mode/where.yasnippet @@ -0,0 +1,5 @@ +# -*- mode: snippet -*- +# name: where +# key: where +# -- +WHERE `(if (eq sql-product 'oracle) "rownum < 20\n AND ")`${2:where_stmt} \ No newline at end of file diff --git a/elpa/ejc-sql-20181111.2343/src/ejc_sql/connect.clj b/elpa/ejc-sql-20190121.1043/src/ejc_sql/connect.clj similarity index 77% rename from elpa/ejc-sql-20181111.2343/src/ejc_sql/connect.clj rename to elpa/ejc-sql-20190121.1043/src/ejc_sql/connect.clj index 11abcbd0..e8ba755e 100644 --- a/elpa/ejc-sql-20181111.2343/src/ejc_sql/connect.clj +++ b/elpa/ejc-sql-20190121.1043/src/ejc_sql/connect.clj @@ -137,8 +137,9 @@ Unsafe for INSERT/UPDATE/CREATE/ALTER queries." "Handle cases where separator is a part of string in SQL query. E.g. you can use default separator char `/` in this query: SELECT * FROM urls WHERE path like '%http://localhost%'" - (String/format "%s(?=(([^('|\")]*('|\")){2})*[^('|\")]*$)" - (into-array separator))) + (String/format + "%s(? +;;; Copyright © 2016-2019 - Kostafey ;;; This program is free software; you can redistribute it and/or modify ;;; it under the terms of the GNU General Public License as published by @@ -253,17 +253,19 @@ (.toLowerCase (first (.split prop "="))))) props-list))) "=")))))) +(def product-assoc {"oracle:sid" "oracle"}) + (defn get-db-type [db] - (let [{:keys [subprotocol connection-uri dbtype]} db] - (keyword - (or dbtype - subprotocol - (let [attrs (.split connection-uri ":")] - (if (= (second attrs) "jtds") - ;; jdbc:jtds:sqlserver://... - (nth attrs 2) - ;; jdbc:sqlserver://localhost\instance:1433; - (second attrs))))))) + (let [{:keys [subprotocol connection-uri dbtype]} db + result (or dbtype + subprotocol + (let [attrs (.split connection-uri ":")] + (if (= (second attrs) "jtds") + ;; jdbc:jtds:sqlserver://... + (nth attrs 2) + ;; jdbc:sqlserver://localhost\instance:1433; + (second attrs))))] + (keyword (or (product-assoc result) result)))) (defn- get? [obj & [force?]] (if (and obj (or force? (realized? obj))) @@ -375,6 +377,18 @@ check if receiveing process is not running, then start it." (defn is-owner? [db prefix] (in? (get-owners db) prefix :case-sensitive false)) +(defn autocomplete-loading [] + "Not loaded tables yet. Output pending db structure data..." + (list "t")) + +(defn autocomplete-result [result] + "Output autocomplete result." + (cons "nil" result)) + +(defn autocomplete-nothing [] + "Output autocomplete nothing." + (list "nil")) + (defn get-owners-candidates [db sql prefix-1 & _] "Return owners candidates autocomplete list from the database structure cache, async request to fill it, if not yet. @@ -386,11 +400,11 @@ if `pending` is nil - no request is running, return result immediately." (if prefix-1 ;; Assume schema|table.# is not applicable. ;; So, return empty list. - (list "nil") + (autocomplete-nothing) (if owners - (cons "nil" owners) + (autocomplete-result owners) ;; pending owners... - (list "t"))))) + (autocomplete-loading))))) (defn get-tables-candidates [db sql prefix-1 & _] "Return tables candidates autocomplete list." @@ -404,9 +418,9 @@ if `pending` is nil - no request is running, return result immediately." ;; unknown?.# case (list)))] (if tables - (cons "nil" tables) + (autocomplete-result tables) ;; pending tables... - (list "t")))) + (autocomplete-loading)))) (defn match-alias? [sql owner table probable-alias] "Check if prefix (`probable-alias`) is alias for `table` in this `sql`." @@ -427,52 +441,84 @@ if `pending` is nil - no request is running, return result immediately." (mapv #(get-tables db % true) (get-owners db true)))) +(def insert-re + (re-pattern (str "(?i)\\s*INSERT\\s+INTO\\s+(\\S+)\\s+"))) + +(defn insert-sql? [sql] + "If `sql` is INSERT query, return a table name used to insert new records. +Otherwise return nil." + (second (re-find insert-re sql))) + +(def update-re + (re-pattern (str "(?i)\\s*UPDATE\\s(\\S+)\\s+\n*SET.*"))) + +(defn update-sql? [sql] + "If `sql` is UPDATE query, return a table name used to modify the existing +records. Otherwise return nil." + (second (re-find update-re sql))) + (defn get-colomns-candidates [db sql prefix-1 & [prefix-2]] "Return colomns candidates autocomplete list." ;; Possible cases: ;; 1. [owner|schema.]table.# ;; 2. SELECT alias.# FROM [owner|schema.]table AS alias ;; 3. SELECT complex-alias.# FROM (SELECT...) AS complex-alias + ;; 4. INSERT INTO table (field1, .#) values (123, 'text') + ;; 5. UPDATE table SET field1 = 123, .# = 'text' WHERE id = 1 ;; - ;; In any case consider `prefix-1` as table or alias - ;; and optional `prefix-2` as owner or schema - (if (not prefix-1) - ;; TODO: cases for: - ;; INSERT INTO table (field1, #) values (123, 'text') - ;; UPDATE table SET field1 = 123, # = 'text' WHERE id = 1 - (list "nil") - (let [owner prefix-2 - tables-list (if owner - (get-tables db owner) - ;; In case of queries like - ;; "SELECT u.# FROM custom.Users as u" - ;; when "custom" is not the current - ;; schema, the full DB structure tree - ;; sould be built to obtain overall - ;; tables list for all owners/schemas. - (if (get-namespace db) - ;; Database has namespaces - (if (not (get-owners db)) - ;; Not received owners list yet - - ;; pending... - (do - (future (get-all-tables db)) - nil) - ;; Owners list is already here - - ;; force tables list receiving! - (get-all-tables db)) - ;; Database hasn't namespaces - - ;; no owners needed - (get-tables db)))] - (if (and tables-list - (not-empty (filter not-empty tables-list))) + ;; In any case, consider `prefix-1` as table or alias + ;; and optional `prefix-2` as owner or schema. + ;; When no any prefix at all, check for 4 (INSERT) or 5 (UPDATE) case. + (let [owner prefix-2 + tables-list (if owner + (get-tables db owner) + ;; In case of queries like + ;; "SELECT u.# FROM custom.Users as u" + ;; when "custom" is not the current + ;; schema, the full DB structure tree + ;; sould be built to obtain overall + ;; tables list for all owners/schemas. + (if (get-namespace db) + ;; Database has namespaces + (if (not (get-owners db)) + ;; Not received owners list yet - + ;; pending... + (do + (future (get-all-tables db)) + nil) + ;; Owners list is already here - + ;; force tables list receiving! + (get-all-tables db)) + ;; Database hasn't namespaces - + ;; no owners needed + (get-tables db)))] + (if (not (and tables-list + (not-empty (filter not-empty tables-list)))) + ;; no tables yet + ;; pending tables... + (autocomplete-loading) + ;; Tables list loaded: + (if (not prefix-1) + (let [insert-or-update-table (or (insert-sql? sql) + (update-sql? sql))] + (cond + (and (not-empty insert-or-update-table) + (in? tables-list insert-or-update-table + :case-sensitive false)) + ;; INSERT INTO table (field1, .#) values (123, 'text') + ;; or + ;; UPDATE table SET field1 = 123, .# = 'text' WHERE id = 1 + (autocomplete-result + (get-colomns db insert-or-update-table true)) + ;; SELECT or other queries types + :else (autocomplete-nothing))) (if (in? tables-list prefix-1 :case-sensitive false) ;; table.# (let [table prefix-1 ;; force columns-cache obtaining... columns-list (get-colomns db table true)] ;; ok - columns - (cons "nil" columns-list)) + (autocomplete-result columns-list)) (let [sql (c/clean-sql sql) table-alias (first (filter @@ -481,7 +527,7 @@ if `pending` is nil - no request is running, return result immediately." tables-list))] (if table-alias ;; table-alias.# - (cons "nil" (get-colomns db table-alias true)) + (autocomplete-result (get-colomns db table-alias true)) ;; Check "SELECT t.# FROM (SELECT ... ) AS t" case. (let [pattern (re-pattern (str "\\(.+\\)(\\s|\\s(as)\\s)" prefix-1)) @@ -493,16 +539,13 @@ if `pending` is nil - no request is running, return result immediately." (let [{:keys [success result]} (c/query-meta db complex-alias)] (if success ;; complex-alias.# - (cons "nil" (mapv :name result)) + (autocomplete-result (mapv :name result)) ;; Can't execute "blah blah" to get metadata in ;; "SELECT t.# FROM (blah blah) AS t" case. - (list "nil"))) + (autocomplete-nothing))) ;; unknown?.# case ;; nothing to complete - (list "nil")))))) - ;; no tables yet - ;; pending tables... - (list "t"))))) + (autocomplete-nothing)))))))))) (defn get-cache [] "Output actual cache." diff --git a/elpa/ejc-sql-readme.txt b/elpa/ejc-sql-readme.txt deleted file mode 100644 index 4875dd4d..00000000 --- a/elpa/ejc-sql-readme.txt +++ /dev/null @@ -1,4 +0,0 @@ -ejc-sql turns Emacs into simple SQL client, it uses JDBC connection to -databases via clojure/java.jdbc lib. - -See README.md for detailed description. -- 2.47.3