datahike-browser-tests 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/.circleci/config.yml +405 -0
  2. package/.circleci/scripts/gen_ci.clj +194 -0
  3. package/.cirrus.yml +60 -0
  4. package/.clj-kondo/babashka/sci/config.edn +1 -0
  5. package/.clj-kondo/babashka/sci/sci/core.clj +9 -0
  6. package/.clj-kondo/config.edn +95 -0
  7. package/.dir-locals.el +2 -0
  8. package/.github/FUNDING.yml +3 -0
  9. package/.github/ISSUE_TEMPLATE/1-bug-report.yml +68 -0
  10. package/.github/ISSUE_TEMPLATE/2-feature-request.yml +28 -0
  11. package/.github/ISSUE_TEMPLATE/config.yml +6 -0
  12. package/.github/pull_request_template.md +24 -0
  13. package/.github/workflows/native-image.yml +84 -0
  14. package/LICENSE +203 -0
  15. package/README.md +273 -0
  16. package/bb/deps.edn +9 -0
  17. package/bb/resources/github-fingerprints +3 -0
  18. package/bb/resources/native-image-tests/run-bb-pod-tests.clj +162 -0
  19. package/bb/resources/native-image-tests/run-libdatahike-tests +12 -0
  20. package/bb/resources/native-image-tests/run-native-image-tests +74 -0
  21. package/bb/resources/native-image-tests/run-python-tests +22 -0
  22. package/bb/resources/native-image-tests/testconfig.attr-refs.edn +6 -0
  23. package/bb/resources/native-image-tests/testconfig.edn +5 -0
  24. package/bb/resources/template/.settings/org.eclipse.jdt.apt.core.prefs +2 -0
  25. package/bb/resources/template/.settings/org.eclipse.jdt.core.prefs +9 -0
  26. package/bb/resources/template/.settings/org.eclipse.m2e.core.prefs +4 -0
  27. package/bb/resources/template/pom.xml +22 -0
  28. package/bb/src/tools/build.clj +132 -0
  29. package/bb/src/tools/clj_kondo.clj +32 -0
  30. package/bb/src/tools/deploy.clj +26 -0
  31. package/bb/src/tools/examples.clj +19 -0
  32. package/bb/src/tools/npm.clj +100 -0
  33. package/bb/src/tools/python.clj +14 -0
  34. package/bb/src/tools/release.clj +94 -0
  35. package/bb/src/tools/test.clj +148 -0
  36. package/bb/src/tools/version.clj +47 -0
  37. package/bb.edn +269 -0
  38. package/benchmark/src/benchmark/cli.clj +195 -0
  39. package/benchmark/src/benchmark/compare.clj +157 -0
  40. package/benchmark/src/benchmark/config.clj +316 -0
  41. package/benchmark/src/benchmark/measure.clj +187 -0
  42. package/benchmark/src/benchmark/store.clj +190 -0
  43. package/benchmark/test/benchmark/measure_test.clj +156 -0
  44. package/build.clj +30 -0
  45. package/config.edn +49 -0
  46. package/deps.edn +138 -0
  47. package/dev/sandbox.clj +82 -0
  48. package/dev/sandbox.cljs +127 -0
  49. package/dev/sandbox_benchmarks.clj +27 -0
  50. package/dev/sandbox_client.clj +87 -0
  51. package/dev/sandbox_transact_bench.clj +109 -0
  52. package/dev/user.clj +79 -0
  53. package/doc/README.md +96 -0
  54. package/doc/adl/README.md +6 -0
  55. package/doc/adl/adr-000-adr.org +28 -0
  56. package/doc/adl/adr-001-attribute-references.org +15 -0
  57. package/doc/adl/adr-002-build-tooling.org +54 -0
  58. package/doc/adl/adr-003-db-meta-data.md +52 -0
  59. package/doc/adl/adr-004-github-flow.md +40 -0
  60. package/doc/adl/adr-XYZ-template.md +30 -0
  61. package/doc/adl/index.org +3 -0
  62. package/doc/assets/datahike-logo.svg +3 -0
  63. package/doc/assets/datahiking-invoice.org +85 -0
  64. package/doc/assets/hhtree2.png +0 -0
  65. package/doc/assets/network_topology.svg +624 -0
  66. package/doc/assets/perf.png +0 -0
  67. package/doc/assets/schema_mindmap.mm +132 -0
  68. package/doc/assets/schema_mindmap.svg +970 -0
  69. package/doc/assets/temporal_index.mm +74 -0
  70. package/doc/backend-development.md +78 -0
  71. package/doc/bb-pod.md +89 -0
  72. package/doc/benchmarking.md +360 -0
  73. package/doc/bindings/edn-conversion.md +383 -0
  74. package/doc/cli.md +162 -0
  75. package/doc/cljdoc.edn +27 -0
  76. package/doc/cljs-support.md +133 -0
  77. package/doc/config.md +406 -0
  78. package/doc/contributing.md +114 -0
  79. package/doc/datalog-vs-sql.md +210 -0
  80. package/doc/datomic_differences.md +109 -0
  81. package/doc/development/pull-api-ns.md +186 -0
  82. package/doc/development/pull-frame-state-diagram.jpg +0 -0
  83. package/doc/distributed.md +566 -0
  84. package/doc/entity_spec.md +92 -0
  85. package/doc/gc.md +273 -0
  86. package/doc/java-api.md +808 -0
  87. package/doc/javascript-api.md +421 -0
  88. package/doc/libdatahike.md +86 -0
  89. package/doc/logging_and_error_handling.md +43 -0
  90. package/doc/norms.md +66 -0
  91. package/doc/schema-migration.md +85 -0
  92. package/doc/schema.md +287 -0
  93. package/doc/storage-backends.md +363 -0
  94. package/doc/store-id-refactoring.md +596 -0
  95. package/doc/time_variance.md +325 -0
  96. package/doc/unstructured.md +167 -0
  97. package/doc/versioning.md +261 -0
  98. package/examples/basic/README.md +19 -0
  99. package/examples/basic/deps.edn +6 -0
  100. package/examples/basic/docker-compose.yml +13 -0
  101. package/examples/basic/src/examples/core.clj +60 -0
  102. package/examples/basic/src/examples/schema.clj +155 -0
  103. package/examples/basic/src/examples/store.clj +60 -0
  104. package/examples/basic/src/examples/time_travel.clj +185 -0
  105. package/examples/java/.settings/org.eclipse.core.resources.prefs +3 -0
  106. package/examples/java/.settings/org.eclipse.jdt.apt.core.prefs +2 -0
  107. package/examples/java/.settings/org.eclipse.jdt.core.prefs +9 -0
  108. package/examples/java/.settings/org.eclipse.m2e.core.prefs +4 -0
  109. package/examples/java/README.md +162 -0
  110. package/examples/java/pom.xml +62 -0
  111. package/examples/java/src/main/java/examples/QuickStart.java +115 -0
  112. package/examples/java/src/main/java/examples/SchemaExample.java +148 -0
  113. package/examples/java/src/main/java/examples/TimeTravelExample.java +121 -0
  114. package/flake.lock +27 -0
  115. package/flake.nix +27 -0
  116. package/http-server/datahike/http/middleware.clj +75 -0
  117. package/http-server/datahike/http/server.clj +269 -0
  118. package/java/src/datahike/java/Database.java +274 -0
  119. package/java/src/datahike/java/Datahike.java +281 -0
  120. package/java/src/datahike/java/DatahikeGeneratedTest.java +349 -0
  121. package/java/src/datahike/java/DatahikeTest.java +370 -0
  122. package/java/src/datahike/java/EDN.java +170 -0
  123. package/java/src/datahike/java/IEntity.java +11 -0
  124. package/java/src/datahike/java/Keywords.java +161 -0
  125. package/java/src/datahike/java/SchemaFlexibility.java +52 -0
  126. package/java/src/datahike/java/Util.java +219 -0
  127. package/karma.conf.js +19 -0
  128. package/libdatahike/compile-cpp +7 -0
  129. package/libdatahike/src/datahike/impl/LibDatahikeBase.java +203 -0
  130. package/libdatahike/src/datahike/impl/libdatahike.clj +59 -0
  131. package/libdatahike/src/test_cpp.cpp +61 -0
  132. package/npm-package/PUBLISHING.md +140 -0
  133. package/npm-package/README.md +226 -0
  134. package/npm-package/package.template.json +34 -0
  135. package/npm-package/test-isomorphic.ts +281 -0
  136. package/npm-package/test.js +557 -0
  137. package/npm-package/typescript-test.ts +70 -0
  138. package/package.json +16 -0
  139. package/pydatahike/README.md +569 -0
  140. package/pydatahike/pyproject.toml +91 -0
  141. package/pydatahike/setup.py +42 -0
  142. package/pydatahike/src/datahike/__init__.py +134 -0
  143. package/pydatahike/src/datahike/_native.py +250 -0
  144. package/pydatahike/src/datahike/_version.py +2 -0
  145. package/pydatahike/src/datahike/database.py +722 -0
  146. package/pydatahike/src/datahike/edn.py +311 -0
  147. package/pydatahike/src/datahike/py.typed +0 -0
  148. package/pydatahike/tests/conftest.py +17 -0
  149. package/pydatahike/tests/test_basic.py +170 -0
  150. package/pydatahike/tests/test_database.py +51 -0
  151. package/pydatahike/tests/test_edn_conversion.py +299 -0
  152. package/pydatahike/tests/test_query.py +99 -0
  153. package/pydatahike/tests/test_schema.py +55 -0
  154. package/resources/clj-kondo.exports/io.replikativ/datahike/config.edn +5 -0
  155. package/resources/example_server.edn +4 -0
  156. package/shadow-cljs.edn +56 -0
  157. package/src/data_readers.clj +7 -0
  158. package/src/datahike/api/impl.cljc +176 -0
  159. package/src/datahike/api/specification.cljc +633 -0
  160. package/src/datahike/api/types.cljc +261 -0
  161. package/src/datahike/api.cljc +41 -0
  162. package/src/datahike/array.cljc +99 -0
  163. package/src/datahike/cli.clj +166 -0
  164. package/src/datahike/cljs.cljs +6 -0
  165. package/src/datahike/codegen/cli.clj +406 -0
  166. package/src/datahike/codegen/clj_kondo.clj +291 -0
  167. package/src/datahike/codegen/java.clj +403 -0
  168. package/src/datahike/codegen/naming.cljc +33 -0
  169. package/src/datahike/codegen/native.clj +559 -0
  170. package/src/datahike/codegen/pod.clj +488 -0
  171. package/src/datahike/codegen/python.clj +838 -0
  172. package/src/datahike/codegen/report.clj +55 -0
  173. package/src/datahike/codegen/typescript.clj +262 -0
  174. package/src/datahike/codegen/validation.clj +145 -0
  175. package/src/datahike/config.cljc +294 -0
  176. package/src/datahike/connections.cljc +16 -0
  177. package/src/datahike/connector.cljc +265 -0
  178. package/src/datahike/constants.cljc +142 -0
  179. package/src/datahike/core.cljc +297 -0
  180. package/src/datahike/datom.cljc +459 -0
  181. package/src/datahike/db/interface.cljc +119 -0
  182. package/src/datahike/db/search.cljc +305 -0
  183. package/src/datahike/db/transaction.cljc +937 -0
  184. package/src/datahike/db/utils.cljc +338 -0
  185. package/src/datahike/db.cljc +956 -0
  186. package/src/datahike/experimental/unstructured.cljc +126 -0
  187. package/src/datahike/experimental/versioning.cljc +172 -0
  188. package/src/datahike/externs.js +31 -0
  189. package/src/datahike/gc.cljc +69 -0
  190. package/src/datahike/http/client.clj +188 -0
  191. package/src/datahike/http/writer.clj +79 -0
  192. package/src/datahike/impl/entity.cljc +218 -0
  193. package/src/datahike/index/interface.cljc +93 -0
  194. package/src/datahike/index/persistent_set.cljc +469 -0
  195. package/src/datahike/index/utils.cljc +44 -0
  196. package/src/datahike/index.cljc +32 -0
  197. package/src/datahike/js/api.cljs +172 -0
  198. package/src/datahike/js/api_macros.clj +22 -0
  199. package/src/datahike/js.cljs +163 -0
  200. package/src/datahike/json.cljc +209 -0
  201. package/src/datahike/lru.cljc +146 -0
  202. package/src/datahike/migrate.clj +39 -0
  203. package/src/datahike/norm/norm.clj +245 -0
  204. package/src/datahike/online_gc.cljc +252 -0
  205. package/src/datahike/pod.clj +155 -0
  206. package/src/datahike/pull_api.cljc +325 -0
  207. package/src/datahike/query.cljc +1945 -0
  208. package/src/datahike/query_stats.cljc +88 -0
  209. package/src/datahike/readers.cljc +62 -0
  210. package/src/datahike/remote.cljc +218 -0
  211. package/src/datahike/schema.cljc +228 -0
  212. package/src/datahike/schema_cache.cljc +42 -0
  213. package/src/datahike/spec.cljc +101 -0
  214. package/src/datahike/store.cljc +80 -0
  215. package/src/datahike/tools.cljc +308 -0
  216. package/src/datahike/transit.cljc +80 -0
  217. package/src/datahike/writer.cljc +239 -0
  218. package/src/datahike/writing.cljc +362 -0
  219. package/src/deps.cljs +1 -0
  220. package/src-hitchhiker-tree/datahike/index/hitchhiker_tree/insert.cljc +76 -0
  221. package/src-hitchhiker-tree/datahike/index/hitchhiker_tree/upsert.cljc +128 -0
  222. package/src-hitchhiker-tree/datahike/index/hitchhiker_tree.cljc +213 -0
  223. package/test/datahike/backward_compatibility_test/src/backward_test.clj +37 -0
  224. package/test/datahike/integration_test/config_record_file_test.clj +14 -0
  225. package/test/datahike/integration_test/config_record_test.clj +14 -0
  226. package/test/datahike/integration_test/depr_config_uri_test.clj +15 -0
  227. package/test/datahike/integration_test/return_map_test.clj +62 -0
  228. package/test/datahike/integration_test.cljc +67 -0
  229. package/test/datahike/norm/norm_test.clj +124 -0
  230. package/test/datahike/norm/resources/naming-and-sorting-test/001-a1-example.edn +5 -0
  231. package/test/datahike/norm/resources/naming-and-sorting-test/002-a2-example.edn +5 -0
  232. package/test/datahike/norm/resources/naming-and-sorting-test/003-tx-fn-test.edn +1 -0
  233. package/test/datahike/norm/resources/naming-and-sorting-test/004-tx-data-and-tx-fn-test.edn +5 -0
  234. package/test/datahike/norm/resources/naming-and-sorting-test/01-transact-basic-characters.edn +2 -0
  235. package/test/datahike/norm/resources/naming-and-sorting-test/02 add occupation.edn +5 -0
  236. package/test/datahike/norm/resources/naming-and-sorting-test/checksums.edn +12 -0
  237. package/test/datahike/norm/resources/simple-test/001-a1-example.edn +5 -0
  238. package/test/datahike/norm/resources/simple-test/002-a2-example.edn +5 -0
  239. package/test/datahike/norm/resources/simple-test/checksums.edn +4 -0
  240. package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/001-a1-example.edn +5 -0
  241. package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/002-a2-example.edn +5 -0
  242. package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/003-tx-fn-test.edn +1 -0
  243. package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/checksums.edn +6 -0
  244. package/test/datahike/norm/resources/tx-data-and-tx-fn-test/second/004-tx-data-and-tx-fn-test.edn +5 -0
  245. package/test/datahike/norm/resources/tx-data-and-tx-fn-test/second/checksums.edn +2 -0
  246. package/test/datahike/norm/resources/tx-fn-test/first/001-a1-example.edn +5 -0
  247. package/test/datahike/norm/resources/tx-fn-test/first/002-a2-example.edn +5 -0
  248. package/test/datahike/norm/resources/tx-fn-test/first/checksums.edn +4 -0
  249. package/test/datahike/norm/resources/tx-fn-test/second/003-tx-fn-test.edn +1 -0
  250. package/test/datahike/norm/resources/tx-fn-test/second/checksums.edn +2 -0
  251. package/test/datahike/test/api_test.cljc +895 -0
  252. package/test/datahike/test/array_test.cljc +40 -0
  253. package/test/datahike/test/attribute_refs/datoms_test.cljc +140 -0
  254. package/test/datahike/test/attribute_refs/db_test.cljc +42 -0
  255. package/test/datahike/test/attribute_refs/differences_test.cljc +515 -0
  256. package/test/datahike/test/attribute_refs/entity_test.cljc +89 -0
  257. package/test/datahike/test/attribute_refs/pull_api_test.cljc +320 -0
  258. package/test/datahike/test/attribute_refs/query_find_specs_test.cljc +59 -0
  259. package/test/datahike/test/attribute_refs/query_fns_test.cljc +130 -0
  260. package/test/datahike/test/attribute_refs/query_interop_test.cljc +47 -0
  261. package/test/datahike/test/attribute_refs/query_not_test.cljc +193 -0
  262. package/test/datahike/test/attribute_refs/query_or_test.cljc +137 -0
  263. package/test/datahike/test/attribute_refs/query_pull_test.cljc +156 -0
  264. package/test/datahike/test/attribute_refs/query_rules_test.cljc +176 -0
  265. package/test/datahike/test/attribute_refs/query_test.cljc +241 -0
  266. package/test/datahike/test/attribute_refs/temporal_search.cljc +22 -0
  267. package/test/datahike/test/attribute_refs/transact_test.cljc +220 -0
  268. package/test/datahike/test/attribute_refs/utils.cljc +128 -0
  269. package/test/datahike/test/cache_test.cljc +38 -0
  270. package/test/datahike/test/components_test.cljc +92 -0
  271. package/test/datahike/test/config_test.cljc +158 -0
  272. package/test/datahike/test/core_test.cljc +105 -0
  273. package/test/datahike/test/datom_test.cljc +44 -0
  274. package/test/datahike/test/db_test.cljc +54 -0
  275. package/test/datahike/test/entity_spec_test.cljc +159 -0
  276. package/test/datahike/test/entity_test.cljc +103 -0
  277. package/test/datahike/test/explode_test.cljc +143 -0
  278. package/test/datahike/test/filter_test.cljc +75 -0
  279. package/test/datahike/test/gc_test.cljc +159 -0
  280. package/test/datahike/test/http/server_test.clj +192 -0
  281. package/test/datahike/test/http/writer_test.clj +86 -0
  282. package/test/datahike/test/ident_test.cljc +32 -0
  283. package/test/datahike/test/index_test.cljc +345 -0
  284. package/test/datahike/test/insert.cljc +125 -0
  285. package/test/datahike/test/java_bindings_test.clj +6 -0
  286. package/test/datahike/test/listen_test.cljc +41 -0
  287. package/test/datahike/test/lookup_refs_test.cljc +266 -0
  288. package/test/datahike/test/lru_test.cljc +27 -0
  289. package/test/datahike/test/migrate_test.clj +297 -0
  290. package/test/datahike/test/model/core.cljc +376 -0
  291. package/test/datahike/test/model/invariant.cljc +142 -0
  292. package/test/datahike/test/model/rng.cljc +82 -0
  293. package/test/datahike/test/model_test.clj +217 -0
  294. package/test/datahike/test/nodejs_test.cljs +262 -0
  295. package/test/datahike/test/online_gc_test.cljc +475 -0
  296. package/test/datahike/test/pod_test.clj +369 -0
  297. package/test/datahike/test/pull_api_test.cljc +474 -0
  298. package/test/datahike/test/purge_test.cljc +144 -0
  299. package/test/datahike/test/query_aggregates_test.cljc +101 -0
  300. package/test/datahike/test/query_find_specs_test.cljc +52 -0
  301. package/test/datahike/test/query_fns_test.cljc +523 -0
  302. package/test/datahike/test/query_interop_test.cljc +47 -0
  303. package/test/datahike/test/query_not_test.cljc +189 -0
  304. package/test/datahike/test/query_or_test.cljc +158 -0
  305. package/test/datahike/test/query_pull_test.cljc +147 -0
  306. package/test/datahike/test/query_rules_test.cljc +248 -0
  307. package/test/datahike/test/query_stats_test.cljc +218 -0
  308. package/test/datahike/test/query_test.cljc +984 -0
  309. package/test/datahike/test/schema_test.cljc +424 -0
  310. package/test/datahike/test/specification_test.cljc +30 -0
  311. package/test/datahike/test/store_test.cljc +78 -0
  312. package/test/datahike/test/stress_test.cljc +57 -0
  313. package/test/datahike/test/time_variance_test.cljc +518 -0
  314. package/test/datahike/test/tools_test.clj +134 -0
  315. package/test/datahike/test/transact_test.cljc +518 -0
  316. package/test/datahike/test/tuples_test.cljc +564 -0
  317. package/test/datahike/test/unstructured_test.cljc +291 -0
  318. package/test/datahike/test/upsert_impl_test.cljc +205 -0
  319. package/test/datahike/test/upsert_test.cljc +363 -0
  320. package/test/datahike/test/utils.cljc +110 -0
  321. package/test/datahike/test/validation_test.cljc +48 -0
  322. package/test/datahike/test/versioning_test.cljc +56 -0
  323. package/test/datahike/test.cljc +66 -0
  324. package/tests.edn +24 -0
