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

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

[elpa] externals/triples 62967f76d3: Provide a lower-level triple API.


From: ELPA Syncer
Subject: [elpa] externals/triples 62967f76d3: Provide a lower-level triple API.
Date: Sat, 5 Nov 2022 21:58:06 -0400 (EDT)

branch: externals/triples
commit 62967f76d3fdb41d4524f942e1bf6fd501250490
Author: Andrew Hyatt <ahyatt@gmail.com>
Commit: Andrew Hyatt <ahyatt@gmail.com>

    Provide a lower-level triple API.
    
    Also add suggestions to the documentation about how to code directly to the
    database if needed.
---
 README.org      |  9 ++++++
 triples-test.el | 86 ++++++++++++++++++++++++++++-----------------------------
 triples.el      | 42 ++++++++++++++--------------
 3 files changed, 73 insertions(+), 64 deletions(-)

diff --git a/README.org b/README.org
index 66ab22eb64..81c820537c 100644
--- a/README.org
+++ b/README.org
@@ -77,3 +77,12 @@ There are other useful functions, including:
 Sometimes the triples library will require predicates that are without type, 
and sometimes with type, or "combined predicates".  The rule is that if the 
type is already specified in the function, it does not need to be respecified.  
If the type is not specified, it is included in the combined predicate.
 
 When returning data, if data is from just one type, the type is not returned 
in the returned predicates.  If the data is from multiple types, the type is 
returned as combined predicates.
+* Using direct SQL access
+Sometimes clients of this library need to do something with the database, and 
the higher-level triples functionality doesn't help.  If you would like 
lower-level functionality into handling triples, you can use the same low-level 
methods that the rest of this library uses.  These start with =triples-db-=.
+- =triples-db-insert=: Add a triple.  Uses SQL's =REPLACE= command, so there 
can't be completely duplicate triples (including the property, which often can 
serve as a disambiguation mechanism).
+- =triples-db-delete=: Delete triples matching the arguments.  Empty arguments 
match everything, so =(triples-db-delete db)= will delete all triples.
+- =triples-db-delete-subject-predicate-prefix=: Delete triples matching 
subjects and with predicates with a certain prefix.  This can't be done with 
=triples-db-delete= because that method uses exact matching for all arguments, 
and this uses prefix matching for the predicate.
+- =triples-db-select-predicate-object-fragment=: Select triples that contain 
an object partially in which the fragment appears.
+- =triples-db-select=: Select triples matching any of the parts of the triple. 
 Like =triples-db-delete=, empty arguments match everything.  You can specify 
