Skip to content

Commit

Permalink
Fix for duplicate rows when upgrading from emacsql to builtin
Browse files Browse the repository at this point in the history
This should fix #5.
  • Loading branch information
ahyatt committed Jul 20, 2023
1 parent 01f8c7c commit ddeb338
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 1 deletion.
18 changes: 18 additions & 0 deletions triples-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,24 @@ easily debug into it.")
(triples-close db))
;; Just so the last close will work.
(setq db (triples-connect db-file))))))

(ert-deftest triples-test-emacsql-to-sqlite-dup-fixing ()
(let ((triples-sqlite-interface 'emacsql)
(db-file (make-temp-file "triples-test"))
(db))
(setq triples-test-db-file db-file)
(setq db (triples-connect db-file))
(triples-add-schema db 'person '(name :base/unique t :base/type string))
(triples-set-type db 1 'person :name "Alice Aardvark")
(triples-close db)
(setq triples-sqlite-interface 'builtin)
(setq db (triples-connect db-file))
(triples-set-type db 1 'person :name "Alice Aardvark")
;; Should just be one plist key and value, so two values. However, if we
;; don't fix things up, we get two because there is a dup row.
(should (= 2 (length (triples-get-subject db 1))))
(triples-close db)
(delete-file db-file)))


;; After this we don't bother testing both with emacsql and the builtin sqlite,
Expand Down
21 changes: 20 additions & 1 deletion triples.el
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,23 @@ This is used in upgrades and when problems are detected."
(sqlite-execute db "INSERT INTO triples (subject, predicate, object, properties) SELECT DISTINCT subject, predicate, object, properties FROM triples_old")
(sqlite-execute db "DROP TABLE triples_old")))

(defun triples-maybe-upgrade-to-builtin (db)
"Check to see if DB needs to be upgraded from emacsql to builtin."
;; Check to see if this was previously an emacsql database, and if so,
;; change the property column to be standard for builtin sqlite.
(when (> (caar (sqlite-select db "SELECT COUNT(*) FROM triples WHERE properties = '(:t t)'"))
0)
(if (> (caar (sqlite-select db "SELECT COUNT(*) FROM triples WHERE properties = '()'"))
0)
(progn
(message "triples: detected data written with both builtin and emacsql, upgrading and removing duplicates")
;; Where we can, let's just upgrade the old data. However, sometimes we cannot due to duplicates.
(sqlite-execute db "UPDATE OR IGNORE triples SET properties = '()' WHERE properties = '(:t t)'")
;; Remove any duplicates that we cannot upgrade.
(sqlite-execute db "DELETE FROM triples WHERE properties = '(:t t)'"))
(message "triples: detected previously used emacsql database, converting to builtin sqlite")
(sqlite-execute db "UPDATE triples SET properties = '()' WHERE properties = '(:t t)'"))))

(defun triples-connect (&optional file)
"Connect to the database FILE and make sure it is populated.
If FILE is nil, use `triples-default-database-filename'."
Expand All @@ -76,7 +93,9 @@ If FILE is nil, use `triples-default-database-filename'."
(pcase triples-sqlite-interface
('builtin (let* ((db (sqlite-open file)))
(condition-case nil
(triples-setup-table-for-builtin db)
(progn
(triples-setup-table-for-builtin db)
(triples-maybe-upgrade-to-builtin db))
(error
(message "triples: failed to ensure proper database tables and indexes. Trying an automatic fix.")
(triples-rebuild-builtin-database db)
Expand Down

0 comments on commit ddeb338

Please sign in to comment.