emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/emacsql b5c8553fc9 1/2: Read all forms in column string re


From: ELPA Syncer
Subject: [nongnu] elpa/emacsql b5c8553fc9 1/2: Read all forms in column string returned by SQLite
Date: Wed, 27 Nov 2024 12:59:51 -0500 (EST)

branch: elpa/emacsql
commit b5c8553fc9f1cfb5aa1f122f77cf209ab3065e2f
Author: Jonas Bernoulli <jonas@bernoul.li>
Commit: Jonas Bernoulli <jonas@bernoul.li>

    Read all forms in column string returned by SQLite
    
    Unlike the low-level function of the removed legacy SQLite back-end
    (which inserted a single string into a buffer) `sqlite-select' and
    `sqlite3-exec' return a two-dimensional tree, in which cells have
    already been parsed.
    
    When a cell is still a string after that, then we have to read a sexp
    from that string.  That is usually enough, but in special cases the
    string may contain multiple sexp, for example, given:
    
      (emacsql db [:insert-into tbl :values (["a"] ["b"] ["c"])])
      (emacsql db [:select (funcall group-concat tbl)])
    
    we have to parse this string "\"a\"\";\"\"b\"\";\"\"c\"".
    
    The legacy back-end did not have to parse such a string explicitly,
    because it got to read the complete value (in this case confined to
    the first line) in a buffer containing this instead:
    
      ((\"a\"\";\"\"b\"\";\"\"c\"))
      success
      #
    
    so it can essentially do
    
      (car (read-from-string "((\"a\"\";\"\"b\"\";\"\"c\"))"))
    
    to parse everything in one go.  The new back-ends have helpfully
    made that this more complicated (which makes sense, it's just a
    bit inconvenient, when using our "store everything as a string"
    approach.
    
    An approach for the new back-ends, which needs much less code,
    could be:
    
      (caar (read-from-string (format "(%s)" col)))
    
    but that feels less safe.
    
    This commit teaches the new back-ends to behave the same as the
    legacy back-end used to.  In the future we might want to look into
    automatically stripping the separators.
    
    Closes #127.
---
 emacsql-sqlite-builtin.el | 12 ++++++------
 emacsql-sqlite-module.el  |  9 +++++----
 emacsql-sqlite.el         | 10 ++++++++++
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/emacsql-sqlite-builtin.el b/emacsql-sqlite-builtin.el
index 7ec926feff..986e99dd17 100644
--- a/emacsql-sqlite-builtin.el
+++ b/emacsql-sqlite-builtin.el
@@ -59,12 +59,12 @@ buffer. This is for debugging purposes."
   (condition-case err
       (let ((include-header emacsql-include-header))
         (mapcar (lambda (row)
-                  (prog1 (mapcar (lambda (col)
-                                   (cond (include-header col)
-                                         ((null col) nil)
-                                         ((equal col "") "")
-                                         ((numberp col) col)
-                                         (t (read col))))
+                  (prog1 (mapcan (lambda (col)
+                                   (cond (include-header (list col))
+                                         ((null col)     (list nil))
+                                         ((equal col "") (list ""))
+                                         ((numberp col)  (list col))
+                                         ((emacsql-sqlite-read-column col))))
                                  row)
                     (setq include-header nil)))
                 (sqlite-select (oref connection handle) message nil
diff --git a/emacsql-sqlite-module.el b/emacsql-sqlite-module.el
index ba4a4e99d7..c3cf29caa2 100644
--- a/emacsql-sqlite-module.el
+++ b/emacsql-sqlite-module.el
@@ -69,10 +69,11 @@ buffer. This is for debugging purposes."
                         (when include-header
                           (push header rows)
                           (setq include-header nil))
-                        (push (mapcar (lambda (col)
-                                        (cond ((null col) nil)
-                                              ((equal col "") "")
-                                              (t (read col))))
+                        (push (mapcan (lambda (col)
+                                        (cond
+                                         ((null col)     (list nil))
+                                         ((equal col "") (list ""))
+                                         ((emacsql-sqlite-read-column col))))
                                       row)
                               rows)))
         (nreverse rows))
diff --git a/emacsql-sqlite.el b/emacsql-sqlite.el
index 38ca112ea2..f1557637f9 100644
--- a/emacsql-sqlite.el
+++ b/emacsql-sqlite.el
@@ -188,6 +188,16 @@ been remove, so we can no longer fall back to that.
     (emacsql connection [:pragma (= busy-timeout $s1)]
              (* emacsql-sqlite-busy-timeout 1000))))
 
+(defun emacsql-sqlite-read-column (string)
+  (let ((value nil)
+        (beg 0)
+        (end (length string)))
+    (while (< beg end)
+      (let ((v (read-from-string string beg)))
+        (push (car v) value)
+        (setq beg (cdr v))))
+    (nreverse value)))
+
 (defun emacsql-sqlite-list-tables (connection)
   "Return a list of the names of all tables in CONNECTION.
 Tables whose names begin with \"sqlite_\", are not included



reply via email to

[Prev in Thread] Current Thread [Next in Thread]