[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])] ()
- [nongnu] elpa/emacsql 048e81b759 320/427: Add file tests/.nosearch, (continued)
- [nongnu] elpa/emacsql 048e81b759 320/427: Add file tests/.nosearch, ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 017cd8460d 329/427: Use own data root in emacsql-sqlite., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 03d4788708 332/427: Bump to version 2.0.0 (fix #15)., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 0a2b3f6496 337/427: Follow rename of emacsql-with-vars in doc-strings., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql a60deae960 335/427: Add NOTNULL and ISNULL special operators (#16)., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql c634a1b6e1 340/427: Use initialize-instance with emacsql-sqlite (fixes #17)., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 176cf10063 342/427: Bump to 2.0.1., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 95a00de3f1 346/427: Save match-data around call to accept-process-output, ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 8f3d0d4b81 344/427: Use font-lock-flush and font-lock-ensure if available, ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 3176aeee61 345/427: Use elisp--preceding-sexp if available, ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 327b09b4b9 348/427: Add support for raw strings and raw parameters (#26, #28).,
ELPA Syncer <=
- [nongnu] elpa/emacsql c93f52159f 347/427: Bump to version 2.0.2., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql e91bac3a20 350/427: Add cl-generic require to emacsql.el (#32)., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql b65c5b03d5 351/427: Fix up Cask file., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql e3bc9b105f 354/427: Finish removing Cask, including updating the README, ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 83a278aa6b 356/427: Remove trailing &key in method definition, ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 67ca8124bc 425/427: make: Suppress warning about obsolete autoload package, ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql e318a6c8f6 426/427: Add new SQLite back-ends, ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 9f0a19280c 296/427: Enhance emacsql-with-transaction to retry., ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 616dde3752 361/427: An identifier named * means select all columns (#19), ELPA Syncer, 2022/12/13
- [nongnu] elpa/emacsql 5da614bc9b 359/427: Drop finalizer use and explicitely depend on Emacs 25, ELPA Syncer, 2022/12/13