Skip to content

Commit 54053be

Browse files
committed
Merge pull request #7 from thegeez/transact-fns
Add transaction functions
2 parents 8e08c02 + 28ea7ad commit 54053be

File tree

4 files changed

+64
-15
lines changed

4 files changed

+64
-15
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# WIP
2+
3+
- Transactor functions via :db.fn/call
4+
15
# 0.1.3
26

37
- `entity` added

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,13 @@ Interface differences:
119119
* Custom query functions and aggregates should be passed as source instead of being referenced by symbol (due to lack of `resolve` in CLJS)
120120
* Conn is just an atom storing last DB value, use `@conn` instead of `(d/db conn)`
121121
* Instead of `#db/id[:db.part/user -100]` just use `-100` in place of `:db/id` or entity id
122+
* Transactor functions can be called as `[:db.fn/call f args]` where `f` is a function reference and will take db as first argument
123+
* Additional `:db.fn/retractAttribute` shortcut
122124

123125
Expected soon:
124126

125127
* Better error reporting
128+
* Support for components in schema
126129
* Direct access to indexes
127130
* Passing DB to rule
128131
* Moar speed
@@ -136,7 +139,6 @@ Expected soon:
136139
* Any value can be used as entity id, attribute or value. It’s better if they are immutable and fast to compare
137140
* No `db/ident` attributes, keywords are _literally_ attribute values, no integer id behind them
138141
* AV index for all datoms
139-
* No transactor functions besides `:db.fn/retractEntity` and `:db.fn/retractAttribute`
140142
* No schema migrations
141143
* No history support, though history can be implemented on top of immutable DB values
142144
* No cache segments management, no laziness. Entire DB must reside in memory

src/datascript.cljs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@
8181
vs
8282
[vs])]
8383
[:db/add eid a v]))
84-
[entity]))
84+
(if (= (first entity) :db.fn/call)
85+
(let [[_ f & args] entity]
86+
(mapcat #(entity->ops db %) (apply f db args)))
87+
[entity])))
8588

8689
(defn- op->tx-data [db [op e a v]]
8790
(let [tx (inc (.-max-tx db))]
@@ -372,20 +375,29 @@
372375
db-before (atom nil)
373376
tx-data (atom nil)
374377
tempids (atom nil)
378+
error (atom nil)
375379
db-after (swap! conn (fn [db]
376-
(let [raw-datoms (mapcat #(entity->tx-data db %) entities)
377-
datoms (map #(resolve-eid db %) raw-datoms)]
378-
(reset! db-before db)
379-
(reset! tx-data datoms)
380-
(reset! tempids (->> raw-datoms
381-
(filter #(neg? (.-e %)))
382-
(map #(vector (.-e %) (-resolve-eid (.-e %) db)))
383-
(into {})))
384-
(-with db datoms))))
385-
report (TxReport. @db-before db-after @tx-data)]
386-
(doseq [[_ l] @(:listeners meta)]
387-
(l report))
388-
(assoc report :tempids @tempids)))
380+
(let [raw-datoms (try (mapcat #(entity->tx-data db %) entities)
381+
(catch js/Object e
382+
(reset! error e)))
383+
]
384+
(if @error
385+
db
386+
(let [datoms (map #(resolve-eid db %) raw-datoms)]
387+
(reset! db-before db)
388+
(reset! tx-data datoms)
389+
(reset! tempids (->> raw-datoms
390+
(filter #(neg? (.-e %)))
391+
(map #(vector (.-e %) (-resolve-eid (.-e %) db)))
392+
(into {})))
393+
(-with db datoms)))
394+
)))]
395+
(if-let [e @error]
396+
(throw e)
397+
(let [report (TxReport. @db-before db-after @tx-data)]
398+
(doseq [[_ l] @(:listeners meta)]
399+
(l report))
400+
(assoc report :tempids @tempids)))))
389401

390402
(defn listen!
391403
([conn callback] (listen! conn (rand) callback))

test/test/datascript.cljs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,35 @@
8484
:where [1 :aka ?v]] @conn)
8585
#{["Devil"] ["Tupen"]}))))
8686

87+
(deftest test-db-fn
88+
(let [conn (d/create-conn {:aka { :cardinality :many }})
89+
inc-age (fn [db name]
90+
(if-let [[eid age] (first (d/q '{:find [?e ?age]
91+
:in [$ ?name]
92+
:where [[?e :name ?name]
93+
[?e :age ?age]]}
94+
db name))]
95+
[{:db/id eid :age (inc age)} [:db/add eid :had-birthday true]]
96+
(throw (js/Error. (str "No entity with name: " name)))
97+
))]
98+
(d/transact! conn [{:db/id 1 :name "Ivan" :age 31}])
99+
(d/transact! conn [[:db/add 1 :name "Petr"]])
100+
(d/transact! conn [[:db/add 1 :aka "Devil"]])
101+
(d/transact! conn [[:db/add 1 :aka "Tupen"]])
102+
(is (= (d/q '[:find ?v ?a
103+
:where [?e :name ?v]
104+
[?e :age ?a]] @conn)
105+
#{["Petr" 31]}))
106+
(is (= (d/q '[:find ?v
107+
:where [?e :aka ?v]] @conn)
108+
#{["Devil"] ["Tupen"]}))
109+
(is (thrown-with-msg? js/Error #"No entity with name: Bob"
110+
(d/transact! conn [[:db.fn/call inc-age "Bob"]])))
111+
(let [{:keys [db-after]} (d/transact! conn [[:db.fn/call inc-age "Petr"]])
112+
e (d/entity db-after 1)]
113+
(is (= (:age e) 32))
114+
(is (:had-birthday e)))))
115+
87116

88117
(deftest test-resolve-eid
89118
(let [conn (d/create-conn)
@@ -457,6 +486,8 @@
457486
#(reverse (sort %))))
458487
#{[:red [5 4 3 2 1]] [:blue [8 7]]})))))
459488

489+
490+
460491
;; (t/test-ns 'test.datomicscript)
461492

462493
;; Performance

0 commit comments

Comments
 (0)