[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/triples 2dae3d49b9 18/19: Various fixes for emacsql cod
From: |
ELPA Syncer |
Subject: |
[elpa] externals/triples 2dae3d49b9 18/19: Various fixes for emacsql code, which wasn't being tested correctly. |
Date: |
Sat, 5 Nov 2022 11:58:17 -0400 (EDT) |
branch: externals/triples
commit 2dae3d49b9e0846f63a64eae19a5fe0facd7a3aa
Author: Andrew Hyatt <ahyatt@gmail.com>
Commit: Andrew Hyatt <ahyatt@gmail.com>
Various fixes for emacsql code, which wasn't being tested correctly.
---
triples-test.el | 52 ++++++++++++++++++--------------
triples.el | 92 ++++++++++++++++++++++++++++++++-------------------------
2 files changed, 81 insertions(+), 63 deletions(-)
diff --git a/triples-test.el b/triples-test.el
index a9c635218c..04217193e9 100644
--- a/triples-test.el
+++ b/triples-test.el
@@ -30,11 +30,11 @@ easily debug into it.")
(sql-sqlite (format "*schema test db SQL %s*" triples-test-db-file))))
(defun triples-test-insert (mode)
- (let ((triples--sqlite-interface mode))
+ (let ((triples-sqlite-interface mode))
(triples-test-with-temp-db
(triples--insert db "sub" 'pred "obj")
- (should (equal (triples--select db)
- '(("sub" pred "obj" nil))))
+ (should (equal (mapcar (lambda (row) (seq-take row 3)) (triples--select
db))
+ '(("sub" pred "obj"))))
;; Test that we actually are storing with builtin something compatible
;; with emacsql.
(when (eq mode 'builtin)
@@ -50,11 +50,15 @@ easily debug into it.")
(should-error (triples--insert db "sub" "pred" "obj"))
(should-error (triples--insert db "sub" 'pred "obj" '(ordinary-list)))
(should-error (triples--insert db "sub" 'pred "obj" "string"))
- ;; Test that we can have symbol subject and objects
+ ;; Test that we can have symbol subject and objects.
(triples--insert db 'sub 'pred 'obj)
(should (equal
- (triples--select db 'sub)
- '((sub pred obj nil)))))))
+ (mapcar (lambda (row) (seq-take row 3)) (triples--select db
'sub))
+ '((sub pred obj))))
+ ;; Test that properties aren't strings. They happen to be stored
+ ;; differently for each system due to differences in how the inserting
+ ;; interface works.
+ (should (plistp (nth 3 (car (triples--select db 'sub))))))))
(ert-deftest triples-test-insert-builtin ()
(skip-unless (and (fboundp 'sqlite-available-p) (sqlite-available-p)))
@@ -65,7 +69,7 @@ easily debug into it.")
(triples-test-insert 'emacsql))
(defun triples-test-delete (mode)
- (let ((triples--sqlite-interface mode))
+ (let ((triples-sqlite-interface mode))
(triples-test-with-temp-db
(triples--insert db 1 'pred 2)
(triples--insert db 2 'pred 1)
@@ -88,7 +92,7 @@ easily debug into it.")
(triples-test-delete 'emacsql))
(defun triples-test-delete-subject-predicate-prefix (mode)
- (let ((triples--sqlite-interface mode))
+ (let ((triples-sqlite-interface mode))
(triples-test-with-temp-db
(triples--insert db 1 'test/foo 2)
(triples--insert db 1 'bar/bar 1)
@@ -107,17 +111,19 @@ easily debug into it.")
(triples-test-delete-subject-predicate-prefix 'emacsql))
(defun triples-test-select (mode)
- (let ((triples--sqlite-interface mode))
+ (let ((triples-sqlite-interface mode))
(triples-test-with-temp-db
- (triples--insert db 1 'pred 2 '(:a 1))
- (let ((expected '((1 pred 2 (:a 1)))))
- (should (equal (triples--select db 1) expected))
- (should (equal (triples--select db nil 'pred) expected))
- (should (equal (triples--select db nil nil 2) expected))
- (should (equal (triples--select db 1 nil 2) expected))
- (should (equal (triples--select db 1 'pred 2) expected))
- (should (equal '((1)) (triples--select db 1 nil nil nil '(subject))))
- (should (equal '((1 pred)) (triples--select db 1 nil nil nil '(subject
predicate))))))))
+ (when (eq mode 'emacsql)
+ (emacsql-enable-debugging db))
+ (triples--insert db 1 'pred 2 '(:a 1))
+ (let ((expected '((1 pred 2 (:a 1)))))
+ (should (equal (triples--select db 1) expected))
+ (should (equal (triples--select db nil 'pred) expected))
+ (should (equal (triples--select db nil nil 2) expected))
+ (should (equal (triples--select db 1 nil 2) expected))
+ (should (equal (triples--select db 1 'pred 2) expected))
+ (should (equal '((1)) (triples--select db 1 nil nil nil '(subject))))
+ (should (equal '((1 pred)) (triples--select db 1 nil nil nil '(subject
predicate))))))))
(ert-deftest triples-test-select-builtin ()
(skip-unless (and (fboundp 'sqlite-available-p) (sqlite-available-p)))
@@ -128,7 +134,7 @@ easily debug into it.")
(triples-test-select 'emacsql))
(defun triples-test-select-with-pred-prefix (mode)
- (let ((triples--sqlite-interface mode))
+ (let ((triples-sqlite-interface mode))
(triples-test-with-temp-db
(triples--insert db 'sub1 'pred/foo 'obj)
(triples--insert db 'sub1 'pred/bar 'obj)
@@ -146,11 +152,13 @@ easily debug into it.")
(triples-test-select 'emacsql))
(defun triples-test-select-predicate-object-fragment (mode)
- (let ((triples--sqlite-interface mode))
+ (let ((triples-sqlite-interface mode))
(triples-test-with-temp-db
(triples--insert db 'sub1 'pred/foo "a whole phrase")
- (should (equal (triples--select-predicate-object-fragment db 'pred/foo
"whole")
- '((sub1 pred/foo "a whole phrase" nil)))))))
+ (should (equal
+ (mapcar (lambda (row) (seq-take row 3))
+ (triples--select-predicate-object-fragment db 'pred/foo
"whole"))
+ '((sub1 pred/foo "a whole phrase")))))))
(ert-deftest triples-test-select-predicate-object-fragment-builtin ()
(skip-unless (and (fboundp 'sqlite-available-p) (sqlite-available-p)))
diff --git a/triples.el b/triples.el
index b005ce381e..ce0c920b08 100644
--- a/triples.el
+++ b/triples.el
@@ -55,7 +55,7 @@ installed.")
(error "The triples package requires either Emacs 29 or the emacsql
package to be installed."))
(pcase triples-sqlite-interface
('builtin (let* ((db (sqlite-open file)))
- (sqlite-execute db "CREATE TABLE IF NOT EXISTS triples(subject
TEXT NOT NULL, predicate TEXT NOT NULL, object TEXT, properties TEXT NOT NULL)")
+ (sqlite-execute db "CREATE TABLE IF NOT EXISTS triples(subject
TEXT NOT NULL, predicate TEXT NOT NULL, object NOT NULL, properties TEXT NOT
NULL)")
(sqlite-execute db "CREATE INDEX IF NOT EXISTS subject_idx ON
triples (subject)")
(sqlite-execute db "CREATE INDEX IF NOT EXISTS
subject_predicate_idx ON triples (subject, predicate)")
(sqlite-execute db "CREATE INDEX IF NOT EXISTS
predicate_object_idx ON triples (predicate, object)")
@@ -66,13 +66,13 @@ installed.")
(let* ((db (emacsql-sqlite file))
(triple-table-exists
(emacsql db [:select name
- :from sqlite_master
- :where (= type table) :and (= name
'triples)])))
+ :from sqlite_master
+ :where (= type table) :and (= name 'triples)])))
(unless triple-table-exists
- (emacsql db [:create-table triples ([(subject text :not-null)
+ (emacsql db [:create-table triples ([(subject :not-null)
(predicate text :not-null)
(object :not-null)
- (properties)])])
+ (properties text :not-null)])])
(emacsql db [:create-index subject_idx :on triples [subject]])
(emacsql db [:create-index subject_predicate_idx :on triples [subject
predicate]])
(emacsql db [:create-index predicate_object_idx :on triples
[predicate object]])
@@ -139,8 +139,11 @@ normal schema checks, so should not be called from client
programs."
;; duplicate triples each with null properties.
(triples-standardize-val properties))))
('emacsql
+ ;; We use a simple small plist '(:t t). Unlike sqlite, we can't insert
this
+ ;; as a string, or else it will store as something that would come out as
a
+ ;; string. And if we use nil, it will actually store a NULL in the cell.
(emacsql db [:replace :into triples :values $v1]
- [subject predicate object (triples-standardize-val
properties)]))))
+ (vector subject (triples--decolon predicate) object (or
properties '(:t t)))))))
(defun triples--emacsql-andify (wc)
"In emacsql where clause WC, insert `:and' between query elements.
@@ -174,18 +177,21 @@ all to nil, everything will be deleted, so be careful!"
(when properties
"PROPERTIES = ?")))
" AND "))))
(mapcar #'triples-standardize-val (seq-filter #'identity (list
subject predicate object properties)))))
- ('emacsql (emacsql db
- (apply #'vector
- (append '(:delete :from triples)
- (when (or subject predicate object
properties)
- (triples--emacsql-andify
- (append
- '(:where)
- (when subject '((= subject $s1)))
- (when predicate '((= predicate $r2)))
- (when object '((= object $s3)))
- (when properties '((= properties
$r4))))))))
- (seq-filter #'identity (list subject predicate object
properties))))))
+ ('emacsql
+ (let ((n 0))
+ (apply #'emacsql
+ db
+ (apply #'vector
+ (append '(:delete :from triples)
+ (when (or subject predicate object properties)
+ (triples--emacsql-andify
+ (append
+ '(:where)
+ (when subject `((= subject ,(intern (format
"$s%d" (cl-incf n))))))
+ (when predicate `((= predicate ,(intern
(format "$s%d" (cl-incf n))))))
+ (when object `((= object ,(intern (format
"$s%d" (cl-incf n))))))
+ (when properties `((= properties ,(intern
(format "$s%d" (cl-incf n)))))))))))
+ (seq-filter #'identity (list subject predicate object
properties)))))))
(defun triples--delete-subject-predicate-prefix (db subject pred-prefix)
"Delete triples matching SUBJECT and predicates with PRED-PREFIX."
@@ -215,7 +221,7 @@ all to nil, everything will be deleted, so be careful!"
(sqlite-select db "SELECT * from triples WHERE predicate
= ? AND object LIKE ?"
(list (triples-standardize-val predicate)
(format "%%%s%%"
object-fragment)))))
- ('emacsql (emacsql db [:select * :from triples :where (= predicate $r1)
:and (like object $s2)]
+ ('emacsql (emacsql db [:select * :from triples :where (= predicate $s1)
:and (like object $s2)]
predicate (format "%%%s%%" object-fragment)))))
(defun triples--select (db &optional subject predicate object properties
selector)
@@ -240,21 +246,23 @@ object, properties to retrieve or nil for *."
(when properties "PROPERTIES = ?")))
" AND "))))
(mapcar #'triples-standardize-val
(seq-filter #'identity (list subject predicate object properties))))))
- ('emacsql (emacsql db (apply #'vector
- (append `(:select
- ,(if selector
- (mapconcat (lambda (e) (format
"%s" e)) selector ", ")
- '*)
- :from triples)
- (when (or subject predicate object
properties)
- (triples--emacsql-andify
- (append
- '(:where)
- (when subject '((= subject $s1)))
- (when predicate '((= predicate
$r2)))
- (when object '((= object $s3)))
- (when properties '((= properties
$r4))))))))
- (seq-filter #'identity (list subject predicate object
properties))))))
+ ('emacsql
+ (let ((n 0))
+ (apply #'emacsql
+ db
+ (apply #'vector
+ (append `(:select
+ ,(if selector (apply #'vector selector) '*)
+ :from triples)
+ (when (or subject predicate object properties)
+ (triples--emacsql-andify
+ (append
+ '(:where)
+ (when subject `((= subject ,(intern (format
"$s%d" (cl-incf n))))))
+ (when predicate `((= predicate ,(intern
(format "$s%d" (cl-incf n))))))
+ (when object `((= object ,(intern (format
"$s%d" (cl-incf n))))))
+ (when properties `((= properties ,(intern
(format "$s%d" (cl-incf n)))))))))))
+ (seq-filter #'identity (list subject predicate object
properties)))))))
;; Code after this point should not call sqlite or emacsql directly. If any
more
;; calls are needed, put them in a defun, make it work for sqlite and emacsql,
@@ -361,13 +369,15 @@ PROPERTIES is a plist of properties, without TYPE
prefixes."
The transaction will abort if an error is thrown."
(declare (indent 0) (debug t))
(let ((db-var (gensym "db")))
- `(let ((,db-var ,db))
- (condition-case nil
- (progn
- (sqlite-transaction ,db-var)
- ,@body
- (sqlite-commit ,db-var))
- (error (sqlite-rollback ,db-var))))))
+ (pcase triples-sqlite-interface
+ ('builtin `(let ((,db-var ,db))
+ (condition-case nil
+ (progn
+ (sqlite-transaction ,db-var)
+ ,@body
+ (sqlite-commit ,db-var))
+ (error (sqlite-rollback ,db-var)))))
+ ('emacsql `(emacsql-with-transaction ,db ,@body)))))
(defun triples-set-types (db subject &rest combined-props)
"Set all data for types in COMBINED-PROPS in DB for SUBJECT.
- [elpa] branch externals/triples created (now d17b3d6e17), ELPA Syncer, 2022/11/05
- [elpa] externals/triples 7d5aca3bb8 02/19: Fix issue where single element lists were not being treated as lists., ELPA Syncer, 2022/11/05
- [elpa] externals/triples 6f8f3376f1 06/19: Add `triples-set-types'., ELPA Syncer, 2022/11/05
- [elpa] externals/triples 5e8abd2989 01/19: Initial commit of triples module., ELPA Syncer, 2022/11/05
- [elpa] externals/triples cc5629fe5c 07/19: Wrap all database access in `triples-set-types' in a transaction., ELPA Syncer, 2022/11/05
- [elpa] externals/triples 257de87fdc 08/19: Minor code cleanup., ELPA Syncer, 2022/11/05
- [elpa] externals/triples 4627d6ed6d 10/19: Fix minor mistakes in ert tests., ELPA Syncer, 2022/11/05
- [elpa] externals/triples fb63dfe44a 12/19: Convert to sqlite., ELPA Syncer, 2022/11/05
- [elpa] externals/triples 0252dad7d1 17/19: Fixes from code review from Stefan Monnier., ELPA Syncer, 2022/11/05
- [elpa] externals/triples d17b3d6e17 19/19: Merge branch 'combined'., ELPA Syncer, 2022/11/05
- [elpa] externals/triples 2dae3d49b9 18/19: Various fixes for emacsql code, which wasn't being tested correctly.,
ELPA Syncer <=
- [elpa] externals/triples 6afcb290ca 15/19: Support both emacs 29 sqlite and emacsql., ELPA Syncer, 2022/11/05
- [elpa] externals/triples aca95ba7f3 03/19: Ensure that we don't duplicate triples., ELPA Syncer, 2022/11/05
- [elpa] externals/triples d82cc1d6b8 14/19: Finish basic sqlite layer, and fix everything so tests work., ELPA Syncer, 2022/11/05
- [elpa] externals/triples 8d7d3c13f4 05/19: Make the combined to and from functions public., ELPA Syncer, 2022/11/05
- [elpa] externals/triples ad6e329540 04/19: Fix for ert tests broken by the last commit., ELPA Syncer, 2022/11/05
- [elpa] externals/triples fdbbd5f61d 09/19: Added package-requires., ELPA Syncer, 2022/11/05
- [elpa] externals/triples cef7ad3a81 11/19: Remove emacs requirement for now., ELPA Syncer, 2022/11/05
- [elpa] externals/triples cca16121d9 13/19: Fix bugs in `triples-remove-type'., ELPA Syncer, 2022/11/05
- [elpa] externals/triples 3593f55dfb 16/19: Support numbers stored via emacsql., ELPA Syncer, 2022/11/05