Skip to content

Commit e022a09

Browse files
committed
Fixed upsert incorectly failing tempid check (closes #363)
1 parent 62130f8 commit e022a09

3 files changed

Lines changed: 67 additions & 33 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# WIP
2+
3+
- Fixed upsert incorectly failing tempid check #363
4+
15
# 1.0.0
26

37
- Support composite tuples #323

src/datascript/db.cljc

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,9 @@
438438
(defprotocol ISearch
439439
(-search [data pattern]))
440440

441+
(defn- ^Datom fsearch [data pattern]
442+
(first (-search data pattern)))
443+
441444
(defprotocol IIndexAccess
442445
(-datoms [db index components])
443446
(-seek-datoms [db index components])
@@ -1018,7 +1021,7 @@
10181021
indexing? (update :avet set/conj datom cmp-datoms-avet-quick)
10191022
true (advance-max-eid (.-e datom))
10201023
true (assoc :hash (atom 0)))
1021-
(if-some [removing (first (-search db [(.-e datom) (.-a datom) (.-v datom)]))]
1024+
(if-some [removing (fsearch db [(.-e datom) (.-a datom) (.-v datom)])]
10221025
(cond-> db
10231026
true (update :eavt set/disj removing cmp-datoms-eavt-quick)
10241027
true (update :aevt set/disj removing cmp-datoms-aevt-quick)
@@ -1204,18 +1207,22 @@
12041207
db (:db-after report)
12051208
e (entid-strict db e)
12061209
v (if (ref? db a) (entid-strict db v) v)
1207-
new-datom (datom e a v tx)]
1208-
(if (multival? db a)
1209-
(if (empty? (-search db [e a v]))
1210+
new-datom (datom e a v tx)
1211+
multival? (multival? db a)
1212+
old-datom ^Datom (if multival?
1213+
(fsearch db [e a v])
1214+
(fsearch db [e a]))]
1215+
(cond
1216+
(nil? old-datom)
12101217
(transact-report report new-datom)
1211-
report)
1212-
(if-some [^Datom old-datom (first (-search db [e a]))]
1213-
(if (= (.-v old-datom) v)
1214-
report
1215-
(-> report
1216-
(transact-report (datom e a (.-v old-datom) tx false))
1217-
(transact-report new-datom)))
1218-
(transact-report report new-datom)))))
1218+
1219+
(= (.-v old-datom) v)
1220+
(update report ::tx-redundant conjv new-datom)
1221+
1222+
:else
1223+
(-> report
1224+
(transact-report (datom e a (.-v old-datom) tx false))
1225+
(transact-report new-datom)))))
12191226

12201227
(defn- transact-retract-datom [report ^Datom d]
12211228
(let [tx (current-tx report)]
@@ -1232,7 +1239,7 @@
12321239
(if (contains? (:tempids initial-report) tempid)
12331240
(raise "Conflicting upsert: " tempid " resolves"
12341241
" both to " upserted-eid " and " (get-in initial-report [:tempids tempid])
1235-
{ :error :transact/upsert })
1242+
{:error :transact/upsert})
12361243
;; try to re-run from the beginning
12371244
;; but remembering that `tempid` will resolve to `upserted-eid`
12381245
(let [tempids' (-> (:tempids report)
@@ -1275,9 +1282,9 @@
12751282
(if (datom-added datom)
12761283
(dissoc tempids (:e datom))
12771284
tempids))
1278-
unused (reduce reduce-fn all-tempids (:tx-data report))]
1285+
unused (reduce reduce-fn all-tempids (concat (:tx-data report) (::tx-redundant report)))]
12791286
(if (empty? unused)
1280-
(dissoc report ::value-tempids)
1287+
(dissoc report ::value-tempids ::tx-redundant)
12811288
(raise "Tempids used only as value in transaction: " (sort (vals unused))
12821289
{:error :transact/syntax, :tempids unused}))))
12831290