@@ -0,0 +1,515 @@
1
+ (ns datahike.test.attribute-refs.differences-test
2
+ (:require
3
+ #?(:cljs [cljs.test :as t :refer-macros [is deftest testing]]
4
+ :clj [clojure.test :as t :refer [is deftest testing]])
5
+ [clojure.set :refer [difference]]
6
+ [datahike.api :as d]
7
+ [datahike.constants :as const]
8
+ [datahike.db :as db :refer [ref-datoms]]
9
+ [datahike.db.interface :as dbi]
10
+ [datahike.test.core-test]
11
+ [datahike.test.utils :refer [get-time]])
12
+ #?(:clj (:import [datahike.datom Datom])))
13
+
14
+ #?(:cljs (def Throwable js/Error))
15
+
16
+ (def no-ref-cfg
17
+ {:store {:backend :memory :id (random-uuid)}
18
+ :keep-history? true
19
+ :attribute-refs? false
20
+ :schema-flexibility :write})
21
+
22
+ (def ref-cfg
23
+ {:store {:backend :memory :id (random-uuid)}
24
+ :keep-history? true
25
+ :attribute-refs? true
26
+ :schema-flexibility :write})
27
+
28
+ (defn init-cfgs []
29
+ [(assoc-in no-ref-cfg [:store :id] #?(:clj (java.util.UUID/randomUUID) :cljs (random-uuid)))
30
+ (assoc-in ref-cfg [:store :id] #?(:clj (java.util.UUID/randomUUID) :cljs (random-uuid)))])
31
+
32
+ (def name-schema [{:db/ident :name
33
+ :db/cardinality :db.cardinality/one
34
+ :db/valueType :db.type/string}])
35
+
36
+ (defn setup-db [cfg]
37
+ (d/delete-database cfg)
38
+ (d/create-database cfg)
39
+ (d/connect cfg))
40
+
41
+ (defn tx-instant [db]
42
+ (if (get-in db [:config :attribute-refs?])
43
+ (:db/txInstant (:ident-ref-map db))
44
+ :db/txInstant))
45
+
46
+ (deftest test-empty-db
47
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
48
+ conn (setup-db no-ref-cfg)]
49
+ (testing "Empty EAVT index for keyword DB"
50
+ (is (= nil
51
+ (d/datoms @conn :eavt))))
52
+ (testing "Empty AEVT index for keyword DB"
53
+ (is (= nil
54
+ (d/datoms @conn :aevt))))
55
+ (testing "Empty AVET index for keyword DB"
56
+ (is (= nil
57
+ (d/datoms @conn :avet))))
58
+ (d/release conn))
59
+
60
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
61
+ conn (setup-db ref-cfg)]
62
+ (testing "System-datoms in EAVT index for reference DB"
63
+ (is (= (set ref-datoms)
64
+ (set (d/datoms @conn :eavt)))))
65
+ (testing "System-datoms in AEVT index for reference DB"
66
+ (is (= (set ref-datoms)
67
+ (set (d/datoms @conn :aevt)))))
68
+ (testing "System ident and transaction datoms in AVET index for reference DB"
69
+ (let [ref (:ident-ref-map @conn)
70
+ indexed-refs #{(:db/ident ref) (:db/txInstant ref)}]
71
+ (is (= (set (filter (fn [^Datom datom] (contains? indexed-refs (:a datom)))
72
+ ref-datoms))
73
+ (set (d/datoms @conn :avet))))))
74
+ (d/release conn)))
75
+
76
+ (deftest test-last-entity-id ;; TODO: What is the behavior wanted?
77
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
78
+ find-last-entity-id (fn [db]
79
+ (->> (d/datoms db :eavt)
80
+ (remove (fn [datom] (= (tx-instant db) (:a datom))))
81
+ (map :e)
82
+ (concat [-1])
83
+ (apply max)))
84
+ simple-schema [{:db/ident :name
85
+ :db/cardinality :db.cardinality/one
86
+ :db/valueType :db.type/string}]]
87
+ (let [conn (setup-db no-ref-cfg)]
88
+ (testing "Last entity id for empty keyword DB"
89
+ (is (= const/e0 (:max-eid @conn)))
90
+ (is (= -1 (find-last-entity-id @conn))))
91
+
92
+ (testing "Last entity id for non-empty keyword DB"
93
+ (d/transact conn simple-schema)
94
+ (is (= (+ 1 const/e0) (:max-eid @conn)))
95
+ (is (= (+ 1 const/e0) (find-last-entity-id @conn))))
96
+ (d/release conn))
97
+
98
+ (let [conn (setup-db ref-cfg)]
99
+ (testing "Last entity id for empty reference DB"
100
+ (is (= const/ue0 (:max-eid @conn)))
101
+ (is (= const/ue0 (find-last-entity-id @conn))))
102
+
103
+ (testing "Last entity id for non-empty reference DB"
104
+ (d/transact conn simple-schema)
105
+ (is (= (+ 1 const/ue0) (:max-eid @conn)))
106
+ (is (= (+ 1 const/ue0) (find-last-entity-id @conn))))
107
+ (d/release conn))))
108
+
109
+ (deftest test-transact-schema
110
+ (testing "Schema for keyword DB"
111
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
112
+ conn (setup-db no-ref-cfg)]
113
+ (is (= (:schema @conn)
114
+ const/non-ref-implicit-schema))
115
+ (d/transact conn name-schema)
116
+ (is (= (:schema @conn)
117
+ (merge const/non-ref-implicit-schema {:name (first name-schema)} {1 :name})))
118
+ (d/release conn)))
119
+ (testing "Schema for reference DB"
120
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
121
+ conn (setup-db ref-cfg)]
122
+ (is (= (:schema @conn)
123
+ const/ref-implicit-schema))
124
+ (d/transact conn name-schema)
125
+ (is (= (:schema @conn)
126
+ (merge const/ref-implicit-schema
127
+ {:name (first name-schema)}
128
+ {(+ 1 const/ue0) :name})))
129
+ (is (contains? (-> (:rschema @conn) :db/ident) :name))
130
+ (is (contains? (-> (:ident-ref-map @conn) keys set) :name))
131
+ (is (contains? (-> (:ref-ident-map @conn) vals set) :name))
132
+
133
+ (testing "after reconnection"
134
+ (d/release conn)
135
+ (let [conn2 (d/connect ref-cfg)]
136
+ (is (= (:schema @conn2)
137
+ (merge const/ref-implicit-schema
138
+ {:name (first name-schema)}
139
+ {(+ 1 const/ue0) :name})))
140
+ (is (contains? (-> (:rschema @conn2) :db/ident) :name))
141
+ (is (contains? (-> (:ident-ref-map @conn2) keys set) :name))
142
+ (is (contains? (-> (:ref-ident-map @conn2) vals set) :name))
143
+ (d/release conn2))))))
144
+
145
+ (deftest test-transact-tempid
146
+ (testing "Tempid resolution for keyword DB"
147
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
148
+ conn (setup-db no-ref-cfg)]
149
+ (is (= (:tempids (d/transact conn name-schema))
150
+ {:db/current-tx (+ 1 const/tx0)}))
151
+ (is (= (:tempids (d/transact conn [{:db/id -1 :name "Ivan"}]))
152
+ {-1 (+ 2 const/e0), :db/current-tx (+ 2 const/tx0)}))
153
+ (is (= (:tempids (d/transact conn [[:db/add -2 :name "Petr"]]))
154
+ {-2 (+ 3 const/e0), :db/current-tx (+ 3 const/tx0)}))
155
+ (is (= (:tempids (d/transact conn [{:db/id "Serg" :name "Sergey"}]))
156
+ {"Serg" (+ 4 const/e0), :db/current-tx (+ 4 const/tx0)}))
157
+ (d/release conn)))
158
+
159
+ (testing "Tempid resolution for reference DB"
160
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
161
+ conn (setup-db ref-cfg)]
162
+ (is (= (:tempids (d/transact conn name-schema))
163
+ {:db/current-tx (+ 1 const/tx0)}))
164
+ (is (= (:tempids (d/transact conn [{:db/id -1 :name "Ivan"}]))
165
+ {-1 (+ 2 const/ue0), :db/current-tx (+ 2 const/tx0)}))
166
+ (is (= (:tempids (d/transact conn [[:db/add -2 (get-in @conn [:ident-ref-map :name]) "Petr"]]))
167
+ {-2 (+ 3 const/ue0), :db/current-tx (+ 3 const/tx0)}))
168
+ (is (= (:tempids (d/transact conn [{:db/id "Serg" :name "Sergey"}]))
169
+ {"Serg" (+ 4 const/ue0), :db/current-tx (+ 4 const/utx0)}))
170
+ (d/release conn))))
171
+
172
+ (deftest test-system-attr-resolution
173
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
174
+ schema [{:db/ident :name
175
+ :db/cardinality :db.cardinality/one
176
+ :db/valueType :db.type/string}]
177
+ keyword-attrs (fn [datoms] (->> datoms
178
+ (filter (fn [datom] (keyword? (:a datom))))
179
+ (map :a)
180
+ set))]
181
+ (testing "Do not resolve attributes in keyword DB"
182
+ (let [conn (setup-db no-ref-cfg)
183
+ tx-data (:tx-data (d/transact conn schema))]
184
+ (is (= (keyword-attrs tx-data)
185
+ #{:db/ident :db/cardinality :db/valueType :db/txInstant}))
186
+ (d/release conn)))
187
+
188
+ (testing "Resolve attributes in reference DB"
189
+ (let [conn (setup-db ref-cfg)
190
+ tx-data (:tx-data (d/transact conn schema))]
191
+ (is (= (keyword-attrs tx-data)
192
+ #{}))
193
+ (d/release conn)))))
194
+
195
+ (deftest test-system-enum-resolution
196
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
197
+ schema [{:db/ident :name
198
+ :db/cardinality :db.cardinality/one
199
+ :db/valueType :db.type/string}]
200
+ unresolved-enums (fn [datoms] (->> datoms
201
+ (filter (fn [datom] (keyword? (:v datom))))
202
+ (map :v)
203
+ set))]
204
+ (testing "Do not resolve enums in keyword DB"
205
+ (let [conn (setup-db no-ref-cfg)
206
+ tx-data (:tx-data (d/transact conn schema))]
207
+ (is (= (unresolved-enums tx-data)
208
+ #{:name :db.cardinality/one :db.type/string}))
209
+ (d/release conn)))
210
+
211
+ (testing "Resolve enums in reference DB"
212
+ (let [conn (setup-db ref-cfg)
213
+ tx-data (:tx-data (d/transact conn schema))]
214
+ (is (= (unresolved-enums tx-data)
215
+ #{:name}))
216
+ (d/release conn)))))
217
+
218
+ (deftest test-store-db-id-as-keyword
219
+ (doseq [cfg (init-cfgs)]
220
+ (testing "Do not resolve enums in keyword DB"
221
+ (let [conn (setup-db cfg)]
222
+ (d/transact conn [{:db/ident :attribute-to-use
223
+ :db/cardinality :db.cardinality/one
224
+ :db/valueType :db.type/keyword}])
225
+ (d/transact conn [{:attribute-to-use :the-location}
226
+ {:attribute-to-use :db/id}])
227
+ (is (= #{[:the-location]
228
+ [:db/id]}
229
+ (d/q '[:find ?v
230
+ :in $ ?a
231
+ :where
232
+ [_ :attribute-to-use ?v]]
233
+ @conn)))
234
+ (d/release conn)))))
235
+
236
+ (deftest test-indexing
237
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
238
+ schema [{:db/ident :name
239
+ :db/cardinality :db.cardinality/one
240
+ :db/index true
241
+ :db/valueType :db.type/string}
242
+ {:db/ident :age
243
+ :db/cardinality :db.cardinality/one
244
+ :db/valueType :db.type/long}]
245
+ tx1 [{:name "Alice"
246
+ :age 10}]
247
+ avet-a-v (fn [db] (->> (d/datoms db :avet)
248
+ (map (fn [datom] [(:a datom) (:v datom)]))
249
+ (remove (fn [[a _]] (= a (tx-instant db))))
250
+ set))]
251
+ (testing "Entry in avet index only when indexing true for keyword DB"
252
+ (let [conn (setup-db no-ref-cfg)]
253
+ (d/transact conn schema)
254
+ (is (= (avet-a-v @conn)
255
+ #{[:db/ident :age] [:db/ident :name]}))
256
+ (d/transact conn tx1)
257
+ (is (= (avet-a-v @conn)
258
+ #{[:db/ident :age] [:db/ident :name] [:name "Alice"]}))
259
+ (d/release conn)))
260
+
261
+ (testing "Entry in avet index only when indexing true for reference DB"
262
+ (let [conn (setup-db ref-cfg)
263
+ initial-avet (avet-a-v @conn)
264
+ ref (fn [ident] (get-in @conn [:ident-ref-map ident]))]
265
+ (d/transact conn schema)
266
+ (is (= (difference (avet-a-v @conn) initial-avet)
267
+ #{[1 :age] [1 :name]}))
268
+ (d/transact conn tx1)
269
+ (is (= (difference (avet-a-v @conn) initial-avet)
270
+ #{[(ref :name) "Alice"] [1 :age] [1 :name]}))
271
+ (d/release conn)))))
272
+
273
+ (deftest test-transact-nested-data
274
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
275
+ schema [{:db/ident :name
276
+ :db/cardinality :db.cardinality/one
277
+ :db/unique :db.unique/identity
278
+ :db/valueType :db.type/string}
279
+ {:db/ident :sibling
280
+ :db/cardinality :db.cardinality/many
281
+ :db/valueType :db.type/ref}]
282
+ find-alices (fn [db] (d/q '[:find ?e :where [?e :name "Alice"]] db))
283
+ find-bobs (fn [db] (d/q '[:find ?e :where [?e :name "Bob"]] db))
284
+ tx1 [{:name "Alice"}]
285
+ tx2 [{:name "Charlie"
286
+ :sibling [{:name "Alice"} {:name "Bob"}]}]]
287
+ (testing "Resolve nesting in keyword DB"
288
+ (let [conn (setup-db no-ref-cfg)]
289
+ (d/transact conn (vec (concat schema tx1)))
290
+ (d/transact conn tx2)
291
+ (is (= 1 (count (find-alices @conn))))
292
+ (is (= 1 (count (find-bobs @conn))))
293
+ (d/release conn)))
294
+
295
+ (testing "Resolve nesting in reference DB"
296
+ (let [conn (setup-db ref-cfg)]
297
+ (d/transact conn (vec (concat schema tx1)))
298
+ (d/transact conn tx2)
299
+ (is (= 1 (count (find-alices @conn))))
300
+ (is (= 1 (count (find-bobs @conn))))
301
+ (d/release conn)))))
302
+
303
+ (deftest test-transact-data-with-keyword-attr
304
+ (testing "Keyword transaction in keyword DB"
305
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
306
+ conn (setup-db no-ref-cfg)
307
+ next-eid (inc (:max-eid @conn))]
308
+ (is (not (nil? (d/transact conn [[:db/add next-eid :db/ident :name]]))))
309
+ (d/release conn)))
310
+
311
+ (testing "Using :db/ident attribute"
312
+ (doseq [cfg (init-cfgs)
313
+ :let [attribute-refs? (:attribute-refs? cfg)
314
+ conn (setup-db cfg)
315
+ next-eid (inc (:max-eid @conn))
316
+ init-datoms (d/datoms
317
+ @conn
318
+ {:index :aevt
319
+ :components [:db/ident]})]]
320
+
321
+ ;; Check that the database with attribute-refs? being true
322
+ ;; contains some initial atoms, and otherwise none.
323
+ (is (= (boolean (seq init-datoms))
324
+ (boolean attribute-refs?)))
325
+
326
+ ;; Transact a datom for attribute :db/ident. This
327
+ ;; must work no matter the value of :attribute-refs?
328
+ (is (some? (d/transact
329
+ conn
330
+ [[:db/add next-eid :db/ident :name]])))
331
+
332
+ ;; Check that we can access the datom just transacted
333
+ ;; using d/datoms.
334
+ (let [datoms (d/datoms @conn
335
+ {:index :aevt
336
+ :components [:db/ident]})]
337
+ (is (= (inc (count init-datoms))
338
+ (count datoms)))
339
+ (is (some (fn [[_ a v]]
340
+ (and (= v :name)
341
+ (or attribute-refs?
342
+ (= a :db/ident))))
343
+ datoms)))
344
+
345
+ ;; Check for a more specific query.
346
+ (let [[ident-name-datom :as ident-name-datoms]
347
+ (d/datoms @conn
348
+ {:index :avet
349
+ :components [:db/ident
350
+ :name]})]
351
+ (is (= 1 (count ident-name-datoms)))
352
+ (is (= :name (:v ident-name-datom)))
353
+ (is (or attribute-refs?
354
+ (= :db/ident (:a ident-name-datom)))))
355
+ (d/release conn))))
356
+
357
+ (deftest test-transact-data-with-reference-attr
358
+ (testing "Reference transaction in keyword DB"
359
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
360
+ conn (setup-db no-ref-cfg)
361
+ next-eid (inc (:max-eid @conn))]
362
+ (is (thrown-with-msg? Throwable
363
+ (re-pattern (str "Bad entity attribute 1"
364
+ " at \\[:db/add " next-eid " 1 :name\\],"
365
+ " expected keyword or string"))
366
+ (d/transact conn [[:db/add next-eid 1 :name]])))
367
+ (d/release conn)))
368
+
369
+ (testing "Reference transaction in reference DB"
370
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
371
+ conn (setup-db ref-cfg)
372
+ next-eid (inc (:max-eid @conn))]
373
+ (is (not (nil? (d/transact conn [[:db/add next-eid 1 :name]]))))
374
+ (d/release conn))))
375
+
376
+ (deftest test-system-schema-protection
377
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
378
+ conn (setup-db ref-cfg)]
379
+ (testing "Transact sequential system schema update"
380
+ (is (thrown-with-msg? Throwable
381
+ #"System schema entity cannot be changed"
382
+ (d/transact conn [[:db/add 1 1 :name]]))))
383
+
384
+ (testing "Transact system schema update as map"
385
+ (is (thrown-with-msg? Throwable
386
+ #"Entity with ID 1 is a system attribute :db/ident and cannot be changed"
387
+ (d/transact conn [{:db/id 1 :db/ident :name}]))))
388
+ (d/release conn)))
389
+
390
+ (deftest test-system-attribute-protection
391
+ (testing "Use system keyword for schema in keyword DB"
392
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
393
+ conn (setup-db no-ref-cfg)]
394
+ (is (thrown-with-msg? Throwable #"Using namespace 'db' for attribute identifiers is not allowed"
395
+ (d/transact conn [{:db/ident :db/unique}])))
396
+ (d/release conn)))
397
+
398
+ (testing "Use system keyword for schema in keyword DB"
399
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
400
+ conn (setup-db ref-cfg)]
401
+ (is (thrown-with-msg? Throwable #"Using namespace 'db' for attribute identifiers is not allowed"
402
+ (d/transact conn [{:db/ident :db/unique}])))
403
+ (d/release conn))))
404
+
405
+ (deftest test-system-enum-protection
406
+ (testing "Use system keyword for schema in keyword DB"
407
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
408
+ conn (setup-db no-ref-cfg)]
409
+ (is (thrown-with-msg? Throwable #"Using namespace 'db' for attribute identifiers is not allowed"
410
+ (d/transact conn [{:db/ident :db.cardinality/many}])))
411
+ (d/release conn)))
412
+
413
+ (testing "Use system keyword for schema in keyword DB"
414
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
415
+ conn (setup-db ref-cfg)]
416
+ (is (thrown-with-msg? Throwable #"Using namespace 'db' for attribute identifiers is not allowed"
417
+ (d/transact conn [{:db/ident :db.cardinality/many}])))
418
+ (d/release conn))))
419
+
420
+ (deftest test-read-schema
421
+ (testing "No error in combination with schema-flexibility read for keyword DB"
422
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
423
+ read-no-ref-cfg (assoc no-ref-cfg :schema-flexibility :read)]
424
+ (db/empty-db nil read-no-ref-cfg)
425
+ (db/init-db [] nil read-no-ref-cfg)))
426
+
427
+ (testing "Error in combination with schema-flexibility read for reference DB"
428
+ (let [read-ref-cfg (assoc ref-cfg :schema-flexibility :read)]
429
+ (is (thrown-with-msg? Throwable
430
+ #"Attribute references cannot be used with schema-flexibility ':read'."
431
+ (db/empty-db nil read-ref-cfg)))
432
+ (is (thrown-with-msg? Throwable
433
+ #"Attribute references cannot be used with schema-flexibility ':read'."
434
+ (db/init-db [] nil read-ref-cfg))))))
435
+
436
+ (deftest test-query
437
+ (testing "Query keyword translation keyword db"
438
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
439
+ conn (setup-db no-ref-cfg)
440
+ schema [{:db/ident :name
441
+ :db/cardinality :db.cardinality/one
442
+ :db/valueType :db.type/string}]
443
+ ref (fn [ident] (dbi/-ref-for @conn ident))]
444
+ (d/transact conn schema)
445
+ (d/transact conn [{:name "Alice"}
446
+ {:name "Bob"}])
447
+ (is (= #{["Alice"] ["Bob"]}
448
+ (d/q '[:find ?n :in $ ?a :where [_ ?a ?n]] @conn :name)))
449
+ (is (= #{["Alice"] ["Bob"]}
450
+ (d/q '[:find ?n :in $ ?a :where [_ ?a ?n]] @conn (ref :name))))
451
+ (is (= #{["Alice"] ["Bob"]}
452
+ (d/q '[:find ?n :in $ :where [_ :name ?n]] @conn)))
453
+ (is (= #{}
454
+ (d/q '[:find ?n :in $ :where [_ ?a ?n] [?a :db/ident :name]] @conn)))
455
+ (is (= #{["Alice"] ["Bob"]}
456
+ (d/q '[:find ?n :in $ ?a :where [_ ?a ?n]] @conn :name)))
457
+ (d/release conn)))
458
+
459
+ (testing "Query keyword translation reference db"
460
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
461
+ conn (setup-db ref-cfg)
462
+ schema [{:db/ident :name
463
+ :db/cardinality :db.cardinality/one
464
+ :db/valueType :db.type/string}]
465
+ ref (fn [ident] (dbi/-ref-for @conn ident))]
466
+ (d/transact conn schema)
467
+ (d/transact conn [{:name "Alice"}
468
+ {:name "Bob"}])
469
+ (is (= #{["Alice"] ["Bob"]}
470
+ (d/q '[:find ?n :in $ ?a :where [_ ?a ?n]] @conn :name)))
471
+ (is (= #{["Alice"] ["Bob"]}
472
+ (d/q '[:find ?n :in $ ?a :where [_ ?a ?n]] @conn (ref :name))))
473
+ (is (= #{["Alice"] ["Bob"]}
474
+ (d/q '[:find ?n :in $ :where [_ :name ?n]] @conn)))
475
+ (is (= #{["Alice"] ["Bob"]}
476
+ (d/q '[:find ?n :in $ :where [_ ?a ?n] [?a :db/ident :name]] @conn)))
477
+ (is (= #{["Alice"] ["Bob"]}
478
+ (d/q '[:find ?n :in $ ?a :where [_ ?a ?n]] @conn :name)))
479
+ (d/release conn))))
480
+
481
+ (deftest test-pull-ref-db
482
+ (let [[no-ref-cfg ref-cfg] (init-cfgs)
483
+ conn (setup-db ref-cfg)
484
+ schema [{:db/ident :name
485
+ :db/cardinality :db.cardinality/one
486
+ :db/valueType :db.type/string}
487
+ {:db/ident :aka
488
+ :db/cardinality :db.cardinality/many
489
+ :db/valueType :db.type/string}
490
+ {:db/ident :child
491
+ :db/cardinality :db.cardinality/many
492
+ :db/valueType :db.type/ref}
493
+ {:db/ident :father
494
+ :db/cardinality :db.cardinality/one
495
+ :db/valueType :db.type/ref}]
496
+ _ (d/transact conn schema)
497
+ _ (d/transact conn [{:name "Ivan"
498
+ :aka ["Devil" "Tupen"]}])
499
+ ivan (ffirst (d/q '[:find ?e :where [?e :name "Ivan"]] @conn))
500
+ _ (d/transact conn [{:name "Matthew"
501
+ :father ivan}])
502
+ matthew (ffirst (d/q '[:find ?e :where [?e :name "Matthew"]] @conn))]
503
+
504
+ (is (= {:name "Ivan" :aka ["Devil" "Tupen"]}
505
+ (d/pull @conn '[:name :aka] ivan)))
506
+
507
+ (is (= {:name "Matthew" :father {:db/id ivan} :db/id matthew}
508
+ (d/pull @conn '[:name :father :db/id] matthew)))
509
+
510
+ (is (= [{:name "Ivan"} {:name "Matthew"}]
511
+ (d/pull-many @conn '[:name] [ivan matthew])))
512
+
513
+ (is (= {:name "Ivan" :_father [{:db/id matthew}]}
514
+ (d/pull @conn '[:name :_father] ivan)))
515
+ (d/release conn)))
@@ -0,0 +1,89 @@
1
+ (ns datahike.test.attribute-refs.entity-test
2
+ (:require
3
+ [#?(:cljs cljs.reader :clj clojure.edn) :as edn]
4
+ #?(:cljs [cljs.test :as t :refer-macros [is deftest testing]]
5
+ :clj [clojure.test :as t :refer [is deftest testing]])
6
+ [datahike.api :as d]
7
+ [datahike.impl.entity :as de]
8
+ [datahike.test.attribute-refs.utils :refer [ref-db ref-e0 shift-entities]]
9
+ [datahike.test.core-test :as tdc]))
10
+
11
+ #?(:cljs (def Throwable js/Error))
12
+
13
+ (t/use-fixtures :once tdc/no-namespace-maps)
14
+
15
+ (deftest test-entity
16
+ (let [entities [{:db/id 1, :name "Ivan", :age 19, :aka ["X" "Y"]}
17
+ {:db/id 2, :name "Petr", :sex "male", :aka ["Z"]}]
18
+ db (d/db-with ref-db (shift-entities ref-e0 entities))
19
+ e (d/entity db (+ ref-e0 1))]
20
+ (is (= (:db/id e) (+ ref-e0 1)))
21
+ (is (identical? (d/entity-db e) db))
22
+ (is (= (:name e) "Ivan"))
23
+ (is (= (e :name) "Ivan")) ; IFn form
24
+ (is (= (:age e) 19))
25
+ (is (= (:aka e) #{"X" "Y"}))
26
+ (is (= true (contains? e :age)))
27
+ (is (= false (contains? e :not-found)))
28
+ (is (= (into {} e)
29
+ {:name "Ivan", :age 19, :aka #{"X" "Y"}}))
30
+ (is (= (into {} (d/entity db (+ ref-e0 1)))
31
+ {:name "Ivan", :age 19, :aka #{"X" "Y"}}))
32
+ (is (= (into {} (d/entity db (+ ref-e0 2)))
33
+ {:name "Petr", :sex "male", :aka #{"Z"}}))
34
+
35
+ (is (= (pr-str (d/entity db 1)) "{:db/id 1}"))
36
+ (is (= (pr-str (let [e (d/entity db 1)] (:unknown e) e))
37
+ (str "{:db/id 1}")))
38
+ ;; read back in to account for unordered-ness
39
+ (is (= (edn/read-string (pr-str (let [e (d/entity db (+ ref-e0 1))] (:name e) e)))
40
+ (edn/read-string (str "{:name \"Ivan\", :db/id " (+ ref-e0 1) "}"))))))
41
+
42
+ (deftest test-entity-refs
43
+ (let [db (d/db-with ref-db
44
+ [{:db/id (+ ref-e0 1) :children [(+ ref-e0 10)]}
45
+ {:db/id (+ ref-e0 10) :father (+ ref-e0 1) :children [(+ ref-e0 100) (+ ref-e0 101)]}
46
+ {:db/id (+ ref-e0 100) :father (+ ref-e0 10)}
47
+ {:db/id (+ ref-e0 101) :father (+ ref-e0 10)}])
48
+ e #(d/entity db (+ ref-e0 %))]
49
+
50
+ (is (= (:children (e 1)) #{(e 10)}))
51
+ (is (= (:children (e 10)) #{(e 100) (e 101)}))
52
+
53
+ (testing "empty attribute"
54
+ (is (= (:children (e 100)) nil)))
55
+
56
+ (testing "nested navigation"
57
+ (is (= (-> (e 1) :children first :children) #{(e 100) (e 101)}))
58
+ (is (= (-> (e 10) :children first :father) (e 10)))
59
+ (is (= (-> (e 10) :father :children) #{(e 10)}))
60
+
61
+ (testing "after touch"
62
+ (let [e1 (e 1)
63
+ e10 (e 10)]
64
+ (de/touch e1)
65
+ (de/touch e10)
66
+ (is (= (-> e1 :children first :children) #{(e 100) (e 101)}))
67
+ (is (= (-> e10 :children first :father) (e 10)))
68
+ (is (= (-> e10 :father :children) #{(e 10)})))))
69
+
70
+ (testing "backward navigation"
71
+ (is (= (:_children (e 1)) nil))
72
+ (is (= (:_father (e 1)) #{(e 10)}))
73
+ (is (= (:_children (e 10)) #{(e 1)}))
74
+ (is (= (:_father (e 10)) #{(e 100) (e 101)}))
75
+ (is (= (-> (e 100) :_children first :_children) #{(e 1)})))))
76
+
77
+ (deftest test-entity-misses
78
+ (let [entities (shift-entities ref-e0
79
+ [{:db/id 1, :name "Ivan"}
80
+ {:db/id 2, :name "Oleg"}])
81
+ db (d/db-with ref-db entities)]
82
+
83
+ (is (nil? (d/entity db nil)))
84
+ (is (nil? (d/entity db "abc")))
85
+ (is (nil? (d/entity db :keyword)))
86
+ (is (nil? (d/entity db [:name "Petr"])))
87
+ (is (= 777 (:db/id (d/entity db 777))))
88
+ (is (thrown-with-msg? Throwable #"Lookup ref attribute should be marked as :db/unique:"
89
+ (d/entity db [:not-an-attr 777])))))