|
1163 | 1163 | #?(:clj (declare ref?) |
1164 | 1164 | :cljs (defn ^boolean ref? [db attr])) |
1165 | 1165 |
|
| 1166 | +#?(:clj (declare tuple?) |
| 1167 | + :cljs (defn ^boolean tuple? [db attr])) |
| 1168 | + |
| 1169 | +#?(:clj (declare resolve-tuple-refs) |
| 1170 | + :cljs (defn resolve-tuple-refs [db a vs context])) |
| 1171 | + |
1166 | 1172 | (defn+ resolve-datom [db e a v t default-e default-tx] |
1167 | 1173 | (when (some? a) |
1168 | 1174 | (validate-attr a (list 'resolve-datom 'db e a v t))) |
1169 | 1175 | (datom |
1170 | 1176 | (if (some? e) (entid-strict db e) default-e) |
1171 | 1177 | a |
1172 | | - (if (and (some? v) (ref? db a)) |
1173 | | - (entid-strict db v) |
1174 | | - v) |
| 1178 | + (cond |
| 1179 | + (nil? v) v |
| 1180 | + (ref? db a) (entid-strict db v) |
| 1181 | + (tuple? db a) (resolve-tuple-refs db a v (list 'resolve-datom 'db e a v t)) |
| 1182 | + :else v) |
1175 | 1183 | (if (some? t) (entid-strict db t) default-tx))) |
1176 | 1184 |
|
1177 | 1185 | (defn+ components->pattern [db index c0 c1 c2 c3 default-e default-tx] |
|
1271 | 1279 | (util/raise "Attribute " a " expected a vector, got: " v " in " context |
1272 | 1280 | {:error :transact/syntax, :attribute a, :value v, :context context})))))) |
1273 | 1281 |
|
1274 | | -(defn resolve-tuple-refs [db a vs context] |
1275 | | - (let [attr (-> db -schema (get a))] |
1276 | | - (validate-tuple db a attr vs context) |
1277 | | - (cond |
1278 | | - (not (sequential? vs)) ;; e.g. nil ov in :db.fn/cas |
1279 | | - vs |
| 1282 | +(defn- #?@(:clj [^Boolean tuple-ref-slot?] |
| 1283 | + :cljs [^boolean tuple-ref-slot?]) |
| 1284 | + [db schema-a idx] |
| 1285 | + (cond |
| 1286 | + (:db/tupleAttrs schema-a) (ref? db (nth (:db/tupleAttrs schema-a) idx nil)) |
| 1287 | + (:db/tupleTypes schema-a) (= :db.type/ref (nth (:db/tupleTypes schema-a) idx nil)) |
| 1288 | + :else (= :db.type/ref (:db/tupleType schema-a)))) |
1280 | 1289 |
|
1281 | | - (:db/tupleAttrs attr) |
1282 | | - (mapv |
1283 | | - (fn [el-a v] |
1284 | | - (if (and (ref? db el-a) (sequential? v)) ;; lookup-ref |
1285 | | - (entid-strict db v) |
1286 | | - v)) |
1287 | | - (:db/tupleAttrs attr) vs) |
1288 | | - |
1289 | | - (:db/tupleTypes attr) |
1290 | | - (mapv |
1291 | | - (fn [el-type v] |
1292 | | - (if (and (= :db.type/ref el-type) (sequential? v)) ;; lookup-ref |
1293 | | - (entid-strict db v) |
1294 | | - v)) |
1295 | | - (:db/tupleTypes attr) vs) |
1296 | | - |
1297 | | - (= :db.type/ref (:db/tupleType attr)) |
1298 | | - (mapv (fn [v] |
1299 | | - (if (sequential? v) ;; lookup-ref |
1300 | | - (entid-strict db v) |
1301 | | - v)) |
1302 | | - vs) |
| 1290 | +(defn- #?@(:clj [^Boolean resolved-eid?] |
| 1291 | + :cljs [^boolean resolved-eid?]) |
| 1292 | + [x] |
| 1293 | + (or |
| 1294 | + (nil? x) |
| 1295 | + (and (number? x) (not (neg? x))))) |
1303 | 1296 |
|
1304 | | - :else |
1305 | | - vs))) |
| 1297 | +(defn+ resolve-tuple-refs |
| 1298 | + "Resolves lookup refs and idents in ref slots of a tuple value. |
| 1299 | + Read path: no tempids, unresolved refs raise" |
| 1300 | + [db a vs context] |
| 1301 | + (let [schema-a (-> db -schema (get a))] |
| 1302 | + (validate-tuple db a schema-a vs context) |
| 1303 | + (if-not (sequential? vs) ;; e.g. nil ov in :db.fn/cas |
| 1304 | + vs |
| 1305 | + (into [] |
| 1306 | + (map-indexed |
| 1307 | + (fn [idx v] |
| 1308 | + (if (and |
| 1309 | + (tuple-ref-slot? db schema-a idx) |
| 1310 | + (not (resolved-eid? v))) |
| 1311 | + (entid-strict db v) |
| 1312 | + v))) |
| 1313 | + vs)))) |
1306 | 1314 |
|
1307 | 1315 | (defn+ ^number entid [db eid] |
1308 | 1316 | {:pre [(db? db)]} |
|
1323 | 1331 | (util/raise "Lookup ref attribute should be marked as :db/unique: " eid |
1324 | 1332 | {:error :lookup-ref/unique, :entity-id eid}) |
1325 | 1333 |
|
| 1334 | + (nil? value) |
| 1335 | + nil |
| 1336 | + |
1326 | 1337 | (tuple? db attr) |
1327 | 1338 | (let [value' (resolve-tuple-refs db attr value eid)] |
1328 | 1339 | (-> (-datoms db :avet attr value' nil nil) first :e)) |
1329 | | - |
1330 | | - (nil? value) |
1331 | | - nil |
1332 | | - |
| 1340 | + |
1333 | 1341 | :else |
1334 | 1342 | (-> (-datoms db :avet attr value nil nil) first :e))) |
1335 | 1343 |
|
|
1468 | 1476 | (auto-tempid? x))) |
1469 | 1477 |
|
1470 | 1478 | (defn- new-eid? [db eid] |
1471 | | - (and (> eid (:max-eid db)) |
| 1479 | + (and |
| 1480 | + (> eid (:max-eid db)) |
1472 | 1481 | (< eid tx0))) ;; tx0 is max eid |
1473 | 1482 |
|
1474 | 1483 | (defn- advance-max-eid [db eid] |
|
1497 | 1506 | true |
1498 | 1507 | (update :db-after advance-max-eid eid)))) |
1499 | 1508 |
|
1500 | | -(defn- #?@(:clj [^Boolean tuple-slot-resolved?] |
1501 | | - :cljs [^boolean tuple-slot-resolved?]) |
1502 | | - [x] |
1503 | | - (or |
1504 | | - (nil? x) |
1505 | | - (and (number? x) (not (neg? x))))) |
1506 | | - |
1507 | | -(defn- resolve-tuple-slot [report v] |
1508 | | - (let [db (:db-after report)] |
1509 | | - (cond |
1510 | | - (tuple-slot-resolved? v) |
1511 | | - [report v] |
1512 | | - |
1513 | | - (tx-id? v) |
1514 | | - (let [id (current-tx report)] |
1515 | | - [(allocate-eid report v id) id]) |
1516 | | - |
1517 | | - (tempid? v) |
1518 | | - (if-some [resolved (get (:tempids report) v)] |
1519 | | - [(update report ::value-tempids assoc resolved v) resolved] |
1520 | | - (let [resolved (next-eid db)] |
1521 | | - [(-> report |
1522 | | - (allocate-eid v resolved) |
1523 | | - (update ::value-tempids assoc resolved v)) |
1524 | | - resolved])) |
1525 | | - |
1526 | | - :else ;; lookup ref or ident |
1527 | | - [report (entid-strict db v)]))) |
1528 | | - |
1529 | 1509 | (defn- resolve-tuple-value |
1530 | 1510 | "Resoleves refs, tempids and :db/current-tx in ref slots. Returns [report' vs']" |
1531 | 1511 | [report a vs context] |
1532 | | - (let [db (:db-after report) |
1533 | | - attr (-> db -schema (get a)) |
1534 | | - _ (validate-tuple db a attr vs context)] |
1535 | | - (cond |
1536 | | - (not (vector? vs)) |
| 1512 | + (let [db (:db-after report) |
| 1513 | + schema-a (-> db -schema (get a)) |
| 1514 | + _ (validate-tuple db a schema-a vs context)] |
| 1515 | + (if-not (vector? vs) |
1537 | 1516 | [report vs] |
1538 | | - |
1539 | | - (:db/tupleAttrs attr) |
1540 | | - (let [el-attrs (:db/tupleAttrs attr)] |
1541 | | - (loop [idx 0 |
1542 | | - report' report |
1543 | | - vs' (transient [])] |
1544 | | - (if (>= idx (count vs)) |
1545 | | - [report' (persistent! vs')] |
1546 | | - (let [v (nth vs idx)] |
1547 | | - (if (ref? db (nth el-attrs idx nil)) |
1548 | | - (let [[report'' v'] (resolve-tuple-slot report' v)] |
1549 | | - (recur (inc idx) report'' (conj! vs' v'))) |
1550 | | - (recur (inc idx) report' (conj! vs' v))))))) |
1551 | | - |
1552 | | - (:db/tupleTypes attr) |
1553 | | - (let [types (:db/tupleTypes attr)] |
1554 | | - (loop [idx 0 |
1555 | | - report' report |
1556 | | - vs' (transient [])] |
1557 | | - (if (>= idx (count vs)) |
1558 | | - [report' (persistent! vs')] |
1559 | | - (let [v (nth vs idx)] |
1560 | | - (if (= :db.type/ref (nth types idx nil)) |
1561 | | - (let [[report'' v'] (resolve-tuple-slot report' v)] |
1562 | | - (recur (inc idx) report'' (conj! vs' v'))) |
1563 | | - (recur (inc idx) report' (conj! vs' v))))))) |
1564 | | - |
1565 | | - (= :db.type/ref (:db/tupleType attr)) |
1566 | 1517 | (loop [idx 0 |
1567 | 1518 | report' report |
1568 | 1519 | vs' (transient [])] |
1569 | 1520 | (if (>= idx (count vs)) |
1570 | 1521 | [report' (persistent! vs')] |
1571 | | - (let [v (nth vs idx) |
1572 | | - [report'' v'] (resolve-tuple-slot report' v)] |
1573 | | - (recur (inc idx) report'' (conj! vs' v'))))) |
1574 | | - |
1575 | | - :else |
1576 | | - [report vs]))) |
| 1522 | + (let [v (nth vs idx)] |
| 1523 | + (if (tuple-ref-slot? db schema-a idx) |
| 1524 | + (let [[report'' v'] (cond |
| 1525 | + (resolved-eid? v) |
| 1526 | + [report' v] |
| 1527 | + |
| 1528 | + (tx-id? v) |
| 1529 | + (let [id (current-tx report')] |
| 1530 | + [(allocate-eid report' v id) id]) |
| 1531 | + |
| 1532 | + (tempid? v) |
| 1533 | + (if-some [resolved (get (:tempids report') v)] |
| 1534 | + [(update report' ::value-tempids assoc resolved v) resolved] |
| 1535 | + (let [resolved (next-eid db)] |
| 1536 | + [(-> report' |
| 1537 | + (allocate-eid v resolved) |
| 1538 | + (update ::value-tempids assoc resolved v)) |
| 1539 | + resolved])) |
| 1540 | + |
| 1541 | + :else ;; lookup ref or ident |
| 1542 | + [report' (entid-strict db v)])] |
| 1543 | + |
| 1544 | + (recur (inc idx) report'' (conj! vs' v'))) |
| 1545 | + (recur (inc idx) report' (conj! vs' v))))))))) |
1577 | 1546 |
|
1578 | 1547 | ;; In context of `with-datom` we can use faster comparators which |
1579 | 1548 | ;; do not check for nil (~10-15% performance gain in `transact`) |
|
0 commit comments