@@ -1377,7 +1384,7 @@
13771384
(and (keyword? op)
13781385
(not (builtin-fn? op)))
13791386
(if-some [ident (entid db op)]
1380-
(let [fun (-> (-search db [ident :db/fn]) first :v)
1387+
(let [fun (:v (fsearch db [ident :db/fn]))
13811388
args (next entity)]
13821389
(if (fn? fun)
13831390
(recur report (concat (apply fun db args) entities))
@@ -1441,7 +1448,6 @@
14411448
(raise "Can’t modify tuple attrs directly: " entity
14421449
{:error :transact/syntax, :tx-data entity})
14431450

1444-
14451451
(= op :db/add)
14461452
(recur (transact-add report entity) entities)
14471453

@@ -1450,7 +1456,7 @@
14501456
(let [v (if (ref? db a) (entid-strict db v) v)]
14511457
(validate-attr a entity)
14521458
(validate-val v entity)
1453-
(if-some [old-datom (first (-search db [e a v]))]
1459+
(if-some [old-datom (fsearch db [e a v])]
14541460
(recur (transact-retract-datom report old-datom) entities)
14551461
(recur report entities)))
14561462
(recur report entities))

test/datascript/test/transact.cljc

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -249,21 +249,45 @@
249249
(is (:had-birthday e)))))
250250

251251
(deftest test-resolve-eid
252-
(let [conn (d/create-conn)
253-
t1 (d/transact! conn [[:db/add -1 :name "Ivan"]
254-
[:db/add -1 :age 19]
255-
[:db/add -2 :name "Petr"]
256-
[:db/add -2 :age 22]])
257-
t2 (d/transact! conn [[:db/add "Serg" :name "Sergey"]
258-
[:db/add "Serg" :age 30]])]
259-
(is (= (:tempids t1) { -1 1, -2 2, :db/current-tx (+ d/tx0 1) }))
260-
(is (= (:tempids t2) { "Serg" 3, :db/current-tx (+ d/tx0 2) }))
261-
(is (= #{[1 "Ivan" 19 (+ d/tx0 1)]
262-
[2 "Petr" 22 (+ d/tx0 1)]
263-
[3 "Sergey" 30 (+ d/tx0 2)]}
264-
(d/q '[:find ?e ?n ?a ?t
265-
:where [?e :name ?n ?t]
266-
[?e :age ?a]] @conn)))))
252+
(let [db (d/empty-db {:name {:db/unique :db.unique/identity}
253+
:aka {:db/unique :db.unique/identity
254+
:db/cardinality :db.cardinality/many}
255+
:ref {:db/valueType :db.type/ref}})]
256+
(let [report (d/with db [[:db/add -1 :name "Ivan"]
257+
[:db/add -1 :age 19]
258+
[:db/add -2 :name "Petr"]
259+
[:db/add -2 :age 22]
260+
[:db/add "Serg" :name "Sergey"]
261+
[:db/add "Serg" :age 30]])]
262+
(is (= (:tempids report)
263+
{-1 1
264+
-2 2
265+
"Serg" 3
266+
:db/current-tx (+ d/tx0 1) }))
267+
(is (= #{[1 :name "Ivan"]
268+
[1 :age 19]
269+
[2 :name "Petr"]
270+
[2 :age 22]
271+
[3 :name "Sergey"]
272+
[3 :age 30]}
273+
(tdc/all-datoms (:db-after report)))))
274+
275+
(let [db' (d/db-with db [[:db/add -1 :name "Ivan"]
276+
[:db/add -2 :ref -1]])]
277+
(is (= #{[1 :name "Ivan"] [2 :ref 1]}
278+
(tdc/all-datoms db'))))
279+
280+
(testing "#363"
281+
(let [db' (-> db
282+
(d/db-with [[:db/add -1 :name "Ivan"]])
283+
(d/db-with [[:db/add -1 :name "Ivan"]
284+
[:db/add -2 :ref -1]]))]
285+
(is (= #{[1 :name "Ivan"] [2 :ref 1]} (tdc/all-datoms db'))))
286+
(let [db' (-> db
287+
(d/db-with [[:db/add -1 :aka "Batman"]])
288+
(d/db-with [[:db/add -1 :aka "Batman"]
289+
[:db/add -2 :ref -1]]))]
290+
(is (= #{[1 :aka "Batman"] [2 :ref 1]} (tdc/all-datoms db')))))))
267291

268292
(deftest test-tempid-ref-295
269293
(let [db (-> (d/empty-db {:ref {:db/unique :db.unique/identity

0 commit comments

Comments
 (0)