exactly what to return with a selector.
+
+Sometimes this still doesn't cover what you might want to do.  In that case, 
you should write your own direct database access.  However, please follow the 
coding patterns for the functions above in writing it, so that the code works 
with both Emacs 29's builtin sqlite, and =emacsql=.
diff --git a/triples-test.el b/triples-test.el
index 6d3adb50ab..d8776100b1 100644
--- a/triples-test.el
+++ b/triples-test.el
@@ -32,8 +32,8 @@ easily debug into it.")
 (defun triples-test-insert (mode)
   (let ((triples-sqlite-interface mode))
     (triples-test-with-temp-db
-      (triples--insert db "sub" 'pred "obj")
-      (should (equal (mapcar (lambda (row) (seq-take row 3)) (triples--select 
db))
+      (triples-db-insert db "sub" 'pred "obj")
+      (should (equal (mapcar (lambda (row) (seq-take row 3)) 
(triples-db-select db))
                      '(("sub" pred "obj"))))
       ;; Test that we actually are storing with builtin something compatible
       ;; with emacsql.
@@ -41,24 +41,24 @@ easily debug into it.")
         (should (equal (sqlite-select db "SELECT * FROM triples")
                        '(("\"sub\"" "pred" "\"obj\"" "()")))))
       ;; Test that it replaces - this shouldn't result in two rows.
-      (triples--insert db "sub" 'pred "obj")
-      (should (= (length (triples--select db)) 1))
+      (triples-db-insert db "sub" 'pred "obj")
+      (should (= (length (triples-db-select db)) 1))
       ;; Test that colons in the predicate are stripped away when stored.
-      (triples--insert db "sub" :test/pred "obj")
-      (should (= (length (triples--select db nil 'test/pred)) 1))
+      (triples-db-insert db "sub" :test/pred "obj")
+      (should (= (length (triples-db-select db nil 'test/pred)) 1))
       ;; Test we correctly test for bad inputs.
-      (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"))
+      (should-error (triples-db-insert db "sub" "pred" "obj"))
+      (should-error (triples-db-insert db "sub" 'pred "obj" '(ordinary-list)))
+      (should-error (triples-db-insert db "sub" 'pred "obj" "string"))
       ;; Test that we can have symbol subject and objects.
-      (triples--insert db 'sub 'pred 'obj)
+      (triples-db-insert db 'sub 'pred 'obj)
       (should (equal
-               (mapcar (lambda (row) (seq-take row 3)) (triples--select db 
'sub))               
+               (mapcar (lambda (row) (seq-take row 3)) (triples-db-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))))))))
+      (should (plistp (nth 3 (car (triples-db-select db 'sub))))))))
 
 (ert-deftest triples-test-insert-builtin ()
   (skip-unless (and (fboundp 'sqlite-available-p) (sqlite-available-p)))
@@ -71,17 +71,17 @@ easily debug into it.")
 (defun triples-test-delete (mode)
   (let ((triples-sqlite-interface mode))
     (triples-test-with-temp-db
-     (triples--insert db 1 'pred 2)
-     (triples--insert db 2 'pred 1)
-     (triples--delete db 1)
-     (should (= 1 (length (triples--select db))))
-     (should (= 0 (length (triples--select db 1))))
-     (triples--insert db 1 'pred 2)
-     (triples--delete db nil nil 2)
-     (should (= 0 (length (triples--select db nil nil 2))))
-     (triples--insert db 1 'pred 2)
-     (triples--delete db nil 'pred nil)
-     (should (= 0 (length (triples--select db)))))))
+     (triples-db-insert db 1 'pred 2)
+     (triples-db-insert db 2 'pred 1)
+     (triples-db-delete db 1)
+     (should (= 1 (length (triples-db-select db))))
+     (should (= 0 (length (triples-db-select db 1))))
+     (triples-db-insert db 1 'pred 2)
+     (triples-db-delete db nil nil 2)
+     (should (= 0 (length (triples-db-select db nil nil 2))))
+     (triples-db-insert db 1 'pred 2)
+     (triples-db-delete db nil 'pred nil)
+     (should (= 0 (length (triples-db-select db)))))))
 
 (ert-deftest triples-test-delete-builtin ()
   (skip-unless (and (fboundp 'sqlite-available-p) (sqlite-available-p)))
@@ -94,13 +94,13 @@ easily debug into it.")
 (defun triples-test-delete-subject-predicate-prefix (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)
-     (triples--delete-subject-predicate-prefix db 1 'test)
-     (should (= 1 (length (triples--select db))))
+     (triples-db-insert db 1 'test/foo 2)
+     (triples-db-insert db 1 'bar/bar 1)
+     (triples-db-delete-subject-predicate-prefix db 1 'test)
+     (should (= 1 (length (triples-db-select db))))
      ;; Make sure colons are stripped.
-     (triples--delete-subject-predicate-prefix db 1 :bar)
-     (should (= 0 (length (triples--select db)))))))
+     (triples-db-delete-subject-predicate-prefix db 1 :bar)
+     (should (= 0 (length (triples-db-select db)))))))
 
 (ert-deftest triples-test-delete-subject-predicate-prefix-builtin ()
   (skip-unless (and (fboundp 'sqlite-available-p) (sqlite-available-p)))
@@ -115,15 +115,15 @@ easily debug into it.")
     (triples-test-with-temp-db
       (when (eq mode 'emacsql)
           (emacsql-enable-debugging db))
-      (triples--insert db 1 'pred 2 '(:a 1))
+      (triples-db-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))))))))
+        (should (equal (triples-db-select db 1) expected))
+        (should (equal (triples-db-select db nil 'pred) expected))
+        (should (equal (triples-db-select db nil nil 2) expected))
+        (should (equal (triples-db-select db 1 nil 2) expected))
+        (should (equal (triples-db-select db 1 'pred 2) expected))
+        (should (equal '((1)) (triples-db-select db 1 nil nil nil '(subject))))
+        (should (equal '((1 pred)) (triples-db-select db 1 nil nil nil 
'(subject predicate))))))))
 
 (ert-deftest triples-test-select-builtin ()
   (skip-unless (and (fboundp 'sqlite-available-p) (sqlite-available-p)))
@@ -136,10 +136,10 @@ easily debug into it.")
 (defun triples-test-select-with-pred-prefix (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)
-     (triples--insert db 'sub2 'pred/foo 'obj)
-     (should (equal (triples-test-list-sort (triples--select-pred-prefix db 
'sub1 'pred))
+     (triples-db-insert db 'sub1 'pred/foo 'obj)
+     (triples-db-insert db 'sub1 'pred/bar 'obj)
+     (triples-db-insert db 'sub2 'pred/foo 'obj)
+     (should (equal (triples-test-list-sort (triples-db-select-pred-prefix db 
'sub1 'pred))
                     (triples-test-list-sort '((sub1 pred/foo obj nil)
                                               (sub1 pred/bar obj nil))))))))
 
@@ -154,10 +154,10 @@ easily debug into it.")
 (defun triples-test-select-predicate-object-fragment (mode)
   (let ((triples-sqlite-interface mode))
     (triples-test-with-temp-db
-     (triples--insert db 'sub1 'pred/foo "a whole phrase")
+     (triples-db-insert db 'sub1 'pred/foo "a whole phrase")
      (should (equal
               (mapcar (lambda (row) (seq-take row 3))
-                      (triples--select-predicate-object-fragment db 'pred/foo 
"whole"))
+                      (triples-db-select-predicate-object-fragment db 
'pred/foo "whole"))
               '((sub1 pred/foo "a whole phrase")))))))
 
 (ert-deftest triples-test-select-predicate-object-fragment-builtin ()
diff --git a/triples.el b/triples.el
index ce0c920b08..6b17d71c9f 100644
--- a/triples.el
+++ b/triples.el
@@ -118,7 +118,7 @@ the string itself is wrapped in quotes."
         result
       (read result))))
 
-(defun triples--insert (db subject predicate object &optional properties)
+(defun triples-db-insert (db subject predicate object &optional properties)
   "Insert triple to DB: SUBJECT, PREDICATE, OBJECT with PROPERTIES.
 This is a SQL replace operation, because we don't want any
 duplicates; if the triple is the same, it has to differ at least
@@ -159,7 +159,7 @@ elements, but it shouldn't matter."
             (setq clauses (cdr clauses)))
           result)))
 
-(defun triples--delete (db &optional subject predicate object properties)
+(defun triples-db-delete (db &optional subject predicate object properties)
   "Delete triples matching SUBJECT, PREDICATE, OBJECT, PROPERTIES.
 If any of these are nil, they will not selected for. If you set
 all to nil, everything will be deleted, so be careful!"
@@ -193,7 +193,7 @@ all to nil, everything will be deleted, so be careful!"
                                  (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)
+(defun triples-db-delete-subject-predicate-prefix (db subject pred-prefix)
   "Delete triples matching SUBJECT and predicates with PRED-PREFIX."
   (unless (symbolp pred-prefix)
     (error "Predicates in triples must always be symbols"))
@@ -204,7 +204,7 @@ all to nil, everything will be deleted, so be careful!"
     ('emacsql (emacsql db [:delete :from triples :where (= subject $s1) :and 
(like predicate $r2)]
                        subject (format "%s/%%" (triples--decolon 
pred-prefix))))))
 
-(defun triples--select-pred-prefix (db subject pred-prefix)
+(defun triples-db-select-pred-prefix (db subject pred-prefix)
   "Return rows matching SUBJECT and PRED-PREFIX."
   (pcase triples-sqlite-interface
     ('builtin (mapcar (lambda (row) (mapcar #'triples-standardize-result row))
@@ -214,7 +214,7 @@ all to nil, everything will be deleted, so be careful!"
     ('emacsql (emacsql db [:select * :from triples :where (= subject $s1) :and 
(like predicate $r2)]
                        subject (format "%s/%%" pred-prefix)))))
 
-(defun triples--select-predicate-object-fragment (db predicate object-fragment)
+(defun triples-db-select-predicate-object-fragment (db predicate 
object-fragment)
   "Return rows with PREDICATE and with OBJECT-FRAGMENT in object."
   (pcase triples-sqlite-interface
     ('builtin (mapcar (lambda (row) (mapcar #'triples-standardize-result row))
@@ -224,7 +224,7 @@ all to nil, everything will be deleted, so be careful!"
     ('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)
+(defun triples-db-select (db &optional subject predicate object properties 
selector)
   "Return rows matching SUBJECT, PREDICATE, OBJECT, PROPERTIES.
 If any of these are nil, they are not included in the select
 statement. The SELECTOR is list of symbols subject, precicate,
@@ -288,39 +288,39 @@ object, properties to retrieve or nil for *."
       ('replace-subject
        (mapc
         (lambda (sub)
-          (triples--delete db sub))
+          (triples-db-delete db sub))
         (triples--subjects (cdr op))))
       ('replace-subject-type
        (mapc (lambda (sub-triples)
                (mapc (lambda (type)
                        ;; We have to ignore base, which keeps type information 
in general.
                        (unless (eq type 'base)
-                         (triples--delete-subject-predicate-prefix db (car 
sub-triples) type)))
+                         (triples-db-delete-subject-predicate-prefix db (car 
sub-triples) type)))
                      (seq-uniq
                       (mapcar #'car (mapcar #'triples-combined-to-type-and-prop
                                                      (mapcar #'cl-second (cdr 
sub-triples)))))))
              (triples--group-by-subjects (cdr op)))))
   (mapc (lambda (triple)
-          (apply #'triples--insert db triple))
+          (apply #'triples-db-insert db triple))
           (cdr op)))
 
 (defun triples-properties-for-predicate (db cpred)
   "Return the properties in DB for combined predicate CPRED as a plist."
   (mapcan (lambda (row)
             (list (intern (format ":%s" (nth 1 row))) (nth 2 row)))
-          (triples--select db cpred)))
+          (triples-db-select db cpred)))
 
 (defun triples-predicates-for-type (db type)
   "Return all predicates defined for TYPE in DB."
   (mapcar #'car
-          (triples--select db type 'schema/property nil nil '(object))))
+          (triples-db-select db type 'schema/property nil nil '(object))))
 
 (defun triples-verify-schema-compliant (db triples)
   "Error if TRIPLES is not compliant with schema in DB."
   (mapc (lambda (triple)
           (pcase-let ((`(,type . ,prop) (triples-combined-to-type-and-prop 
(nth 1 triple))))
             (unless (or (eq type 'base)
-                        (triples--select db type 'schema/property prop nil))
+                        (triples-db-select db type 'schema/property prop nil))
               (error "Property %s not found in schema" (nth 1 triple)))))
         triples)
   (mapc (lambda (triple)
@@ -422,7 +422,7 @@ PROPERTIES is a plist of properties, without TYPE prefixes."
                      (cons (cons (nth 2 db-triple) (nth 3 db-triple))
                            (gethash (nth 1 db-triple) preds))
                      preds))
-          (triples--select-pred-prefix db subject type))
+          (triples-db-select-pred-prefix db subject type))
     (append
      (cl-loop for k being the hash-keys of preds using (hash-values v)
               nconc (list (triples--encolon (cdr 
(triples-combined-to-type-and-prop k)))
@@ -440,20 +440,20 @@ PROPERTIES is a plist of properties, without TYPE 
prefixes."
                                     :base/virtual-reversed)))
                 (when reversed-prop
                   (let ((result
-                         (triples--select db nil reversed-prop subject nil 
'(subject))))
+                         (triples-db-select db nil reversed-prop subject nil 
'(subject))))
                     (when result (cons (triples--encolon pred) (list (mapcar 
#'car result)))))))))))
 
 (defun triples-remove-type (db subject type)
   "Remove TYPE for SUBJECT in DB, and all associated data."
   (triples-with-transaction
     db
-    (triples--delete db subject 'base/type type)
-    (triples--delete-subject-predicate-prefix db subject type)))
+    (triples-db-delete db subject 'base/type type)
+    (triples-db-delete-subject-predicate-prefix db subject type)))
 
 (defun triples-get-types (db subject)
   "From DB, get all types for SUBJECT."
   (mapcar #'car
-          (triples--select db subject 'base/type nil nil '(object))))
+          (triples-db-select db subject 'base/type nil nil '(object))))
 
 (defun triples-get-subject (db subject)
   "From DB return all properties for SUBJECT as a single plist."
@@ -475,19 +475,19 @@ TYPE-VALS-CONS is a list of conses, combining a type and 
a plist of values."
 
 (defun triples-delete-subject (db subject)
   "Delete all data in DB associated with SUBJECT."
-  (triples--delete db subject))
+  (triples-db-delete db subject))
 
 (defun triples-search (db cpred text)
   "Search DB for instances of combined property CPRED with TEXT."
-  (triples--select-predicate-object-fragment db cpred text))
+  (triples-db-select-predicate-object-fragment db cpred text))
 
 (defun triples-with-predicate (db cpred)
   "Return all triples in DB with CPRED as its combined predicate."
-  (triples--select db nil cpred))
+  (triples-db-select db nil cpred))
 
 (defun triples-subjects-with-predicate-object (db cpred obj)
   "Return all subjects in DB with CPRED equal to OBJ."
-  (triples--select db nil cpred obj))
+  (triples-db-select db nil cpred obj))
 
 (defun triples-subjects-of-type (db type)
   "Return a list of all subjects with a particular TYPE in DB."



reply via email to

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