mentat/test/datomish/db_test.cljc

187 lines
7.7 KiB
Text
Raw Normal View History

2016-07-27 21:29:16 +00:00
;; 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-test
#?(:cljs
(:require-macros
[datomish.pair-chan :refer [go-pair <?]]
[datomish.node-tempfile-macros :refer [with-tempfile]]
[cljs.core.async.macros :as a :refer [go]]))
(:require
[datomish.util :as util #?(:cljs :refer-macros :clj :refer) [raise cond-let]]
[datomish.sqlite :as s]
[datomish.datom]
[datascript.core :as d]
[datascript.db :as db]
[datomish.db :as dm]
#?@(:clj [[datomish.pair-chan :refer [go-pair <?]]
[tempfile.core :refer [tempfile with-tempfile]]
[datomish.test-macros :refer [deftest-async]]
[clojure.test :as t :refer [is are deftest testing]]
[clojure.core.async :refer [go <! >!]]])
#?@(:cljs [[datomish.pair-chan]
[datomish.test-macros :refer-macros [deftest-async]]
[datomish.node-tempfile :refer [tempfile]]
[cljs.test :as t :refer-macros [is are deftest testing async]]
[cljs.core.async :as a :refer [<! >!]]]))
#?(:clj
(:import [clojure.lang ExceptionInfo]))
#?(:clj
(:import [datascript.db DB])))
(defn- <datoms [db]
(let [entids (zipmap (vals (dm/idents db)) (keys (dm/idents db)))]
(go-pair
(->>
(s/all-rows (:sqlite-connection db) ["SELECT e, a, v, tx FROM datoms"])
(<?)
(mapv #(vector (:e %) (entids (:a %)) (:v %)))
(filter #(not (= :db/txInstant (second %))))
(set)))))
(defn- <transactions [db]
(let [entids (zipmap (vals (dm/idents db)) (keys (dm/idents db)))]
(go-pair
(->>
(s/all-rows (:sqlite-connection db) ["SELECT e, a, v, tx, added FROM transactions ORDER BY tx ASC, e, a, v, added"])
(<?)
(mapv #(vector (:e %) (entids (:a %)) (:v %) (:tx %) (:added %)))))))
(defn tx [report]
(get-in report [:db-after :current-tx]))
2016-07-28 00:07:05 +00:00
(def test-schema
{:x {:db/unique :db.unique/identity
:db/valueType :db.type/integer}
:y {:db/cardinality :db.cardinality/many
:db/valueType :db.type/integer}
:name {:db/unique :db.unique/identity
:db/valueType :db.type/string}
:aka {:db/cardinality :db.cardinality/many
:db/valueType :db.type/string}})
2016-07-27 21:29:16 +00:00
(deftest-async test-add-one
(with-tempfile [t (tempfile)]
(let [c (<? (s/<sqlite-connection t))
2016-07-28 00:07:05 +00:00
db (<? (dm/<db-with-sqlite-connection c test-schema))
2016-07-27 21:29:16 +00:00
conn (dm/connection-with-db db)
now 0xdeadbeef]
(try
(let [;; TODO: drop now, allow to set :db/txInstant.
2016-07-28 00:07:05 +00:00
report (<? (dm/<transact! conn [[:db/add 0 :name "valuex"]] now))
2016-07-27 21:29:16 +00:00
tx (tx report)]
(is (= (<? (<datoms (dm/db conn)))
2016-07-28 00:07:05 +00:00
#{[0 :name "valuex"]}))
2016-07-27 21:29:16 +00:00
(is (= (<? (<transactions (dm/db conn)))
2016-07-28 00:07:05 +00:00
[[0 :name "valuex" tx 1] ;; TODO: true, not 1.
2016-07-27 21:29:16 +00:00
[tx :db/txInstant now tx 1]])))
(finally
(<? (dm/close-db db)))))))
(deftest-async test-add-two
(with-tempfile [t (tempfile)]
(let [c (<? (s/<sqlite-connection t))
2016-07-28 00:07:05 +00:00
db (<? (dm/<db-with-sqlite-connection c test-schema))
2016-07-27 21:29:16 +00:00
conn (dm/connection-with-db db)
now 0xdeadbeef]
(try
2016-07-28 00:07:05 +00:00
(let [tx1 (tx (<? (dm/<transact! conn [[:db/add 1 :name "Ivan"]] now)))
tx2 (tx (<? (dm/<transact! conn [[:db/add 1 :name "Petr"]] now)))
tx3 (tx (<? (dm/<transact! conn [[:db/add 1 :aka "Tupen"]] now)))
tx4 (tx (<? (dm/<transact! conn [[:db/add 1 :aka "Devil"]] now)))]
2016-07-27 21:29:16 +00:00
(is (= (<? (<datoms (dm/db conn)))
2016-07-28 00:07:05 +00:00
#{[1 :name "Petr"]
[1 :aka "Tupen"]
[1 :aka "Devil"]}))
2016-07-27 21:29:16 +00:00
(is (= (<? (<transactions (dm/db conn)))
2016-07-28 00:07:05 +00:00
[[1 :name "Ivan" tx1 1] ;; TODO: true, not 1.
2016-07-27 21:29:16 +00:00
[tx1 :db/txInstant now tx1 1]
2016-07-28 00:07:05 +00:00
[1 :name "Ivan" tx2 0]
[1 :name "Petr" tx2 1]
2016-07-27 21:29:16 +00:00
[tx2 :db/txInstant now tx2 1]
2016-07-28 00:07:05 +00:00
[1 :aka "Tupen" tx3 1]
2016-07-27 21:29:16 +00:00
[tx3 :db/txInstant now tx3 1]
2016-07-28 00:07:05 +00:00
[1 :aka "Devil" tx4 1]
2016-07-27 21:29:16 +00:00
[tx4 :db/txInstant now tx4 1]])))
(finally
(<? (dm/close-db db)))))))
;; TODO: fail multiple :add and :retract of the same datom in the same transaction.
(deftest-async test-retract
(with-tempfile [t (tempfile)]
(let [c (<? (s/<sqlite-connection t))
2016-07-28 00:07:05 +00:00
db (<? (dm/<db-with-sqlite-connection c test-schema))
2016-07-27 21:29:16 +00:00
conn (dm/connection-with-db db)
now 0xdeadbeef]
(try
2016-07-28 00:07:05 +00:00
(let [txa (tx (<? (dm/<transact! conn [[:db/add 0 :x 123]] now)))
txb (tx (<? (dm/<transact! conn [[:db/retract 0 :x 123]] now)))]
2016-07-27 21:29:16 +00:00
(is (= (<? (<datoms db))
#{}))
(is (= (<? (<transactions db))
2016-07-28 00:07:05 +00:00
[[0 :x 123 txa 1] ;; TODO: true, not 1.
2016-07-27 21:29:16 +00:00
[txa :db/txInstant now txa 1]
2016-07-28 00:07:05 +00:00
[0 :x 123 txb 0]
2016-07-27 21:29:16 +00:00
[txb :db/txInstant now txb 1]])))
(finally
(<? (dm/close-db db)))))))
(deftest-async test-id-literal-1
(with-tempfile [t (tempfile)]
(let [c (<? (s/<sqlite-connection t))
2016-07-28 00:07:05 +00:00
db (<? (dm/<db-with-sqlite-connection c test-schema))
2016-07-27 21:29:16 +00:00
conn (dm/connection-with-db db)
now -1]
(try
(let [report (<? (dm/<transact! conn [[:db/add (dm/id-literal :db.part/user -1) :x 0]
[:db/add (dm/id-literal :db.part/user -1) :y 1]
[:db/add (dm/id-literal :db.part/user -2) :y 2]
[:db/add (dm/id-literal :db.part/user -2) :y 3]] now))]
(is (= (keys (:tempids report)) ;; TODO: include values.
[(dm/id-literal :db.part/user -1)
(dm/id-literal :db.part/user -2)]))
(let [eid1 (get-in report [:tempids (dm/id-literal :db.part/user -1)])
eid2 (get-in report [:tempids (dm/id-literal :db.part/user -2)])]
(is (= (<? (<datoms db))
#{[eid1 :x 0]
[eid1 :y 1]
[eid2 :y 2]
[eid2 :y 3]}))))
(finally
(<? (dm/close-db db)))))))
2016-07-27 21:30:01 +00:00
(deftest-async test-add-ident
(with-tempfile [t (tempfile)]
(let [c (<? (s/<sqlite-connection t))
2016-07-28 00:07:05 +00:00
db (<? (dm/<db-with-sqlite-connection c test-schema))
2016-07-27 21:30:01 +00:00
conn (dm/connection-with-db db)
now -1]
(try
2016-07-28 00:07:05 +00:00
(let [report (<? (dm/<transact! conn [[:db/add (dm/id-literal :db.part/db -1) :db/ident :test/ident]] now))
2016-07-27 21:30:01 +00:00
db-after (:db-after report)
tx (:current-tx db-after)]
2016-07-28 00:07:05 +00:00
(is (= (:test/ident (dm/idents db-after)) (get-in report [:tempids (dm/id-literal :db.part/db -1)]))))
2016-07-27 21:30:01 +00:00
2016-07-28 00:07:05 +00:00
;; TODO: This should fail, but doesn't, due to stringification of :test/ident.
2016-07-27 21:30:01 +00:00
;; (is (thrown-with-msg?
;; ExceptionInfo #"Retracting a :db/ident is not yet supported, got "
2016-07-28 00:07:05 +00:00
;; (<? (dm/<transact! conn [[:db/retract 44 :db/ident :test/ident]] now))))
2016-07-27 21:30:01 +00:00
;; ;; Renaming looks like retraction and then assertion.
;; (is (thrown-with-msg?
;; ExceptionInfo #"Retracting a :db/ident is not yet supported, got"
;; (<? (dm/<transact! conn [[:db/add 44 :db/ident :other-name]] now))))
;; (is (thrown-with-msg?
;; ExceptionInfo #"Re-asserting a :db/ident is not yet supported, got"
2016-07-28 00:07:05 +00:00
;; (<? (dm/<transact! conn [[:db/add 55 :db/ident :test/ident]] now))))
2016-07-27 21:30:01 +00:00
(finally
(<? (dm/close-db db)))))))