branch: externals/triples
commit aca95ba7f34af4395eae05e4a62b48da3207bd59
Author: Andrew Hyatt <[email protected]>
Commit: Andrew Hyatt <[email protected]>
Ensure that we don't duplicate triples.
Also, remove flakiness in tests caused by changing plist and list ordering.
---
triples-test.el | 72 ++++++++++++++++++++++++++++++++++++---------------------
triples.el | 12 ++++++----
2 files changed, 54 insertions(+), 30 deletions(-)
diff --git a/triples-test.el b/triples-test.el
index f539727cd8..e3172fa42b 100644
--- a/triples-test.el
+++ b/triples-test.el
@@ -1,6 +1,7 @@
;;; triples-test.el --- Tests for triples module.
(require 'triples)
(require 'seq)
+(require 'kv)
;;; Code:
@@ -46,6 +47,10 @@ easily debug into it.")
(named schema/property alternate-names)
(named schema/property nicknames))))))
+(defun triples-test-list-sort (list)
+ "Standard sort for LIST for test stability."
+ (sort list (lambda (a b) (string< (format "%s" a) (format "%s" b))) ))
+
(ert-deftest triples-schema-crud ()
(triples-test-with-temp-db
(triples-add-schema db 'named
@@ -53,8 +58,8 @@ easily debug into it.")
(should (equal '(:base/unique t)
(triples-properties-for-predicate db 'named/name)))
(should (equal
- '(name alternate-names)
- (triples-predicates-for-type db 'named)))))
+ (triples-test-list-sort '(name alternate-names))
+ (triples-test-list-sort (triples-predicates-for-type db
'named))))))
(ert-deftest triples-properties-for-predicate ()
(triples-test-with-temp-db
@@ -88,14 +93,20 @@ easily debug into it.")
(should-error (triples-verify-schema-compliant db '(("foo" named/name
"bar" (:index 0)))))
(should (triples-verify-schema-compliant db '(("foo" named/alternate-names
"bar" (:index 0)))))))
+(defun triples-test-plist-sort (plist)
+ "Sort PLIST in a standard way, for comparison."
+ (kvalist->plist
+ (kvalist-sort (kvplist->alist plist)
+ (lambda (a b) (string< (format "%s" a) (format "%s" b))))))
+
(ert-deftest triples-crud ()
(triples-test-with-temp-db
(triples-add-schema db 'named
'(name :unique t)
'alias)
(triples-set-type db "foo" 'named :name "Name" :alias '("alias1" "alias2"))
- (should (equal '(:name "Name" :alias ("alias1" "alias2"))
- (triples-get-type db "foo" 'named)))
+ (should (equal (triples-test-plist-sort '(:name "Name" :alias ("alias1"
"alias2")))
+ (triples-test-plist-sort (triples-get-type db "foo"
'named))))
(should (equal (triples-get-types db "foo") '(named)))
(should-not (triples-get-type db "bar" 'named))
(should-not (triples-get-types db "bar"))
@@ -138,16 +149,6 @@ easily debug into it.")
(triples-get-type db "en/US" 'locale)))
(should-error (triples-set-type db "en/US" 'locale :used-in-name
'("bar")))))
-(ert-deftest triples-with-preciate-object ()
- (triples-test-with-temp-db
- (triples-add-schema db 'named '(name))
- (should-not (triples-search db 'named/name "Fred"))
- (triples-set-type db "foo" 'named :name "My Name Is Fred Foo")
- (triples-set-type db "bar" 'named :name "My Name Is Betty Bar")
- (should (equal
- '(("foo" named/name "My Name Is Fred Foo" nil))
- (triples-search db 'named/name "Fred")))))
-
(ert-deftest triples-with-predicate ()
(triples-test-with-temp-db
(triples-add-schema db 'named '(name))
@@ -163,12 +164,27 @@ easily debug into it.")
(ert-deftest triples-subjects-of-type ()
(triples-test-with-temp-db
- (triples-add-schema db 'named '(name))
- (should-not (triples-subjects-of-type db 'named))
- (triples-set-type db "foo" 'named :name "My Name Is Fred Foo")
- (triples-set-type db "bar" 'named :name "My Name Is Betty Bar")
- (should (seq-set-equal-p '("foo" "bar")
- (triples-subjects-of-type db 'named)))))
+ (triples-add-schema db 'named '(name))
+ (should-not (triples-subjects-of-type db 'named))
+ (triples-set-type db "foo" 'named :name "My Name Is Fred Foo")
+ (triples-set-type db "bar" 'named :name "My Name Is Betty Bar")
+ (should (seq-set-equal-p '("foo" "bar")
+ (triples-subjects-of-type db 'named)))))
+
+(ert-deftest triples-no-dups ()
+ (triples-test-with-temp-db
+ ;; Just add a marker schema, no attributes
+ (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")))
+ (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")))))
(ert-deftest triples-readme ()
(triples-test-with-temp-db
@@ -185,14 +201,18 @@ easily debug into it.")
(triples-delete-subject db "alice")
(triples-set-type db "alice" 'person :name "Alice Aardvark" :age 41)
(triples-set-type db "alice" 'employee :id 1901 :manager "bob")
- (should (equal (triples-get-subject db "alice")
- '(:person/name "Alice Aardvark" :person/age 41 :employee/id
1901
- :employee/manager "bob" :employee/reportees
("catherine" "dennis"))))
+ (should (equal (triples-test-plist-sort (triples-get-subject db "alice"))
+ (triples-test-plist-sort '(:person/name "Alice Aardvark"
:person/age 41
+ :employee/id 1901
+ :employee/manager
"bob"
+ :employee/reportees
("catherine" "dennis")))))
(triples-set-subject db "alice" '(person :name "Alice Aardvark" :age 41)
'(employee :id 1901 :manager "bob"))
- (should (equal (triples-get-subject db "alice")
- '(:person/name "Alice Aardvark" :person/age 41 :employee/id
1901
- :employee/manager "bob" :employee/reportees
("catherine" "dennis"))))))
+ (should (equal (triples-test-plist-sort (triples-get-subject db "alice"))
+ (triples-test-plist-sort '(:person/name "Alice Aardvark"
:person/age 41
+ :employee/id 1901
+ :employee/manager
"bob"
+ :employee/reportees
("catherine" "dennis")))))))
(provide 'triples-test)
diff --git a/triples.el b/triples.el
index 66d2c994b7..a26c29a874 100644
--- a/triples.el
+++ b/triples.el
@@ -44,14 +44,18 @@
(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-index predicate_object_idx :on triples [predicate
object]])
+ (emacsql db [:create-unique-index
subject_predicate_object_properties_idx :on triples [subject predicate object
properties]]))
db))
(defun triples--ensure-property-val (vec)
- "Return a VEC has 4 elements."
+ "Return a VEC has 4 elements.
+We add a bogus value as a property because we want to be able
+to enforce unique constraints, which sqlite will not do will NULL
+values."
(if (= (length vec) 4)
vec
- (vconcat vec '(nil))))
+ (vconcat vec '((:empty t)))))
(defun triples--subjects (triples)
"Return all unique subjects in TRIPLES."
@@ -96,7 +100,7 @@
(mapcar #'cl-second (cdr
sub-triples)))))))
(triples--group-by-subjects (cdr op)))))
(mapc (lambda (triple)
- (emacsql db [:insert :into triples
+ (emacsql db [:replace :into triples
:values $v1] (triples--ensure-property-val
(apply #'vector triple))))
(cdr op)))