Skip to content

Commit 9ae1fd5

Browse files
committed
Allow lookup-refs inside tuples used for lookup-refs (closes #452)
1 parent 3915250 commit 9ae1fd5

File tree

3 files changed

+62
-7
lines changed

3 files changed

+62
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- Correctly restore `:max-tx` from storage
55
- Fixed tempid/upsert resolution when multiple tempids are added first #472
66
- Allow upsert by implicit tuple when only tuple components are specified #473
7+
- Allow lookup-refs inside tuples used for lookup-refs #452
78

89
# 1.6.5 - May 3, 2024
910

src/datascript/db.cljc

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,14 @@
12381238
(raise "Bad attribute type: " attr ", expected keyword or string"
12391239
{:error :transact/syntax, :attribute attr})))
12401240

1241+
(defn resolve-tuple-refs [db a vs]
1242+
(mapv
1243+
(fn [a v]
1244+
(if (and (ref? db a) (sequential? v)) ;; lookup-ref
1245+
(entid-strict db v)
1246+
v))
1247+
(-> db -schema (get a) :db/tupleAttrs) vs))
1248+
12411249
(defn+ ^number entid [db eid]
12421250
{:pre [(db? db)]}
12431251
(cond
@@ -1250,15 +1258,22 @@
12501258
(let [[attr value] eid]
12511259
(cond
12521260
(not= (count eid) 2)
1253-
(raise "Lookup ref should contain 2 elements: " eid
1254-
{:error :lookup-ref/syntax, :entity-id eid})
1261+
(raise "Lookup ref should contain 2 elements: " eid
1262+
{:error :lookup-ref/syntax, :entity-id eid})
1263+
12551264
(not (is-attr? db attr :db/unique))
1256-
(raise "Lookup ref attribute should be marked as :db/unique: " eid
1257-
{:error :lookup-ref/unique, :entity-id eid})
1265+
(raise "Lookup ref attribute should be marked as :db/unique: " eid
1266+
{:error :lookup-ref/unique, :entity-id eid})
1267+
1268+
(tuple? db attr)
1269+
(let [value' (resolve-tuple-refs db attr value)]
1270+
(-> (-datoms db :avet attr value' nil nil) first :e))
1271+
12581272
(nil? value)
1259-
nil
1273+
nil
1274+
12601275
:else
1261-
(-> (-datoms db :avet attr value nil nil) first :e)))
1276+
(-> (-datoms db :avet attr value nil nil) first :e)))
12621277

12631278
#?@(:cljs [(array? eid) (recur db (array-seq eid))])
12641279

@@ -1838,6 +1853,13 @@
18381853
(allocate-eid v resolved)
18391854
(update ::value-tempids assoc resolved v))]
18401855
(recur report' es)))
1856+
1857+
(and
1858+
(or (= op :db/add) (= op :db/retract))
1859+
(not (::internal (meta entity)))
1860+
(tuple? db a)
1861+
(not= v (resolve-tuple-refs db a v)))
1862+
(recur report (cons [op e a (resolve-tuple-refs db a v)] entities))
18411863

18421864
(tempid? e)
18431865
(let [upserted-eid (when (is-attr? db a :db.unique/identity)
@@ -1861,7 +1883,8 @@
18611883
(raise "Conflicting upsert: " e " resolves to " upserted-eid " via " entity
18621884
{:error :transact/upsert})))
18631885

1864-
(and (not (::internal (meta entity)))
1886+
(and
1887+
(not (::internal (meta entity)))
18651888
(tuple? db a))
18661889
;; allow transacting in tuples if they fully match already existing values
18671890
(let [tuple-attrs (get-in db [:schema a :db/tupleAttrs])]

test/datascript/test/tuples.cljc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,37 @@
293293
:c "c"}
294294
(d/pull (d/db conn) '[*] [:a+b ["a" "b"]])))))
295295

296+
;; https://github.com/tonsky/datascript/issues/452
297+
(deftest lookup-refs-in-tuple
298+
(let [schema {:ref {:db/valueType :db.type/ref}
299+
:name {:db/unique :db.unique/identity}
300+
:ref+name {:db/valueType :db.type/tuple
301+
:db/tupleAttrs [:ref :name]
302+
:db/unique :db.unique/identity}}
303+
db (-> (d/empty-db schema)
304+
(d/db-with
305+
[{:db/id -1 :name "Ivan"}
306+
{:db/id -2 :name "Oleg"}
307+
{:db/id -3 :name "Petr" :ref -1}
308+
{:db/id -4 :name "Yuri" :ref -2}]))]
309+
(let [db' (d/db-with db [{:ref+name [1 "Petr"], :age 32}])]
310+
(is (= {:age 32} (d/pull db' [:age] 3))))
311+
312+
(let [db' (d/db-with db [{:ref+name [[:name "Ivan"] "Petr"], :age 32}])]
313+
(is (= {:age 32} (d/pull db' [:age] 3))))
314+
315+
(let [db' (d/db-with db [[:db/add -1 :ref+name [1 "Petr"]]
316+
[:db/add -1 :age 32]])]
317+
(is (= {:age 32} (d/pull db' [:age] 3))))
318+
319+
(let [db' (d/db-with db [[:db/add -1 :ref+name [[:name "Ivan"] "Petr"]]
320+
[:db/add -1 :age 32]])]
321+
(is (= {:age 32} (d/pull db' [:age] 3))))
322+
323+
(is (= 1 (:db/id (d/entity db [:name "Ivan"]))))
324+
(is (= 3 (:db/id (d/entity db [:ref+name [1 "Petr"]]))))
325+
(is (= 3 (:db/id (d/entity db [:ref+name [[:name "Ivan"] "Petr"]]))))))
326+
296327
(deftest test-validation
297328
(let [db (d/empty-db {:a+b {:db/tupleAttrs [:a :b]}})
298329
db1 (d/db-with db [[:db/add 1 :a "a"]])]

0 commit comments

Comments
 (0)