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

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

[nongnu] elpa/emacsql 327b09b4b9 348/427: Add support for raw strings an


From: ELPA Syncer
Subject: [nongnu] elpa/emacsql 327b09b4b9 348/427: Add support for raw strings and raw parameters (#26, #28).
Date: Tue, 13 Dec 2022 03:00:00 -0500 (EST)

branch: elpa/emacsql
commit 327b09b4b99ccb6b5605b804027a42fd73589929
Author: Christopher Wellons <wellons@nullprogram.com>
Commit: Christopher Wellons <wellons@nullprogram.com>

    Add support for raw strings and raw parameters (#26, #28).
    
    Strings quoted with ' are not printed when used. A new "r" parameter
    type was also introduced to include unprinted string values in
    queries.
---
 README.md                       | 14 ++++++++++++++
 emacsql-compiler.el             | 25 +++++++++++++++++++------
 tests/emacsql-compiler-tests.el | 14 ++++++++++++++
 3 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/README.md b/README.md
index c76ed67f1d..2edb978142 100644
--- a/README.md
+++ b/README.md
@@ -137,6 +137,17 @@ does not "escape" `$tn` parameter symbols.
 (emacsql db [... :where (= category 'hiking)])
 ```
 
+Quoting a string makes EmacSQL handle it as a "raw string." These raw
+strings are not printed when being assembled into a query. These are
+intended for use in special circumstances like filenames (`ATTACH`) or
+pattern matching (`LIKE`). It is vital that raw strings are not
+returned as results.
+
+```el
+(emacsql db [... :where (like name '"%foo%")])
+(emacsql db [:attach '"/path/to/foo.db" :as foo])
+```
+
 Since template parameters include their type they never need to be
 quoted.
 
@@ -261,6 +272,8 @@ one-indexed.
 
 ```el
 (emacsql db [:select * :from $i1 :where (> salary $s2)] 'employees 50000)
+
+(emacsql db [:select * :from employees :where (like name $r1)] "%Smith%")
 ```
 
 The letter before the number is the type.
@@ -268,6 +281,7 @@ The letter before the number is the type.
  * `i` : identifier
  * `s` : scalar
  * `v` : vector (or multiple vectors)
+ * `r` : raw, unprinted strings
  * `S` : schema
 
 When combined with `:values`, the vector type can refer to lists of
diff --git a/emacsql-compiler.el b/emacsql-compiler.el
index 2f5b596f4e..3267d18118 100644
--- a/emacsql-compiler.el
+++ b/emacsql-compiler.el
@@ -83,6 +83,12 @@
           ((numberp value) (prin1-to-string value))
           ((emacsql-quote-scalar (prin1-to-string value))))))
 
+(defun emacsql-escape-raw (value)
+  "Escape VALUE for sending to SQLite."
+  (cond ((null value) "NULL")
+        ((stringp value) (emacsql-quote-scalar value))
+        ((error "Expected string or nil"))))
+
 (defun emacsql-escape-vector (vector)
   "Encode VECTOR into a SQL vector scalar."
   (cl-typecase vector
@@ -174,28 +180,30 @@
   "Return the index and type of THING, or nil if THING is not a parameter.
 A parameter is a symbol that looks like $i1, $s2, $v3, etc. The
 letter refers to the type: identifier (i), scalar (s),
-vector (v), schema (S)."
+vector (v), raw string (r), schema (S)."
   (when (symbolp thing)
     (let ((name (symbol-name thing)))
-      (when (string-match-p "^\\$[isvS][0-9]+$" name)
+      (when (string-match-p "^\\$[isvrS][0-9]+$" name)
         (cons (1- (read (substring name 2)))
               (cl-ecase (aref name 1)
                 (?i :identifier)
                 (?s :scalar)
                 (?v :vector)
+                (?r :raw)
                 (?S :schema)))))))
 
 (defmacro emacsql-with-params (prefix &rest body)
   "Evaluate BODY, collecting parameters.
-Provided local functions: `param', `identifier', `scalar',
-`svector', `expr', `subsql', and `combine'. BODY should return a string,
-which will be combined with variable definitions."
+Provided local functions: `param', `identifier', `scalar', `raw',
+`svector', `expr', `subsql', and `combine'. BODY should return a
+string, which will be combined with variable definitions."
   (declare (indent 1))
   `(let ((emacsql--vars ()))
      (cl-flet* ((combine (prepared) (emacsql--*combine prepared))
                 (param (thing) (emacsql--!param thing))
                 (identifier (thing) (emacsql--!param thing :identifier))
                 (scalar (thing) (emacsql--!param thing :scalar))
+                (raw (thing) (emacsql--!param thing :raw))
                 (svector (thing) (combine (emacsql--*vector thing)))
                 (expr (thing) (combine (emacsql--*expr thing)))
                 (subsql (thing)
@@ -218,6 +226,7 @@ Only use within `emacsql-with-params'!"
                  (:identifier (emacsql-escape-identifier thing))
                  (:scalar (emacsql-escape-scalar thing))
                  (:vector (emacsql-escape-vector thing))
+                 (:raw (emacsql-escape-raw thing))
                  (:schema (emacsql-prepare-schema thing)))
              (if (and (not (null thing))
                       (not (keywordp thing))
@@ -275,7 +284,10 @@ Only use within `emacsql-with-params'!"
             ((asc desc)
              (format "%s %s" (recur 0) (upcase (symbol-name op))))
             ;; Special case quote
-            ((quote) (scalar (nth 0 args)))
+            ((quote) (let ((arg (nth 0 args)))
+                       (if (stringp arg)
+                           (raw arg)
+                         (scalar arg))))
             ;; Special case funcall
             ((funcall)
              (format "%s(%s)" (recur 0)
@@ -365,6 +377,7 @@ Only use within `emacsql-with-params'!"
                         (:identifier (emacsql-escape-identifier thing))
                         (:scalar (emacsql-escape-scalar thing))
                         (:vector (emacsql-escape-vector thing))
+                        (:raw (emacsql-escape-raw thing))
                         (:schema (emacsql-prepare-schema thing))
                         (otherwise
                          (emacsql-error "Invalid var type %S" kind))))))))
diff --git a/tests/emacsql-compiler-tests.el b/tests/emacsql-compiler-tests.el
index 5297245f3c..bed49c8889 100644
--- a/tests/emacsql-compiler-tests.el
+++ b/tests/emacsql-compiler-tests.el
@@ -33,6 +33,12 @@
   (should (string= (emacsql-escape-vector '([1 2 3] [4 5 6]))
                    "(1, 2, 3), (4, 5, 6)")))
 
+(ert-deftest emacsql-escape-raw ()
+  (should (string= (emacsql-escape-raw "/var/emacsql") "'/var/emacsql'"))
+  (should (string= (emacsql-escape-raw "a b c") "'a b c'"))
+  (should (string= (emacsql-escape-raw "a 'b' c") "'a ''b'' c'"))
+  (should (string= (emacsql-escape-raw nil) "NULL")))
+
 (ert-deftest emacsql-schema ()
   (should (string= (emacsql-prepare-schema [a]) "a &NONE"))
   (should (string= (emacsql-prepare-schema [a b c])
@@ -55,6 +61,7 @@
   (should (equal (emacsql-param '$1) nil))
   (should (equal (emacsql-param '$s5) '(4 . :scalar)))
   (should (equal (emacsql-param '$v10) '(9 . :vector)))
+  (should (equal (emacsql-param '$r2) '(1 . :raw)))
   (should (equal (emacsql-param '$a) nil))
   (should (equal (emacsql-param '$i10) '(9 . :identifier))))
 
@@ -86,6 +93,13 @@
     ([:select p:name :from [(as [:select * :from people] p)]] '()
      "SELECT p.name FROM (SELECT * FROM people) AS p;")))
 
+(ert-deftest emacsql-attach ()
+  (emacsql-tests-with-queries
+    ([:attach $r1 :as $i2] '("/var/foo.db" foo)
+     "ATTACH '/var/foo.db' AS foo;")
+    ([:detach $i1] '(foo)
+     "DETACH foo;")))
+
 (ert-deftest emacsql-create-table ()
   (emacsql-tests-with-queries
     ([:create-table foo ([a b c])] ()



reply via email to

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