[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/emacsql 1116a0873e 163/427: Turn everything into generic f
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/emacsql 1116a0873e 163/427: Turn everything into generic functions. |
Date: |
Tue, 13 Dec 2022 02:59:38 -0500 (EST) |
branch: elpa/emacsql
commit 1116a0873e65c7e55a8b8414526e25f81dbe95f0
Author: Christopher Wellons <wellons@nullprogram.com>
Commit: Christopher Wellons <wellons@nullprogram.com>
Turn everything into generic functions.
This opens up the path for multiple backends.
---
Makefile | 4 +-
emacsql-pkg.el | 3 +
emacsql-sqlite.el | 165 +++++++++++++++++++++++++++
emacsql.el | 327 ++++++++++++++++++------------------------------------
4 files changed, 278 insertions(+), 221 deletions(-)
diff --git a/Makefile b/Makefile
index 8f4579f75b..b6ea2b187b 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ BATCH := $(EMACS) -batch -Q -L .
COMPILE := $(BATCH) -f batch-byte-compile
TEST := $(BATCH) -l $(PACKAGE)-tests.elc -f ert-run-tests-batch
-EL = $(PACKAGE).el $(PACKAGE)-tests.el
+EL = emacsql.el emacsql-sqlite.el $(PACKAGE)-tests.el
ELC = $(EL:.el=.elc)
@@ -22,4 +22,4 @@ clean:
$(RM) *.elc
%.elc: %.el
- @$(COMPILE) $<
+ $(COMPILE) $<
diff --git a/emacsql-pkg.el b/emacsql-pkg.el
new file mode 100644
index 0000000000..89314bddbb
--- /dev/null
+++ b/emacsql-pkg.el
@@ -0,0 +1,3 @@
+(define-package "emacsql" "1.0.0"
+ "high-level SQL database front-end"
+ '((emacs "24.1") (cl-lib "0.3")))
diff --git a/emacsql-sqlite.el b/emacsql-sqlite.el
new file mode 100644
index 0000000000..243cb73113
--- /dev/null
+++ b/emacsql-sqlite.el
@@ -0,0 +1,165 @@
+;; emacsql-sqlite.el --- SQLite backend for Emacsql -*- lexical-binding: t; -*-
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'eieio)
+(require 'emacsql)
+
+(defvar emacsql-sqlite3-executable "sqlite3"
+ "Path to the sqlite3 executable.")
+
+(defun emacsql-sqlite3-unavailable-p ()
+ "Return a reason if the sqlite3 executable is not available.
+
+:no-executable -- cannot find the executable
+:cannot-execute -- cannot run the executable
+:old-version -- sqlite3 version is too old"
+ (let ((sqlite3 emacsql-sqlite3-executable))
+ (if (null (executable-find sqlite3))
+ :no-executable
+ (condition-case _
+ (with-temp-buffer
+ (call-process sqlite3 nil (current-buffer) nil "--version")
+ (let ((version (car (split-string (buffer-string)))))
+ (if (version< version "3.0.0")
+ :old-version
+ nil)))
+ (error :cannot-execute)))))
+
+(defclass emacsql-sqlite-connection (emacsql-connection)
+ ((file :initarg :file
+ :type (or null string)
+ :documentation "Database file name."))
+ (:documentation "A connection to a SQLite database."))
+
+;;;###autoload
+(cl-defun emacsql-sqlite (file &key debug)
+ "Open a connected to database stored in FILE.
+If FILE is nil use an in-memory database.
+
+:debug LOG -- When non-nil, log all SQLite commands to a log
+buffer. This is for debugging purposes."
+ (let* ((buffer (generate-new-buffer "*emacsql-connection*"))
+ (fullfile (if file (expand-file-name file) ":memory:"))
+ (process (start-process "emacsql" buffer emacsql-sqlite3-executable
+ "-interactive" fullfile)))
+ (setf (process-sentinel process) (lambda (_proc _) (kill-buffer buffer)))
+ (process-send-string process ".mode list\n")
+ (process-send-string process ".separator ' '\n")
+ (process-send-string process ".nullvalue nil\n")
+ (process-send-string process ".prompt ]\n")
+ (process-send-string process "EMACSQL;\n") ;; error message flush
+ (let ((connection (make-instance
+ 'emacsql-sqlite-connection
+ :process process
+ :file (when file fullfile)
+ :log-buffer )))
+ (prog1 connection
+ (when debug
+ (setf (emacsql-log-buffer connection)
+ (generate-new-buffer "*emacsql-log*")))
+ (emacsql-wait connection)
+ (emacsql-add-connection connection)))))
+
+;;;###autoload
+(defalias 'emacsql-connect 'emacsql-sqlite)
+
+(defmethod emacsql-close ((connection emacsql-sqlite-connection))
+ "Gracefully exits the SQLite subprocess."
+ (let ((process (emacsql-process connection)))
+ (when (and process (process-live-p process))
+ (process-send-string process ".exit\n"))))
+
+(defmethod emacsql-waiting-p ((connection emacsql-sqlite-connection))
+ (with-current-buffer (emacsql-buffer connection)
+ (cond ((= (buffer-size) 1) (string= "]" (buffer-string)))
+ ((> (buffer-size) 1) (string= "\n]"
+ (buffer-substring
+ (- (point-max) 2) (point-max)))))))
+
+(defun emacsql-sqlite--parse (connection)
+ "Parse SQLite output into an s-expression."
+ (with-current-buffer (emacsql-buffer connection)
+ (let ((standard-input (current-buffer)))
+ (setf (point) (point-min))
+ (cl-loop until (looking-at "]")
+ collect (read) into row
+ when (looking-at "\n")
+ collect row into rows
+ and do (progn (forward-char 1) (setf row ()))
+ finally (cl-return rows)))))
+
+(defvar emacsql-sqlite-condition-alist
+ '(("unable to open" emacsql-access)
+ ("cannot open" emacsql-access)
+ ("source database is busy" emacsql-access)
+ ("unknown database" emacsql-access)
+ ("writable" emacsql-access)
+ ("no such table" emacsql-table)
+ ("table [^ ]+ already exists" emacsql-table)
+ ("no such column" emacsql-table)
+ ("already another table" emacsql-table)
+ ("Cannot add" emacsql-table)
+ ("table name" emacsql-table)
+ ("already an index" emacsql-table)
+ ("constraint cannot be drop" emacsql-table)
+ ("database is locked" emacsql-lock)
+ ("no transaction is active" emacsql-transaction)
+ ("cannot start a transaction" emacsql-transaction)
+ ("out of memory" emacsql-fatal)
+ ("corrupt database" emacsql-fatal)
+ ("interrupt" emacsql-fatal)
+ ("values were supplied" emacsql-syntax)
+ ("mismatch" emacsql-syntax)
+ ("no such" emacsql-syntax)
+ ("does not match" emacsql-syntax)
+ ("circularly defined" emacsql-syntax)
+ ("parameters are not allowed" emacsql-syntax)
+ ("missing" emacsql-syntax)
+ ("is only allowed on" emacsql-syntax)
+ ("more than one primary key" emacsql-syntax)
+ ("not constant" emacsql-syntax)
+ ("duplicate" emacsql-syntax)
+ ("name reserved" emacsql-syntax)
+ ("cannot use variables" emacsql-syntax)
+ ("no tables specified" emacsql-syntax)
+ ("syntax error" emacsql-syntax)
+ ("no such function" emacsql-syntax)
+ ("unknown function" emacsql-syntax)
+ ("wrong number of arguments" emacsql-syntax)
+ ("term does not match" emacsql-syntax)
+ ("clause" emacsql-syntax)
+ ("tree is too large" emacsql-syntax)
+ ("too many" emacsql-syntax))
+ "List of regexp's mapping sqlite3 output to conditions.")
+
+(defun emacsql-sqlite-get-condition (message)
+ "Get condition for MESSAGE provided from SQLite."
+ (or (cadr (cl-assoc message emacsql-sqlite-condition-alist
+ :test (lambda (a b) (string-match-p b a))))
+ 'emacsql-error))
+
+(defun emacsql-sqlite--check-error (conn)
+ "Return non-nil or throw an appropriate error."
+ (with-current-buffer (emacsql-buffer conn)
+ (emacsql-wait conn)
+ (setf (point) (point-min))
+ (prog1 t
+ (when (looking-at "Error:")
+ (let* ((message (buffer-substring (line-beginning-position)
+ (line-end-position)))
+ (condition (emacsql-sqlite-get-condition message)))
+ (signal condition (list message)))))))
+
+(defmethod emacsql ((connection emacsql-sqlite-connection) sql &rest args)
+ "Send structured SQL expression to CONNECTION with ARGS."
+ (let ((sql-string (apply #'emacsql-compile sql args)))
+ (emacsql-clear connection)
+ (emacsql-send-string connection sql-string)
+ (emacsql-sqlite--check-error connection)
+ (emacsql-sqlite--parse connection)))
+
+(provide 'emacsql-sqlite)
+
+;;; emacsql-sqlite.el ends here
diff --git a/emacsql.el b/emacsql.el
index 52b7ea87a6..c9097c6113 100644
--- a/emacsql.el
+++ b/emacsql.el
@@ -1,29 +1,30 @@
-;;; emacsql.el --- SQL database built on SQLite -*- lexical-binding: t; -*-
+;;; emacsql.el --- high-level SQL database front-end -*- lexical-binding: t;
-*-
;; This is free and unencumbered software released into the public domain.
;; Author: Christopher Wellons <wellons@nullprogram.com>
;; URL: https://github.com/skeeto/emacsql
;; Version: 1.0.0
-;; Package-Requires: ((cl-lib "0.3"))
;;; Commentary:
;; The purpose of this package is to provide a high-level Elisp
-;; interface to a high-performance database backend. Not every feature
-;; of SQLite will be exposed at the high-level, but most of it should
-;; be.
+;; interface to a high-performance database back-end. Not every feature
+;; of SQL will be exposed, but the important parts should be.
-;; Every emacsql function operates on a database connection
-;; established with `emacsql-connect', connecting to a SQLite database
-;; file. For each connection a sqlite3 inferior process is kept alive.
-;; Connections are closed with `elfeed-close'.
+;; Most emacsql functions operate on a database connection. A
+;; connection to SQLite is established with `emacsql-connect'. For
+;; each such connection a sqlite3 inferior process is kept alive in
+;; the background. Connections are closed with `emacsql-close'.
;; (defvar db (emacsql-connect "company.db"))
-;; Identifiers for tables and columns are symbols. SQL keywords are
-;; lisp keywords. Use `emacsql' for sending structured statements to
-;; the database.
+;; Other types of database connections are available (PostgreSQL via
+;; `emacsql-psql').
+
+;; Use `emacsql' to send an s-expression SQL statements to a connected
+;; database. Identifiers for tables and columns are symbols. SQL
+;; keywords are lisp keywords. Anything else is data.
;; (emacsql db [:create-table people [name id salary]])
@@ -57,29 +58,38 @@
;;; Code:
(require 'cl-lib)
+(require 'eieio)
+
+(defclass emacsql-connection ()
+ ((process :type process
+ :initarg :process
+ :accessor emacsql-process)
+ (log-buffer :type (or null buffer)
+ :initarg :log-buffer
+ :accessor emacsql-log-buffer
+ :documentation "Output log (debug)."))
+ (:documentation "A connection to a SQL database."))
+
+(defgeneric emacsql (connection sql &rest args)
+ "Send SQL s-expression to CONNECTION and return the results.")
+
+(defgeneric emacsql-close (connection)
+ "Close CONNECTION and free all resources.")
+
+(defmethod emacsql-buffer ((connection emacsql-connection))
+ "Get proccess buffer for CONNECTION."
+ (process-buffer (emacsql-process connection)))
+
+(defmethod emacsql-log ((connection emacsql-connection) message)
+ "Log MESSAGE into CONNECTION's log.
+MESSAGE should not have a newline on the end."
+ (let ((log (emacsql-log-buffer connection)))
+ (when log
+ (with-current-buffer log
+ (setf (point) (point-max))
+ (princ (concat message "\n") log)))))
-(defvar emacsql-sqlite3-executable "sqlite3"
- "Path to the sqlite3 executable.")
-
-(defun emacsql-sqlite3-unavailable-p ()
- "Return a reason if the sqlite3 executable is not available.
-
-:no-executable -- cannot find the executable
-:cannot-execute -- cannot run the executable
-:old-version -- sqlite3 version is too old"
- (let ((sqlite3 emacsql-sqlite3-executable))
- (if (null (executable-find sqlite3))
- :no-executable
- (condition-case _
- (with-temp-buffer
- (call-process sqlite3 nil (current-buffer) nil "--version")
- (let ((version (car (split-string (buffer-string)))))
- (if (version< version "3.0.0")
- :old-version
- nil)))
- (error :cannot-execute)))))
-
-;;; Error definitions
+;; Standard Emacsql errors:
(defmacro emacsql-deferror (symbol parents message)
"Defines a new error symbol for Emacsql."
@@ -94,74 +104,44 @@
"Emacsql had an unhandled condition")
(emacsql-deferror emacsql-syntax () "Invalid SQL statement")
-(emacsql-deferror emacsql-table () "SQL table error")
+(emacsql-deferror emacsql-table () "Table error")
(emacsql-deferror emacsql-lock () "Database locked")
(emacsql-deferror emacsql-transaction () "Invalid transaction")
(emacsql-deferror emacsql-fatal () "Fatal error")
-(emacsql-deferror emacsql-file () "Filesystem access error")
-
-(defvar emacsql-condition-alist
- '(("unable to open" emacsql-file)
- ("cannot open" emacsql-file)
- ("source database is busy" emacsql-file)
- ("unknown database" emacsql-file)
- ("writable" emacsql-file)
- ("no such table" emacsql-table)
- ("table [^ ]+ already exists" emacsql-table)
- ("no such column" emacsql-table)
- ("already another table" emacsql-table)
- ("Cannot add" emacsql-table)
- ("table name" emacsql-table)
- ("already an index" emacsql-table)
- ("constraint cannot be drop" emacsql-table)
- ("database is locked" emacsql-lock)
- ("no transaction is active" emacsql-transaction)
- ("cannot start a transaction" emacsql-transaction)
- ("out of memory" emacsql-fatal)
- ("corrupt database" emacsql-fatal)
- ("interrupt" emacsql-fatal)
- ("values were supplied" emacsql-syntax)
- ("mismatch" emacsql-syntax)
- ("no such" emacsql-syntax)
- ("does not match" emacsql-syntax)
- ("circularly defined" emacsql-syntax)
- ("parameters are not allowed" emacsql-syntax)
- ("missing" emacsql-syntax)
- ("is only allowed on" emacsql-syntax)
- ("more than one primary key" emacsql-syntax)
- ("not constant" emacsql-syntax)
- ("duplicate" emacsql-syntax)
- ("name reserved" emacsql-syntax)
- ("cannot use variables" emacsql-syntax)
- ("no tables specified" emacsql-syntax)
- ("syntax error" emacsql-syntax)
- ("no such function" emacsql-syntax)
- ("unknown function" emacsql-syntax)
- ("wrong number of arguments" emacsql-syntax)
- ("term does not match" emacsql-syntax)
- ("clause" emacsql-syntax)
- ("tree is too large" emacsql-syntax)
- ("too many" emacsql-syntax))
- "List of regexp's mapping sqlite3 output to conditions.")
-
-(defun emacsql-get-condition (message)
- (or (cadr (cl-assoc message emacsql-condition-alist
- :test (lambda (a b) (string-match-p b a))))
- 'emacsql-error))
+(emacsql-deferror emacsql-access () "Database access error")
(defun emacsql-error (format &rest args)
"Like `error', but signal an emacsql-syntax condition."
(signal 'emacsql-syntax (list (apply #'format format args))))
-;;; Connection handling:
+;;; Sending and receiving:
-(cl-defstruct (emacsql (:constructor emacsql--create))
- "A connection to a SQLite database."
- process file log)
+(defmethod emacsql-send-string
+ ((connection emacsql-connection) string &optional no-log)
+ "Send STRING to CONNECTION, automatically appending newline."
+ (let ((process (emacsql-process connection)))
+ (unless no-log (emacsql-log connection string))
+ (process-send-string process string)
+ (process-send-string process "\n")))
+
+(defmethod emacsql-clear ((connection emacsql-connection))
+ "Clear the process buffer for CONNECTION-SPEC."
+ (with-current-buffer (emacsql-buffer connection)
+ (erase-buffer)))
-(defun emacsql-buffer (conn)
- "Get proccess buffer for CONN."
- (process-buffer (emacsql-process conn)))
+(defgeneric emacsql-waiting-p (connection)
+ "Return non-nil if CONNECTION is ready for more input.")
+
+(defmethod emacsql-wait ((connection emacsql-connection) &optional timeout)
+ "Block until CONNECTION is waiting for further input."
+ (let ((end (when timeout (+ (float-time) timeout))))
+ (while (and (or (null timeout) (< (float-time) end))
+ (not (emacsql-waiting-p connection)))
+ (accept-process-output (emacsql-process connection) timeout))))
+
+(provide 'emacsql) ; end of generic function declarations
+
+;; Automatic connection cleanup:
(defvar emacsql-connections ()
"Collection of all known emacsql connections.
@@ -170,6 +150,12 @@ This collection exists for cleanup purposes.")
(defvar emacsql-reap-timer nil
"Timer used to check for dead emacsql connections.")
+(defun emacsql-add-connection (connection)
+ "Add CONNECTION to the global connection list."
+ (emacsql-start-reap-timer)
+ (push (cons (copy-sequence connection) (emacsql--ref connection))
+ emacsql-connections))
+
(defun emacsql--ref (thing)
"Create a weak reference to THING."
(let ((ref (make-hash-table :test 'eq :size 1 :weakness 'value)))
@@ -180,64 +166,6 @@ This collection exists for cleanup purposes.")
"Retrieve value from REF."
(gethash t ref))
-(cl-defun emacsql-connect (file &key debug)
- "Open a connected to database stored in FILE.
-If FILE is nil use an in-memory database.
-
-:debug LOG -- When non-nil, log all SQLite commands to a log
-buffer. This is for debugging purposes."
- (emacsql-start-reap-timer)
- (let* ((buffer (generate-new-buffer "*emacsql-connection*"))
- (fullfile (if file (expand-file-name file) ":memory:"))
- (process (start-process "emacsql" buffer emacsql-sqlite3-executable
- "-interactive" fullfile)))
- (setf (process-sentinel process) (lambda (_proc _) (kill-buffer buffer)))
- (process-send-string process ".mode list\n")
- (process-send-string process ".separator ' '\n")
- (process-send-string process ".nullvalue nil\n")
- (process-send-string process ".prompt ]\n")
- (process-send-string process "EMACSQL;\n") ;; force error message
- (let ((conn (emacsql--create
- :process process
- :file (when file fullfile)
- :log (when debug (generate-new-buffer "*emacsql-log*")))))
- (prog1 conn
- (emacsql--wait conn)
- (push (cons (copy-sequence conn) (emacsql--ref conn))
- emacsql-connections)))))
-
-(defun emacsql-close (conn)
- "Close connection to CONN database."
- (let ((process (emacsql-process conn)))
- (when (and process (process-live-p process))
- (process-send-string process ".exit\n"))))
-
-(defmacro emacsql-with-connection (conn-spec &rest body)
- "Open an Emacsql connection, evaluate BODY, and close the connection.
-CONN-SPEC is a connection specification like the call to
-`emacsql-connect', establishing a single binding.
-
- (emacsql-with-connection (db \"company.db\")
- (emacsql db [:create-table foo [x]])
- (emacsql db [:insert :into foo :values ([1] [2] [3])])
- (emacsql db [:select * :from foo]))"
- (declare (indent 1))
- `(let ((,(car conn-spec) (emacsql-connect ,@(cdr conn-spec))))
- (unwind-protect
- (progn ,@body)
- (emacsql-close ,(car conn-spec)))))
-
-(defmacro emacsql-thread (conn &rest statements)
- "Thread CONN through STATEMENTS.
-A statement can be a list, containing a statement with its arguments."
- (declare (indent 1))
- `(let ((emacsql--conn ,conn))
- ,@(cl-loop for statement in statements
- when (vectorp statement)
- collect (list 'emacsql 'emacsql--conn statement)
- else
- collect (append (list 'emacsql 'emacsql--conn) statement))))
-
(defun emacsql-reap ()
"Clean up after lost connections."
(cl-loop for (conn-copy . ref) in emacsql-connections
@@ -260,66 +188,35 @@ A statement can be a list, containing a statement with
its arguments."
(cancel-timer emacsql-reap-timer)
(setf emacsql-reap-timer nil)))
-;;; Sending and receiving:
+;; Useful macros:
-(defun emacsql--log (conn &rest messages)
- "Log MESSAGES into CONN's log."
- (let ((log (emacsql-log conn)))
- (when log
- (with-current-buffer log
- (setf (point) (point-max))
- (mapc (lambda (s) (princ s log)) messages)))))
+(require 'emacsql-sqlite) ; for `emacsql-connect'
-(defun emacsql--send (conn string)
- "Send STRING to CONN, automatically appending newline."
- (let ((process (emacsql-process conn)))
- (emacsql--log conn string "\n")
- (process-send-string process string)
- (process-send-string process "\n")))
+(defmacro emacsql-with-connection (connection-spec &rest body)
+ "Open an Emacsql connection, evaluate BODY, and close the connection.
+CONNECTION-SPEC is a connection specification like the call to
+`emacsql-connect', establishing a single binding.
-(defun emacsql--clear (conn)
- "Clear the process buffer for CONN."
- (with-current-buffer (emacsql-buffer conn)
- (erase-buffer)))
+ (emacsql-with-connection (db \"company.db\")
+ (emacsql db [:create-table foo [x]])
+ (emacsql db [:insert :into foo :values ([1] [2] [3])])
+ (emacsql db [:select * :from foo]))"
+ (declare (indent 1))
+ `(let ((,(car connection-spec) (emacsql-connect ,@(cdr connection-spec))))
+ (unwind-protect
+ (progn ,@body)
+ (emacsql-close ,(car connection-spec)))))
-(defun emacsql--complete-p (conn)
- "Return non-nil if receive buffer has finished filling."
- (with-current-buffer (emacsql-buffer conn)
- (cond ((= (buffer-size) 1) (string= "]" (buffer-string)))
- ((> (buffer-size) 1) (string= "\n]"
- (buffer-substring
- (- (point-max) 2) (point-max)))))))
-
-(defun emacsql--parse (conn)
- "Parse a query result into an s-expression."
- (with-current-buffer (emacsql-buffer conn)
- (let ((standard-input (current-buffer)))
- (setf (point) (point-min))
- (cl-loop until (looking-at "]")
- collect (read) into row
- when (looking-at "\n")
- collect row into rows
- and do (progn (forward-char 1) (setf row ()))
- finally (cl-return rows)))))
-
-(defun emacsql--check-error (conn)
- "Return non-nil or throw an appropriate error."
- (with-current-buffer (emacsql-buffer conn)
- (emacsql--wait conn)
- (setf (point) (point-min))
- (prog1 t
- (when (looking-at "Error:")
- (let* ((message (buffer-substring (line-beginning-position)
- (line-end-position)))
- (condition (emacsql-get-condition message)))
- (signal condition (list message)))))))
-
-(defun emacsql--wait (conn &optional timeout)
- "Block Emacs until CONN has finished sending output."
- (let ((end (when timeout (+ (float-time) timeout))))
- (while (and (or (null timeout) (< (float-time) end))
- (not (emacsql--complete-p conn)))
- (accept-process-output (emacsql-process conn) timeout))))
+(defmacro emacsql-thread (connection &rest statements)
+ "Thread CONNECTION through STATEMENTS.
+A statement can be a list, containing a statement with its arguments."
+ (declare (indent 1))
+ `(let ((emacsql--conn ,connection))
+ ,@(cl-loop for statement in statements
+ when (vectorp statement)
+ collect (list 'emacsql 'emacsql--conn statement)
+ else
+ collect (append (list 'emacsql 'emacsql--conn) statement))))
;;; Escaping:
@@ -355,7 +252,7 @@ A statement can be a list, containing a statement with its
arguments."
(vector (concat "(" (mapconcat #'emacsql-escape-value vector ", ") ")"))
(otherwise (emacsql-error "Invalid vector %S" vector))))
-;; Structured SQL compilation:
+;; S-expression SQL compilation:
(defvar emacsql-expanders ()
"Alist of all expansion functions.")
@@ -430,16 +327,9 @@ a list of (<string> [arg-pos] ...)."
(emacsql-error "Invalid var type %S" kind))))))))
(defun emacsql-compile (sql &rest args)
- "Compile structured SQL expression into a string."
+ "Compile s-expression SQL expression into a string."
(apply #'emacsql-format (emacsql-expand sql) args))
-(defun emacsql (conn sql &rest args)
- "Send structured SQL expression to CONN with ARGS."
- (emacsql--clear conn)
- (emacsql--send conn (apply #'emacsql-format (emacsql-expand sql) args))
- (emacsql--check-error conn)
- (emacsql--parse conn))
-
(defun emacsql-var (var)
"Return the index number of VAR, or nil if VAR is not a variable.
A variable is a symbol that looks like $1, $2, $3, etc. A $ means
@@ -846,16 +736,15 @@ definitions for return from a `emacsql-defexpander'."
(pop-to-buffer (current-buffer))))))
(defun emacsql-flatten-sql (sql)
- "Convert a structured SQL into a flat string for display."
+ "Convert a s-expression SQL into a flat string for display."
(cl-destructuring-bind (string . vars) (emacsql-expand sql)
(apply #'format string (cl-loop for i from 1 to (length vars)
collect (intern (format "$%d" i))))))
+;;;###autoload
(defun emacsql-show-last-sql ()
- "Display the compiled SQL of the structured SQL expression before point."
+ "Display the compiled SQL of the s-expression SQL expression before point."
(interactive)
(emacsql-show-sql (emacsql-flatten-sql (preceding-sexp))))
-(provide 'emacsql)
-
;;; emacsql.el ends here
- [nongnu] elpa/emacsql 935cca89a9 176/427: Add updated information about Windows., (continued)
- [nongnu] elpa/emacsql 935cca89a9 176/427: Add updated information about Windows., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql b3aea1e6af 055/427: Oops, fix >= back., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql c4396ec5e6 057/427: Fix a bunch of warnings., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql e9fbc4a913 061/427: Fill out a Makefile., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 829298d5a7 063/427: Add dependency listing., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 231ec586ca 088/427: Drop forced process coding system., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql eba26bead6 102/427: Add emacsql-compile function for debugging., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql d5cfaee783 158/427: Be more precise about error messages., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql f512300aba 054/427: Fix a few things in emacsql-expr., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql e900f99091 075/427: Update examples., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 1116a0873e 163/427: Turn everything into generic functions.,
ELPA Syncer <=
- [nongnu] elpa/emacsql 47d9476a02 142/427: Add tests for quote operator., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql cd5e856ea6 150/427: Add :autoincrement., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql f31120edb6 155/427: Fix up documentation headers., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql adfbc7ed83 156/427: Add emacsql-show-last-sql., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 60d92d3051 159/427: Change the output mode to list., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql d2f1bcef5d 165/427: Rename add-connection to register., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 9dcfebfba7 030/427: Factor out schema->string code., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 1f6c06bda9 050/427: Use expr expansion in :where expander., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 39aa16906a 034/427: Remove redundant wait., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql cda366379a 085/427: Add Windows note., ELPA Syncer, 2022/12/13