|
30 | 30 | data (last fragments)] |
31 | 31 | `(throw (ex-info (str ~@(map (fn [m#] (if (string? m#) m# (list 'pr-str m#))) msgs)) ~data))))) |
32 | 32 |
|
33 | | -(defn #?@(:clj [^Boolean seqable?] |
| 33 | +(defn #?@(:clj [^Boolean seqable?] |
34 | 34 | :cljs [^boolean seqable?]) |
35 | 35 | [x] |
36 | 36 | (and (not (string? x)) |
|
147 | 147 | IIndexed |
148 | 148 | (-nth [this i] (nth-datom this i)) |
149 | 149 | (-nth [this i not-found] (nth-datom this i not-found)) |
150 | | - |
| 150 | + |
151 | 151 | IAssociative |
152 | 152 | (-assoc [d k v] (assoc-datom d k v)) |
153 | 153 |
|
|
172 | 172 | (empty [d] (throw (UnsupportedOperationException. "empty is not supported on Datom"))) |
173 | 173 | (count [d] 5) |
174 | 174 | (cons [d [k v]] (assoc-datom d k v)) |
175 | | - |
| 175 | + |
176 | 176 | clojure.lang.Indexed |
177 | 177 | (nth [this i] (nth-datom this i)) |
178 | 178 | (nth [this i not-found] (nth-datom this i not-found)) |
|
191 | 191 | ([e a v] (Datom. e a v tx0 true)) |
192 | 192 | ([e a v tx] (Datom. e a v tx true)) |
193 | 193 | ([e a v tx added] (Datom. e a v tx added))) |
194 | | - |
| 194 | + |
195 | 195 | (defn datom? [x] (instance? Datom x)) |
196 | 196 |
|
197 | 197 | (defn- hash-datom [^Datom d] |
|
468 | 468 | (or (> (hc/compare i e) 0) |
469 | 469 | (> (hc/compare j f) 0) |
470 | 470 | (> (hc/compare k g) 0) |
471 | | - (> (hc/compare l h) 0)) |
| 471 | + (> (hc/compare l h) 0)) |
472 | 472 |
|
473 | 473 | (and e f g) |
474 | 474 | (or (> (hc/compare i e) 0) |
|
775 | 775 |
|
776 | 776 | (defn ^DB init-db |
777 | 777 | ([datoms] (init-db datoms default-schema)) |
778 | | - ([datoms schema] |
| 778 | + ([datoms schema & {:as options :keys [validate?] :or {validate? true}}] |
779 | 779 | (if (empty? datoms) |
780 | 780 | (empty-db schema) |
781 | | - (let [_ (validate-schema schema) |
| 781 | + (let [_ (when validate? (validate-schema schema)) |
782 | 782 | rschema (rschema schema) |
783 | 783 | indexed (:db/index rschema) |
784 | 784 | #?@(:cljs |
|
945 | 945 | (defn entid [db eid] |
946 | 946 | {:pre [(db? db)]} |
947 | 947 | (cond |
948 | | - (number? eid) eid |
| 948 | + (number? eid) |
| 949 | + eid |
| 950 | + |
949 | 951 | (sequential? eid) |
950 | | - (cond |
951 | | - (not= (count eid) 2) |
952 | | - (raise "Lookup ref should contain 2 elements: " eid |
953 | | - {:error :lookup-ref/syntax, :entity-id eid}) |
954 | | - (not (is-attr? db (first eid) :db/unique)) |
955 | | - (raise "Lookup ref attribute should be marked as :db/unique: " eid |
956 | | - {:error :lookup-ref/unique |
957 | | - :entity-id eid}) |
958 | | - (nil? (second eid)) |
959 | | - nil |
960 | | - :else |
961 | | - (:e (first (-datoms db :avet eid)))) |
962 | | - #?@(:cljs [(array? eid) (recur db (array-seq eid))]) |
| 952 | + (cond |
| 953 | + (not= (count eid) 2) |
| 954 | + (raise "Lookup ref should contain 2 elements: " eid |
| 955 | + {:error :lookup-ref/syntax, :entity-id eid}) |
| 956 | + (not (is-attr? db (first eid) :db/unique)) |
| 957 | + (if (= :db/ident (first eid)) |
| 958 | + (raise "You must have :db/ident marked as :db/unique in your schema to use keyword refs" {:error :lookup-ref/db-ident |
| 959 | + :entity-id eid}) |
| 960 | + (raise "Lookup ref attribute should be marked as :db/unique: " eid |
| 961 | + {:error :lookup-ref/unique |
| 962 | + :entity-id eid})) |
| 963 | + (nil? (second eid)) |
| 964 | + nil |
| 965 | + :else |
| 966 | + (:e (first (-datoms db :avet eid)))) |
| 967 | + |
| 968 | + #?@(:cljs |
| 969 | + [(array? eid) |
| 970 | + (recur db (array-seq eid))]) |
| 971 | + |
| 972 | + (keyword? eid) |
| 973 | + (recur db [:db/ident eid]) |
| 974 | + |
963 | 975 | :else |
964 | | - (raise "Expected number or lookup ref for entity id, got " eid |
965 | | - {:error :entity-id/syntax |
966 | | - :entity-id eid}))) |
| 976 | + (raise "Expected number or lookup ref for entity id, got " eid |
| 977 | + {:error :entity-id/syntax |
| 978 | + :entity-id eid}))) |
967 | 979 |
|
968 | 980 | (defn entid-strict [db eid] |
969 | 981 | (or (entid db eid) |
|
1090 | 1102 | (cond |
1091 | 1103 | (keyword? attr) |
1092 | 1104 | (= \_ (nth (name attr) 0)) |
1093 | | - |
| 1105 | + |
1094 | 1106 | (string? attr) |
1095 | 1107 | (boolean (re-matches #"(?:([^/]+)/)?_([^/]+)" attr)) |
1096 | | - |
| 1108 | + |
1097 | 1109 | :else |
1098 | 1110 | (raise "Bad attribute type: " attr ", expected keyword or string" |
1099 | 1111 | {:error :transact/syntax, :attribute attr}))) |
|
1110 | 1122 | (if (= \_ (nth name 0)) |
1111 | 1123 | (if ns (str ns "/" (subs name 1)) (subs name 1)) |
1112 | 1124 | (if ns (str ns "/_" name) (str "_" name)))) |
1113 | | - |
| 1125 | + |
1114 | 1126 | :else |
1115 | 1127 | (raise "Bad attribute type: " attr ", expected keyword or string" |
1116 | 1128 | {:error :transact/syntax, :attribute attr}))) |
|
1169 | 1181 | (not (or (da/array? vs) |
1170 | 1182 | (and (coll? vs) (not (map? vs))))) |
1171 | 1183 | [vs] |
1172 | | - |
| 1184 | + |
1173 | 1185 | ;; probably lookup ref |
1174 | 1186 | (and (= (count vs) 2) |
1175 | 1187 | (is-attr? db (first vs) :db.unique/identity)) |
1176 | 1188 | [vs] |
1177 | | - |
| 1189 | + |
1178 | 1190 | :else vs)) |
1179 | 1191 |
|
1180 | 1192 |
|
|
1251 | 1263 | (transact-tx-data (assoc-in report [:tempids tempid] upserted-eid) |
1252 | 1264 | es))) |
1253 | 1265 |
|
1254 | | -(defn transact-tx-data [initial-report initial-es] |
| 1266 | +(defn transact-tx-data* [initial-report initial-es] |
1255 | 1267 | (when-not (or (nil? initial-es) |
1256 | 1268 | (sequential? initial-es)) |
1257 | 1269 | (raise "Bad transaction data " initial-es ", expected sequential collection" |
|
1277 | 1289 | (let [id (current-tx report)] |
1278 | 1290 | (recur (allocate-eid report old-eid id) |
1279 | 1291 | (cons (assoc entity :db/id id) entities))) |
1280 | | - |
| 1292 | + |
1281 | 1293 | ;; lookup-ref => resolved | error |
1282 | 1294 | (sequential? old-eid) |
1283 | 1295 | (let [id (entid-strict db old-eid)] |
1284 | 1296 | (recur report |
1285 | 1297 | (cons (assoc entity :db/id id) entities))) |
1286 | | - |
| 1298 | + |
1287 | 1299 | ;; upserted => explode | error |
1288 | 1300 | [upserted-eid (upsert-eid db entity)] |
1289 | 1301 | (if (and (neg-number? old-eid) |
|
1292 | 1304 | (retry-with-tempid initial-report initial-es old-eid upserted-eid) |
1293 | 1305 | (recur (allocate-eid report old-eid upserted-eid) |
1294 | 1306 | (concat (explode db (assoc entity :db/id upserted-eid)) entities))) |
1295 | | - |
| 1307 | + |
1296 | 1308 | ;; resolved | allocated-tempid | tempid | nil => explode |
1297 | 1309 | (or (number? old-eid) |
1298 | 1310 | (nil? old-eid)) |
|
1301 | 1313 | (neg? old-eid) (or (get (:tempids report) old-eid) |
1302 | 1314 | (next-eid db)) |
1303 | 1315 | :else old-eid) |
1304 | | - new-entity (assoc entity :db/id new-eid)] |
| 1316 | + new-entity (assoc entity :db/id new-eid)] |
1305 | 1317 | (recur (allocate-eid report old-eid new-eid) |
1306 | 1318 | (concat (explode db new-entity) entities))) |
1307 | | - |
| 1319 | + |
1308 | 1320 | ;; trash => error |
1309 | 1321 | :else |
1310 | 1322 | (raise "Expected number or lookup ref for :db/id, got " old-eid |
|
1392 | 1404 | :else |
1393 | 1405 | (raise "Unknown operation at " entity ", expected :db/add, :db/retract, :db.fn/call, :db.fn/retractAttribute or :db.fn/retractEntity" |
1394 | 1406 | {:error :transact/syntax, :operation op, :tx-data entity}))) |
1395 | | - |
| 1407 | + |
1396 | 1408 | (datom? entity) |
1397 | 1409 | (let [[e a v tx added] entity] |
1398 | 1410 | (if added |
|
1404 | 1416 | {:error :transact/syntax, :tx-data entity}) |
1405 | 1417 | )))) |
1406 | 1418 |
|
| 1419 | +(defn transact-tx-data [{:as initial-report :keys [tx-meta]} initial-es] |
| 1420 | + (let [middleware (or |
| 1421 | + (when (map? tx-meta) |
| 1422 | + (::tx-middleware tx-meta)) |
| 1423 | + identity)] |
| 1424 | + ((middleware transact-tx-data*) |
| 1425 | + initial-report |
| 1426 | + initial-es))) |
| 1427 | + |
1407 | 1428 |
|
1408 | 1429 |
|
1409 | 1430 | (comment |
|
0 commit comments