Part 1: Implement database on top of SQLite connection.

We would prefer to talk about a knowledge base on top of a database, but
all the Datomic and DataScript code (and symbols, like :db/add, etc)
refer to the "database of datoms", so let's roll with that nomenclature
and try to be specific that the persistent storage-layer is SQLite.
This will become more clear when we actually use SQLite's unique
capabilities for text indexing.
This commit is contained in:
Nick Alexander 2016-07-12 15:37:26 -07:00
parent 724c37466d
commit c398c4b153
3 changed files with 107 additions and 0 deletions

38
src/datomish/db.cljc Normal file
View file

@ -0,0 +1,38 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
(ns datomish.db
#?(:cljs
(:require-macros
[datomish.pair-chan :refer [go-pair <?]]
[cljs.core.async.macros :refer [go]]))
#?(:clj
(:require
[datomish.sqlite :as s]
[datomish.sqlite-schema :as sqlite-schema]
[datomish.pair-chan :refer [go-pair <?]]
[clojure.core.async :refer [go <! >!]])
:cljs
(:require
[datomish.sqlite :as s]
[datomish.sqlite-schema :as sqlite-schema]
[datomish.pair-chan]
[cljs.core.async :as a :refer [<! >!]])))
(defprotocol IDB
(close
[db]
"Close this database. Returns a pair channel of [nil error]."))
(defrecord DB [sqlite-connection]
IDB
(close [db] (close (.-sqlite-connection db))))
(declare ensure-current-version)
(defn with-sqlite-connection [sqlite-connection]
(go-pair
(when-not (= sqlite-schema/current-version (<? (sqlite-schema/ensure-current-version sqlite-connection)))
(throw (Exception. "badness ensued"))) ;; TODO: raise
(->DB [sqlite-connection])))

View file

@ -68,3 +68,11 @@
[nil e])))
(catch #?(:clj Exception :cljs js/Error) e
[nil e]))))
(defn get-user-version [db]
(go-pair
(let [row (first (<? (all-rows db ["PRAGMA user_version"])))]
(:user_version row))))
(defn set-user-version [db version]
(execute! db [(str "PRAGMA user_version = " version)]))

View file

@ -0,0 +1,61 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
(ns datomish.sqlite-schema
#?(:cljs
(:require-macros
[datomish.pair-chan :refer [go-pair <?]]
[cljs.core.async.macros :refer [go]]))
#?(:clj
(:require
[datomish.sqlite :as s]
[datomish.pair-chan :refer [go-pair <?]]
[clojure.core.async :refer [go <! >!]])
:cljs
(:require
[datomish.sqlite :as s]
[datomish.pair-chan]
[cljs.core.async :as a :refer [<! >!]])))
(def current-version 1)
(def v1-statements
["CREATE TABLE datoms (e INTEGER NOT NULL, a TINYINT NOT NULL, v BLOB NOT NULL, tx INTEGER NOT NULL, index_avet TINYINT NOT NULL DEFAULT 0, index_vaet TINYINT NOT NULL DEFAULT 0)"
"CREATE TABLE transactions (e INTEGER NOT NULL, a TINYINT NOT NULL, v BLOB NOT NULL, tx INTEGER NOT NULL, added TINYINT NOT NULL DEFAULT 1)"
"CREATE INDEX eavt ON datoms (e, a)" ;; No v -- that's an opt-in index.
"CREATE INDEX aevt ON datoms (a, e)" ;; No v -- that's an opt-in index.
"CREATE INDEX avet ON datoms (a, v, e) WHERE index_avet = 1" ;; Opt-in index: only if a has :db/index true.
"CREATE INDEX vaet ON datoms (v, a, e) WHERE index_vaet = 1" ;; Opt-in index: only if a has :db/valueType :db.type/ref
"CREATE INDEX tx ON transactions (tx)"])
(defn create-current-version
[db]
(go-pair
(doseq [statement v1-statements]
(<? (s/execute! db [statement])))
(<? (s/set-user-version db current-version))
(<? (s/get-user-version db))))
(defn update-from-version
[db from-version]
{:pre [(> from-version 0)]} ;; Or we'd create-current-version instead.
{:pre [(< from-version current-version)]} ;; Or we wouldn't need to update-from-version.
(go-pair
(throw (Exception. "No possible migrations!")) ;; TODO: raise.
(<? (s/set-user-version db current-version))
(<? (s/get-user-version db))))
(defn ensure-current-version
[db]
(go-pair
(let [v (<? (s/get-user-version db))]
(cond
(= v current-version)
v
(= v 0)
(<? (create-current-version db))
(< v current-version)
(<? (update-from-version db v))))))