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

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

[elpa] externals/triples fb63dfe44a 12/19: Convert to sqlite.


From: ELPA Syncer
Subject: [elpa] externals/triples fb63dfe44a 12/19: Convert to sqlite.
Date: Sat, 5 Nov 2022 11:58:16 -0400 (EDT)

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

    Convert to sqlite.
    
    Change not yet finalized, this doesn't yet work.
---
 triples-test.el |  13 +++---
 triples.el      | 129 +++++++++++++++++++++++++++++++++-----------------------
 2 files changed, 83 insertions(+), 59 deletions(-)

diff --git a/triples-test.el b/triples-test.el
index d94c1e54ec..2844dccf96 100644
--- a/triples-test.el
+++ b/triples-test.el
@@ -16,7 +16,8 @@ easily debug into it.")
          (progn 
            (let ((db (triples-connect db-file)))
              (setq triples-test-db-file db-file)
-             ,@body))
+             ,@body
+             (triples-close db)))
        (delete-file db-file))))
 
 (defun triples-test-connect-db ()
@@ -188,14 +189,12 @@ easily debug into it.")
     (triples-add-schema db 'marker)
     (triples-set-type db "foo" 'marker)
     (should (equal '((1))
-                (emacsql db [:select (funcall count) :from triples :where (= 
subject $s1)
-                             :and (= predicate 'base/type) :and (= object 
'marker)]
-                         "foo")))
+                   (sqlite-select db "COUNT(*) FROM triples WHERE subject = ? 
AND predicate = 'base/type' AND object = 'marker'"
+                                  (triples-standardize-val "foo"))))
     (triples-set-type db "foo" 'marker)
     (should (equal '((1))
-                (emacsql db [:select (funcall count) :from triples :where (= 
subject $s1)
-                             :and (= predicate 'base/type) :and (= object 
'marker)]
-                         "foo")))))
+                   (sqlite-select db "COUNT(*) FROM triples WHERE subject = ? 
AND predicate = 'base/type' AND object = 'marker'"
+                                  (triples-standardize-val "foo"))))))
 
 (ert-deftest triples-readme ()
   (triples-test-with-temp-db
diff --git a/triples.el b/triples.el
index 1e52471490..bf9403d9ea 100644
--- a/triples.el
+++ b/triples.el
@@ -4,7 +4,7 @@
 
 ;; Author: Andrew Hyatt <ahyatt@gmail.com>
 ;; Homepage: https://github.com/ahyatt/triples
-;; Package-Requires: ((emacsql "3.0.0") cl-lib (seq "2.0"))
+;; Package-Requires: ((seq "2.0") (emacs29))
 ;; Keywords: triples, kg, data, sqlite
 ;; Version: 0.0
 ;; This program is free software; you can redistribute it and/or
@@ -27,29 +27,24 @@
 ;; provide an API offering two-way links between all information stored.
 
 (require 'cl-macs)
-(require 'emacsql)
 (require 'seq)
 
 ;;; Code:
 
 (defun triples-connect (file)
   "Connect to the database FILE and make sure it is populated."
-  (let* ((db (emacsql-sqlite3 file))
-         (triple-table-exists
-          (emacsql db [:select name
-                       :from sqlite_master
-                       :where (= type table) :and (= name 'triples)])))
-    (unless triple-table-exists
-      (emacsql db [:create-table triples ([(subject text :not-null)
-                                               (predicate text :not-null)
-                                               (object :not-null)
-                                               (properties)])])
-      (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]])
-      (emacsql db [:create-unique-index 
subject_predicate_object_properties_idx :on triples [subject predicate object 
properties]]))
+  (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 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)")
+    (sqlite-execute db "CREATE INDEX IF NOT EXISTS 
subject_predicate_object_properties_idx ON triples (subject, predicate, object, 
properties)")
     db))
 
+(defun triples-close (db)
+  "Close sqlite database DB."
+  (sqlite-close db))
+
 (defun triples--ensure-property-val (vec)
   "Return a VEC has 4 elements.
 We add a bogus value as a property because we want to be able
@@ -81,52 +76,62 @@ values."
   "Add a colon to SYM."
   (intern (format ":%s" sym)))
 
+(defun triples-standardize-val (val)
+  "If VAL is a string, return it as enclosed in quotes
+This is done to have compatibility with the way emacsql stores
+values."
+  (if (stringp val)
+      (format "\"%s\"" val)
+    val))
+
 (defun triples--add (db op)
   "Perform OP on DB."
   (pcase (car op)
       ('replace-subject
        (mapc
         (lambda (sub)
-          (emacsql db [:delete :from triples :where (= subject $s1)] sub))
+          (sqlite-execute db "DELETE FROM TRIPLES WHERE subject = ?"
+                          (list (triples-standardize-val 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)
-                         (emacsql db [:delete :from triples :where (= subject 
$s1)
-                                      :and (like predicate $r2)]
-                                  (car sub-triples) (format "%s/%%" type))))
+                         (sqlite-execute db "DELETE FROM TRIPLES WHERE SUBJECT 
= ? AND PREDICATE LIKE ?"
+                                         (list (triples-standardize-val (car 
sub-triples))
+                                               (format "%s/%%" 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)
-            (emacsql db [:replace :into triples
-                         :values $v1] (triples--ensure-property-val
-                                       (apply #'vector triple))))
+  (mapc (lambda (triple)
+          (sqlite-execute db "REPLACE INTO TRIPLES VALUES (?, ?, ?, ?)"
+                          (triples--ensure-property-val
+                           (apply #'vector (mapcar #'triples-standardize-val 
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)))
-          (emacsql db [:select * :from triples :where (= subject $s1)] cpred)))
+          (sqlite-select db "SELECT * FROM TRIPLES WHERE subject = ?"
+                         (list (triples-standardize-val cpred)))))
 
 (defun triples-predicates-for-type (db type)
   "Return all predicates defined for TYPE in DB."
   (mapcar #'car
-          (emacsql db [:select object :from triples :where (= subject $s1)
-                       :and (= predicate 'schema/property)] type)))
+          (sqlite-select db "SELECT object FROM triples WHERE subject = ? AND 
predicate = 'schema/property'"
+                         (list (triples-standardize-val type)))))
 
 (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)
-                        (emacsql db [:select * :from triples :where (= subject 
$s1)
-                                     :and (= predicate 'schema/property) :and 
(= object $s2)]
-                                 type prop))
+                        (sqlite-select db "SELECT * FROM triples WHERE subject 
= ? AND predicate = 'schema/property'
+AND object = ?"
+                                       (list (triples-standardize-val type) 
(triples-standardize-val prop))))
               (error "Property %s not found in schema" (nth 1 triple)))))
         triples)
   (mapc (lambda (triple)
@@ -170,6 +175,19 @@ PROPERTIES is a plist of properties, without TYPE 
prefixes."
     (triples-verify-schema-compliant db (cdr op))
     (triples--add db op)))
 
+(defmacro triples-with-transaction (db &rest body)
+  "Create a transaction using DB, executing BODY.
+The transaction will abort if an error is thrown."
+  (declare (indent 0) (debug t))
+  (let ((db-var (gensym "db")))
+    `(condition-case
+         (let ((,db-var ,db))
+           (progn
+             (sqlite-transaction ,db-var)
+             ,@body
+             (sqlite-commit ,db-var)))
+         (error (sqlite-rollback ,db-var)))))
+
 (defun triples-set-types (db subject &rest combined-props)
   "Set all data for types in COMBINED-PROPS in DB for SUBJECT.
 COMBINED-PROPS is a plist which takes combined properties such as
@@ -183,7 +201,7 @@ given in the COMBINED-PROPS will be removed."
                   (plist-put (gethash (triples--decolon type) type-to-plist)
                              (triples--encolon prop) val) type-to-plist)))
      combined-props)
-    (emacsql-with-transaction db
+    (triples-with-transaction db
       (cl-loop for k being the hash-keys of type-to-plist using (hash-values v)
                do (apply #'triples-set-type db subject k v)))))
 
@@ -212,8 +230,9 @@ 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))
-          (emacsql db [:select * :from triples :where (= subject $s1)
-                       :and (like predicate $r2)] subject (format "%s/%%" 
type)))
+          (sqlite-select db "SELECT * FROM triples WHERE subject = ? AND 
predicate LIKE ?"
+                         (list (triples-standardize-val subject)
+                               (format "%s/%%" 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)))
@@ -230,23 +249,27 @@ PROPERTIES is a plist of properties, without TYPE 
prefixes."
                                      db (triples-type-and-prop-to-combined 
type pred))
                                     :base/virtual-reversed)))
                 (when reversed-prop
-                  (let ((result (emacsql db [:select subject :from triples 
:where (= object $s1)
-                                             :and (= predicate $s2)] subject 
reversed-prop)))
+                  (let ((result
+                         (sqlite-select db "SELECT subject FROM triples WHERE 
object = ? AND predicate = ?"
+                                        (triples-standardize-val (subject))
+                                        reversed-prop)))
                     (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."
-  (emacsql-with-transaction db
-    (emacsql db [:delete :from triples :where (= subject $s1)
-                 :and (= predicate 'base/type)] subject)
-    (emacsql db [:delete :from triples :where (= subject $s1)
-                 :and (like $r2)] subject (format "%s/%%" type))))
+  (triples-with-transaction
+    db
+    (sqlite-execute db "DELETE FROM TRIPLES WHERE subject = ? AND PREDICATE = 
'base/type' AND object = ?"
+                    (list (triples-standardize-val subject) type))
+    (sqlite-execute db "DELETE FROM TRIPLES WHERE subject = ? AND PREDICATE 
LIKE ?"
+                    (list (triples-standardize-val subject)
+                          (format "%s/%%" type)))))
 
 (defun triples-get-types (db subject)
   "From DB, get all types for SUBJECT."
-  (mapcar #'car (emacsql db [:select object :from triples :where (= subject 
$s1)
-                             :and (= predicate 'base/type)]
-                         subject)))
+  (mapcar #'car
+          (sqlite-select db "SELECT object FROM triples WHERE subject = ? AND 
predicate = 'base/type'"
+                         (list (triples-standardize-val subject)))))
 
 (defun triples-get-subject (db subject)
   "From DB return all properties for SUBJECT as a single plist."
@@ -260,7 +283,7 @@ PROPERTIES is a plist of properties, without TYPE prefixes."
 (defun triples-set-subject (db subject &rest type-vals-cons)
   "From DB set properties of SUBJECT to TYPE-VALS-CONS data.
 TYPE-VALS-CONS is a list of conses, combining a type and a plist of values."
-  (emacsql-with-transaction db
+  (triples-with-transaction db
     (triples-delete-subject db subject)
     (mapc (lambda (cons)
             (apply #'triples-set-type db subject cons))
@@ -268,23 +291,25 @@ 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."
-  (emacsql-with-transaction db
-    (emacsql db [:delete :from triples :where (= subject $s1)] subject)))
+  (sqlite-execute db "DELETE FROM triples WHERE SUBJECT = ?"
+                  (list (triples-standardize-val subject))))
 
 (defun triples-search (db cpred text)
   "Search DB for instances of combined property CPRED with TEXT."
-  (emacsql db [:select * :from triples :where (= predicate $i1)
-               :and (like object $r2)] (triples--decolon cpred)
-                       (format "%%%s%%" text)))
+  (sqlite-select db "SELECT * FROM triples WHERE predicate = ? AND object LIKE 
?"
+                 (list (triples--decolon cpred)
+                       (format "%%%s%%" text))))
 
 (defun triples-with-predicate (db cpred)
   "Return all triples in DB with CPRED as its combined predicate."
-  (emacsql db [:select * :from triples :where (= predicate $i1)] 
(triples--decolon cpred)))
+  (sqlite-select db "SELECT * FROM triples WHERE predicate = ?"
+                 (list (triples--decolon cpred))))
 
 (defun triples-subjects-with-predicate-object (db cpred obj)
   "Return all subjects in DB with CPRED equal to OBJ."
-  (emacsql db [:select subject :from triples :where (= predicate $i1) :and (= 
object $s2)]
-           (triples--decolon cpred) obj))
+  (sqlite-select db "SELECT subject FROM triples WHERE predicate = ? AND 
object = ?"
+                 (list (triples--decolon cpred)
+                       (triples-standardize-val 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]