From 7a90c43a5a8411a23c9d889dd4a221965a29d0ce Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Wed, 27 Jul 2016 21:15:57 -0700 Subject: [PATCH] Map valueTypes to SQLite encodings. In the future, we might add a layer of indirection, hashing values to avoid duplicating storage, or sorting URLs, or handling fulltext indexed values differently, or ... --- src/datomish/db.cljc | 69 +++++++++++++++++++++----------------- src/datomish/schema.cljc | 27 ++++++++++++++- test/datomish/db_test.cljc | 32 ++++++++++++++++++ 3 files changed, 96 insertions(+), 32 deletions(-) diff --git a/src/datomish/db.cljc b/src/datomish/db.cljc index 85f11740..d9dc9ee6 100644 --- a/src/datomish/db.cljc +++ b/src/datomish/db.cljc @@ -70,14 +70,14 @@ [db] "TODO: document this interface.")) -;; TODO: handle _? -(defn search->sql-clause [pattern] - (merge - {:select [:*] ;; e :a :v :tx] ;; TODO: generalize columns. - :from [:datoms]} - (if-not (empty? pattern) - {:where (cons :and (map #(vector := %1 (if (keyword? %2) (str %2) %2)) [:e :a :v :tx] pattern))} ;; TODO: use schema to process v. - {}))) +(defn db? [x] + (and (satisfies? IDB x))) + +(defn- row->Datom [schema row] + (let [e (:e row) + a (:a row) + v (:v row)] + (Datom. e a (ds/<-SQLite schema a v) (:tx row) (:added row)))) (defrecord DB [sqlite-connection schema idents current-tx] ;; idents is map {ident -> entid} of known idents. See http://docs.datomic.com/identity.html#idents. @@ -94,33 +94,43 @@ ;; TODO: use q for searching? Have q use this for searching for a single pattern? (> - (search->sql-clause pattern) - (sql/format) - (s/all-rows (:sqlite-connection db))))] - (mapv #(Datom. (:e %) (:a %) (:v %) (:tx %) true) rows)))) ;; TODO: map values according to schema. + (let [[e a v tx] pattern + v (and v (ds/->SQLite schema a v))] ;; We assume e and a are always given. + (go-pair + (->> + {:select [:*] ;; e :a :v :tx] ;; TODO: generalize columns. + :from [:datoms] + :where (cons :and (map #(vector := %1 %2) [:e :a :v :tx] (take-while (comp not nil?) [e a v tx])))} ;; Must drop nils. + (sql/format) + + (s/all-rows (:sqlite-connection db)) + (Datom (.-schema db))))))) ;; TODO: understand why (schema db) fails. (> - {:select [:*] :from [:datoms] :where [:and [:= :a a] [:= :v v]]} - (sql/format) - (s/all-rows (:sqlite-connection db))))] - (mapv #(Datom. (:e %) (:a %) (:v %) (:tx %) true) rows)))) ;; TODO: map values according to schema. + (let [[a v] pattern + v (ds/->SQLite schema a v)] + (go-pair + (->> + {:select [:*] :from [:datoms] :where [:and [:= :a a] [:= :v v]]} + (sql/format) + + (s/all-rows (:sqlite-connection db)) + (Datom (.-schema db))))))) ;; TODO: understand why (schema db) fails. (SQLite (.-schema db) a v)] ;; TODO: understand why (schema db) fails. ;; Append to transaction log. (> - {:select [:e :v] :from [:datoms] :where [:= :a ":db/ident"]} ;; TODO: don't stringify? + {:select [:e :v] :from [:datoms] :where [:= :a ":db/ident"]} ;; TODO: use raw entid. (sql/format) (s/all-rows sqlite-connection)))] (into {} (map #(-> {(keyword (:v %)) (:e %)})) rows)))) @@ -228,7 +235,7 @@ (go-pair (when-not (= sqlite-schema/current-version (DB {:sqlite-connection sqlite-connection :idents idents @@ -365,7 +372,7 @@ (vec (for [[op & entity] (:entities report)] (into [op] (for [field entity] (if (lookup-ref? field) - (first (SQLite identity :<-SQLite identity } - :db.type/keyword { :valid? keyword? :->SQLite name :<-SQLite keyword } + :db.type/keyword { :valid? keyword? :->SQLite str :<-SQLite #(keyword (subs % 1)) } :db.type/string { :valid? string? :->SQLite identity :<-SQLite identity } :db.type/boolean { :valid? #(instance? Boolean %) :->SQLite #(if % 1 0) :<-SQLite #(if (= % 1) true false) } :db.type/integer { :valid? integer? :->SQLite identity :<-SQLite identity } @@ -104,6 +104,31 @@ (raise "Unknown attribute " attr ", expected one of " (sorted-set (keys schema)) {:error :schema/valueType, :attribute attr})))) +(defn ->SQLite [schema attr value] + {:pre [(schema? schema)]} + (let [schema (.-schema schema)] + (if-let [valueType (get-in schema [attr :db/valueType])] + (if-let [valid? (get-in value-type-map [valueType :valid?])] + (if (valid? value) + ((get-in value-type-map [valueType :->SQLite]) value) + (raise "Invalid value for attribute " attr ", expected " valueType " but got " value + {:error :schema/valueType, :attribute attr, :value value})) + (raise "Unknown valueType for attribute " attr ", expected one of " (sorted-set (keys value-type-map)) + {:error :schema/valueType, :attribute attr})) + (raise "Unknown attribute " attr ", expected one of " (sorted-set (keys schema)) + {:error :schema/valueType, :attribute attr})))) + +(defn <-SQLite [schema attr value] + {:pre [(schema? schema)]} + (let [schema (.-schema schema)] + (if-let [valueType (get-in schema [attr :db/valueType])] + (if-let [<-SQLite (get-in value-type-map [valueType :<-SQLite])] + (<-SQLite value) + (raise "Unknown valueType for attribute " attr ", expected one of " (sorted-set (keys value-type-map)) + {:error :schema/valueType, :attribute attr})) + (raise "Unknown attribute " attr ", expected one of " (sorted-set (keys schema)) + {:error :schema/valueType, :attribute attr})))) + (defn- validate-schema [schema] (doseq [[a kv] schema] (when-not (:db/valueType kv) diff --git a/test/datomish/db_test.cljc b/test/datomish/db_test.cljc index 63dc8b47..7ec2d5ee 100644 --- a/test/datomish/db_test.cljc +++ b/test/datomish/db_test.cljc @@ -184,3 +184,35 @@ (finally (