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,474 @@
1
+ (ns datahike.test.pull-api-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
+ [datahike.api :as d]
6
+ [datahike.db :as db]
7
+ [datahike.datom :as dd]
8
+ [datahike.pull-api :as p]
9
+ [datahike.constants :refer [tx0]]
10
+ [datahike.test.core-test]
11
+ [datalog.parser.pull :as dpp]))
12
+
13
+ (def test-schema
14
+ {:aka {:db/cardinality :db.cardinality/many}
15
+ :child {:db/cardinality :db.cardinality/many
16
+ :db/valueType :db.type/ref}
17
+ :friend {:db/cardinality :db.cardinality/many
18
+ :db/valueType :db.type/ref}
19
+ :enemy {:db/cardinality :db.cardinality/many
20
+ :db/valueType :db.type/ref}
21
+ :father {:db/valueType :db.type/ref}
22
+ :part {:db/valueType :db.type/ref
23
+ :db/isComponent true
24
+ :db/cardinality :db.cardinality/many}
25
+ :spec {:db/valueType :db.type/ref
26
+ :db/isComponent true
27
+ :db/cardinality :db.cardinality/one}})
28
+
29
+ (def test-datoms
30
+ (->>
31
+ [[1 :name "Petr"]
32
+ [1 :aka "Devil"]
33
+ [1 :aka "Tupen"]
34
+ [2 :name "David"]
35
+ [3 :name "Thomas"]
36
+ [4 :name "Lucy"]
37
+ [5 :name "Elizabeth"]
38
+ [6 :name "Matthew"]
39
+ [7 :name "Eunan"]
40
+ [8 :name "Kerri"]
41
+ [9 :name "Rebecca"]
42
+ [1 :child 2]
43
+ [1 :child 3]
44
+ [2 :father 1]
45
+ [3 :father 1]
46
+ [6 :father 3]
47
+ [10 :name "Part A"]
48
+ [11 :name "Part A.A"]
49
+ [10 :part 11]
50
+ [12 :name "Part A.A.A"]
51
+ [11 :part 12]
52
+ [13 :name "Part A.A.A.A"]
53
+ [12 :part 13]
54
+ [14 :name "Part A.A.A.B"]
55
+ [12 :part 14]
56
+ [15 :name "Part A.B"]
57
+ [10 :part 15]
58
+ [16 :name "Part A.B.A"]
59
+ [15 :part 16]
60
+ [17 :name "Part A.B.A.A"]
61
+ [16 :part 17]
62
+ [18 :name "Part A.B.A.B"]
63
+ [16 :part 18]]
64
+ (map (fn [[e a v]] (dd/datom e a v tx0)))))
65
+
66
+ (def test-db (db/init-db test-datoms test-schema))
67
+
68
+ (deftest test-pull-attr-spec
69
+ (is (= {:name "Petr" :aka ["Devil" "Tupen"]}
70
+ (d/pull test-db '[:name :aka] 1)))
71
+
72
+ (is (= {:name "Matthew" :father {:db/id 3} :db/id 6}
73
+ (d/pull test-db '[:name :father :db/id] 6)))
74
+
75
+ (is (= [{:name "Petr"} {:name "Elizabeth"}
76
+ {:name "Eunan"} {:name "Rebecca"}]
77
+ (d/pull-many test-db '[:name] [1 5 7 9]))))
78
+
79
+ (deftest test-pull-reverse-attr-spec
80
+ (is (= {:name "David" :_child [{:db/id 1}]}
81
+ (d/pull test-db '[:name :_child] 2)))
82
+
83
+ (is (= {:name "David" :_child [{:name "Petr"}]}
84
+ (d/pull test-db '[:name {:_child [:name]}] 2)))
85
+
86
+ (testing "Reverse non-component references yield collections"
87
+ (is (= {:name "Thomas" :_father [{:db/id 6}]}
88
+ (d/pull test-db '[:name :_father] 3)))
89
+
90
+ (is (= {:name "Petr" :_father [{:db/id 2} {:db/id 3}]}
91
+ (d/pull test-db '[:name :_father] 1)))
92
+
93
+ (is (= {:name "Thomas" :_father [{:name "Matthew"}]}
94
+ (d/pull test-db '[:name {:_father [:name]}] 3)))
95
+
96
+ (is (= {:name "Petr" :_father [{:name "David"} {:name "Thomas"}]}
97
+ (d/pull test-db '[:name {:_father [:name]}] 1)))))
98
+
99
+ (deftest test-pull-component-attr
100
+ (let [parts {:name "Part A",
101
+ :part
102
+ [{:db/id 11
103
+ :name "Part A.A",
104
+ :part
105
+ [{:db/id 12
106
+ :name "Part A.A.A",
107
+ :part
108
+ [{:db/id 13 :name "Part A.A.A.A"}
109
+ {:db/id 14 :name "Part A.A.A.B"}]}]}
110
+ {:db/id 15
111
+ :name "Part A.B",
112
+ :part
113
+ [{:db/id 16
114
+ :name "Part A.B.A",
115
+ :part
116
+ [{:db/id 17 :name "Part A.B.A.A"}
117
+ {:db/id 18 :name "Part A.B.A.B"}]}]}]}
118
+ rpart (update-in parts [:part 0 :part 0 :part]
119
+ (partial into [{:db/id 10}]))
120
+ recdb (db/init-db
121
+ (concat test-datoms [(dd/datom 12 :part 10)])
122
+ test-schema)
123
+
124
+ mutdb (db/init-db
125
+ (concat test-datoms [(dd/datom 12 :part 10)
126
+ (dd/datom 12 :spec 10)
127
+ (dd/datom 10 :spec 13)
128
+ (dd/datom 13 :spec 12)])
129
+ test-schema)]
130
+
131
+ (testing "Component entities are expanded recursively"
132
+ (is (= parts (d/pull test-db '[:name :part] 10))))
133
+
134
+ (testing "Reverse component references yield a single result"
135
+ (is (= {:name "Part A.A" :_part {:db/id 10}}
136
+ (d/pull test-db [:name :_part] 11)))
137
+
138
+ (is (= {:name "Part A.A" :_part {:name "Part A"}}
139
+ (d/pull test-db [:name {:_part [:name]}] 11))))
140
+
141
+ (testing "Like explicit recursion, expansion will not allow loops"
142
+ (is (= rpart (d/pull recdb '[:name :part] 10))))))
143
+
144
+ (deftest test-pull-wildcard-pattern
145
+ (is (= {:db/id 1 :name "Petr" :aka ["Devil" "Tupen"]
146
+ :child [{:db/id 2} {:db/id 3}]}
147
+ (d/pull test-db '[*] 1)))
148
+
149
+ (is (= {:db/id 2 :name "David" :_child [{:db/id 1}] :father {:db/id 1}}
150
+ (d/pull test-db '[* :_child] 2))))
151
+
152
+ (deftest test-pull-limit
153
+ (let [db (db/init-db
154
+ (concat
155
+ test-datoms
156
+ [(dd/datom 4 :friend 5)
157
+ (dd/datom 4 :friend 6)
158
+ (dd/datom 4 :friend 7)
159
+ (dd/datom 4 :friend 8)]
160
+ (for [idx (range 2000)]
161
+ (dd/datom 8 :aka (str "aka-" idx))))
162
+ test-schema)]
163
+
164
+ (testing "Without an explicit limit, the default is 1000"
165
+ (is (= 1000 (->> (d/pull db '[:aka] 8) :aka count))))
166
+
167
+ (testing "Explicit limit can reduce the default"
168
+ (is (= 500 (->> (d/pull db '[(limit :aka 500)] 8) :aka count)))
169
+ (is (= 500 (->> (d/pull db '[[:aka :limit 500]] 8) :aka count))))
170
+
171
+ (testing "Explicit limit can increase the default"
172
+ (is (= 1500 (->> (d/pull db '[(limit :aka 1500)] 8) :aka count))))
173
+
174
+ (testing "A nil limit produces unlimited results"
175
+ (is (= 2000 (->> (d/pull db '[(limit :aka nil)] 8) :aka count))))
176
+
177
+ (testing "Limits can be used as map specification keys"
178
+ (is (= {:name "Lucy"
179
+ :friend [{:name "Elizabeth"} {:name "Matthew"}]}
180
+ (d/pull db '[:name {(limit :friend 2) [:name]}] 4))))))
181
+
182
+ (deftest test-pull-default
183
+ (testing "Empty results return nil"
184
+ (is (nil? (d/pull test-db '[:foo] 1))))
185
+
186
+ (testing "A default can be used to replace nil results"
187
+ (is (= {:foo "bar"}
188
+ (d/pull test-db '[(default :foo "bar")] 1)))
189
+ (is (= {:foo "bar"}
190
+ (d/pull test-db '[[:foo :default "bar"]] 1)))))
191
+
192
+ (deftest test-pull-as
193
+ (is (= {"Name" "Petr", :alias ["Devil" "Tupen"]}
194
+ (d/pull test-db '[[:name :as "Name"] [:aka :as :alias]] 1))))
195
+
196
+ (deftest test-pull-attr-with-opts
197
+ (is (= {"Name" "Nothing"}
198
+ (d/pull test-db '[[:x :as "Name" :default "Nothing"]] 1))))
199
+
200
+ (deftest test-pull-map
201
+ (testing "Single attrs yield a map"
202
+ (is (= {:name "Matthew" :father {:name "Thomas"}}
203
+ (d/pull test-db '[:name {:father [:name]}] 6))))
204
+
205
+ (testing "Multi attrs yield a collection of maps"
206
+ (is (= {:name "Petr" :child [{:name "David"}
207
+ {:name "Thomas"}]}
208
+ (d/pull test-db '[:name {:child [:name]}] 1))))
209
+
210
+ (testing "Missing attrs are dropped"
211
+ (is (= {:name "Petr"}
212
+ (d/pull test-db '[:name {:father [:name]}] 1))))
213
+
214
+ (testing "Non matching results are removed from collections"
215
+ (is (= {:name "Petr" :child []}
216
+ (d/pull test-db '[:name {:child [:foo]}] 1))))
217
+
218
+ (testing "Map specs can override component expansion"
219
+ (let [parts {:name "Part A" :part [{:name "Part A.A"} {:name "Part A.B"}]}]
220
+ (is (= parts
221
+ (d/pull test-db '[:name {:part [:name]}] 10)))
222
+
223
+ (is (= parts
224
+ (d/pull test-db '[:name {:part 1}] 10))))))
225
+
226
+ (deftest test-pull-recursion
227
+ (let [db (-> test-db
228
+ (d/db-with [[:db/add 4 :friend 5]
229
+ [:db/add 5 :friend 6]
230
+ [:db/add 6 :friend 7]
231
+ [:db/add 7 :friend 8]
232
+ [:db/add 4 :enemy 6]
233
+ [:db/add 5 :enemy 7]
234
+ [:db/add 6 :enemy 8]
235
+ [:db/add 7 :enemy 4]]))
236
+ friends {:db/id 4
237
+ :name "Lucy"
238
+ :friend
239
+ [{:db/id 5
240
+ :name "Elizabeth"
241
+ :friend
242
+ [{:db/id 6
243
+ :name "Matthew"
244
+ :friend
245
+ [{:db/id 7
246
+ :name "Eunan"
247
+ :friend
248
+ [{:db/id 8
249
+ :name "Kerri"}]}]}]}]}
250
+ enemies {:db/id 4 :name "Lucy"
251
+ :friend
252
+ [{:db/id 5 :name "Elizabeth"
253
+ :friend
254
+ [{:db/id 6 :name "Matthew"
255
+ :enemy [{:db/id 8 :name "Kerri"}]}]
256
+ :enemy
257
+ [{:db/id 7 :name "Eunan"
258
+ :friend
259
+ [{:db/id 8 :name "Kerri"}]
260
+ :enemy
261
+ [{:db/id 4 :name "Lucy"
262
+ :friend [{:db/id 5}]}]}]}]
263
+ :enemy
264
+ [{:db/id 6 :name "Matthew"
265
+ :friend
266
+ [{:db/id 7 :name "Eunan"
267
+ :friend
268
+ [{:db/id 8 :name "Kerri"}]
269
+ :enemy [{:db/id 4 :name "Lucy"
270
+ :friend [{:db/id 5 :name "Elizabeth"}]}]}]
271
+ :enemy
272
+ [{:db/id 8 :name "Kerri"}]}]}]
273
+
274
+ (testing "Infinite recursion"
275
+ (is (= friends (d/pull db '[:db/id :name {:friend ...}] 4))))
276
+
277
+ (testing "Multiple recursion specs in one pattern"
278
+ (is (= enemies (d/pull db '[:db/id :name {:friend 2 :enemy 2}] 4))))
279
+
280
+ (let [db (d/db-with db [[:db/add 8 :friend 4]])]
281
+ (testing "Cycles are handled by returning only the :db/id of entities which have been seen before"
282
+ (is (= (update-in friends (take 8 (cycle [:friend 0]))
283
+ assoc :friend [{:db/id 4 :name "Lucy" :friend [{:db/id 5}]}])
284
+ (d/pull db '[:db/id :name {:friend ...}] 4)))))))
285
+
286
+ (deftest test-dual-recursion
287
+ (let [empty (db/empty-db {:part {:db/valueType :db.type/ref}
288
+ :spec {:db/valueType :db.type/ref}})
289
+ db (d/db-with empty [[:db/add 1 :part 2]
290
+ [:db/add 2 :part 3]
291
+ [:db/add 3 :part 1]
292
+ [:db/add 1 :spec 2]
293
+ [:db/add 2 :spec 1]])]
294
+ (is (= (d/pull db '[:db/id {:part ...} {:spec ...}] 1)
295
+ {:db/id 1,
296
+ :spec {:db/id 2
297
+ :spec {:db/id 1,
298
+ :spec {:db/id 2}, :part {:db/id 2}}
299
+ :part {:db/id 3,
300
+ :part {:db/id 1,
301
+ :spec {:db/id 2},
302
+ :part {:db/id 2}}}}
303
+ :part {:db/id 2
304
+ :spec {:db/id 1, :spec {:db/id 2}, :part {:db/id 2}}
305
+ :part {:db/id 3,
306
+ :part {:db/id 1,
307
+ :spec {:db/id 2},
308
+ :part {:db/id 2}}}}}))))
309
+
310
+ (deftest test-deep-recursion
311
+ (let [start 100
312
+ depth 1500
313
+ txd (mapcat
314
+ (fn [idx]
315
+ [(dd/datom idx :name (str "Person-" idx))
316
+ (dd/datom (dec idx) :friend idx)])
317
+ (range (inc start) depth))
318
+ db (db/init-db (concat
319
+ test-datoms
320
+ [(dd/datom start :name (str "Person-" start))]
321
+ txd)
322
+ test-schema)
323
+ pulled (d/pull db '[:name {:friend ...}] start)
324
+ path (->> [:friend 0]
325
+ (repeat (dec (- depth start)))
326
+ (into [] cat))]
327
+ (is (= (str "Person-" (dec depth))
328
+ (:name (get-in pulled path))))))
329
+
330
+ ;; Helper functions
331
+
332
+ (def empty-frame
333
+ "Needs at least eids, specs, pattern to be assigned"
334
+ {:multi? false
335
+ :state :pattern
336
+ :specs '()
337
+ :recursion {:depth {}, :seen #{}}
338
+ :wildcard? false})
339
+
340
+ (deftest test-pull-spec
341
+ (let [spec (dpp/->PullSpec false {:name {:attr :name}})]
342
+ (is (= (p/pull-spec test-db spec [1] false)
343
+ {:name "Petr"}))
344
+ (is (= (p/pull-spec test-db spec [1] true)
345
+ [{:name "Petr"}]))))
346
+
347
+ (deftest test-pull-pattern
348
+ (let [frame (merge empty-frame
349
+ {:eids [1]
350
+ :specs '([:name {:attr :name}])
351
+ :pattern (dpp/->PullSpec false {})
352
+ :results (transient [])
353
+ :kvps (transient {})})]
354
+ (is (= (p/pull-pattern test-db [frame])
355
+ {:name "Petr"}))))
356
+
357
+ (dpp/->PullSpec false {:name {:attr :name}})
358
+
359
+ (deftest test-pull-pattern-frame
360
+ (let [frame (merge empty-frame
361
+ {:eids [1]
362
+ :specs '([:name {:attr :name}])
363
+ :pattern (dpp/->PullSpec false {})
364
+ :kvps (transient {})})
365
+ ppf (p/pull-pattern-frame test-db [frame])]
366
+ (is (= (count ppf) 1))
367
+ (is (= (persistent! (:kvps (first ppf)))
368
+ {:name "Petr"}))))
369
+
370
+ (deftest test-pull-attr
371
+ (let [frame (merge empty-frame
372
+ {:eids [1]
373
+ :pattern (dpp/->PullSpec false {})
374
+ :kvps (transient {})})
375
+ res (p/pull-attr test-db [:name {:attr :name}] 1 [frame])]
376
+ (is (= (persistent! (:kvps (first res)))
377
+ {:name "Petr"}))))
378
+
379
+ (deftest test-pull-attr-datoms
380
+ (let [datom (dd/datom 1 :name "Petr" 536870912 true)
381
+ opts {:attr :name}
382
+ frame (merge empty-frame
383
+ {:eids [1]
384
+ :pattern (dpp/->PullSpec false {})
385
+ :kvps (transient {})})
386
+ res (p/pull-attr-datoms test-db :name {:attr :name} 1 true [datom] opts [frame])]
387
+ (is (= (persistent! (:kvps (first res)))
388
+ {:name "Petr"}))))
389
+
390
+ (deftest test-pull-wildcard
391
+ (let [frame (merge empty-frame
392
+ {:eids [1]
393
+ :eid 1
394
+ :wildcard? false
395
+ :pattern (dpp/->PullSpec false {})
396
+ :results (transient [])
397
+ :kvps (transient {})})
398
+ res (p/pull-wildcard test-db frame nil)]
399
+ (is (= (persistent! (:kvps (first res)))
400
+ {:db/id 1, :aka ["Devil" "Tupen"]}))))
401
+
402
+ (deftest test-pull-wildcard-expand
403
+ (let [pattern (dpp/->PullSpec false {})
404
+ frame {:multi? false,
405
+ :eids [1]
406
+ :state :pattern
407
+ :recursion {:depth {}, :seen #{}},
408
+ :specs '(),
409
+ :wildcard? false,
410
+ :results (transient [])
411
+ :kvps (transient {})
412
+ :pattern pattern}
413
+ res (p/pull-wildcard-expand test-db frame nil 1 pattern)]
414
+ (is (= (persistent! (:kvps (first res)))
415
+ {:db/id 1, :aka ["Devil" "Tupen"]}))))
416
+
417
+ (deftest test-pull-expand-frame
418
+ (let [parent {:state :pattern
419
+ :specs '()
420
+ :results (transient [])
421
+ :kvps (transient {})
422
+ :eids [1]
423
+ :pattern (dpp/->PullSpec false {})}
424
+ frame {:state :expand
425
+ :kvps (transient {})
426
+ :eid 1
427
+ :pattern (dpp/->PullSpec false {})
428
+ :datoms (list [:aka [(dd/datom 1 :aka "Devil" 536870912 true)
429
+ (dd/datom 1 :aka "Tupen" 536870912 true)]]
430
+ [:child [(dd/datom 1 :child 2 536870912 true)
431
+ (dd/datom 1 :child 3 536870912 true)]]
432
+ [:name [(dd/datom 1 :name "Petr" 536870912 true)]])
433
+ :recursion {:depth {}, :seen #{}}}
434
+
435
+ frames (seq [frame parent])
436
+ res (p/pull-expand-frame test-db frames)]
437
+ (is (= (persistent! (:kvps (first res)))
438
+ {:aka ["Devil" "Tupen"]}))
439
+ (is (= (:datoms (first res))
440
+ (list [:child [(dd/datom 1 :child 2 536870912 true)
441
+ (dd/datom 1 :child 3 536870912 true)]]
442
+ [:name [(dd/datom 1 :name "Petr" 536870912 true)]])))))
443
+
444
+ (deftest test-pull-recursion-frame
445
+ (let [db (d/db-with test-db [[:db/add 4 :friend 5]
446
+ [:db/add 5 :friend 6]])
447
+ parent {:state :pattern
448
+ :multi? false
449
+ :eids [5]
450
+ :recursion {:depth {:friend 1} :seen #{5}}
451
+ :specs '()
452
+ :wildcard? false
453
+ :kvps (transient {:db/id 5, :name "Elizabeth"})
454
+ :pattern (dpp/->PullSpec false {}),
455
+ :attr :datahike.pull-api/recursion
456
+ :results (transient [])}
457
+ frame {:state :recursion
458
+ :pattern (dpp/->PullSpec false {:db/id {:attr :db/id}
459
+ :name {:attr :name}
460
+ :friend {:attr :friend, :recursion nil}})
461
+ :attr :friend
462
+ :multi? true
463
+ :eids [6]
464
+ :recursion {:depth {:friend 1}, :seen #{5}}
465
+ :results (transient [])}
466
+ frames (seq [frame parent])
467
+ res (p/pull-recursion-frame db frames)]
468
+ (is (= (:recursion (first res))
469
+ {:depth {:friend 2} :seen #{5 6}}))
470
+ (is (= (:multi? (first res)) false))
471
+ (is (= (:specs (first res))
472
+ '([:db/id {:attr :db/id}]
473
+ [:name {:attr :name}]
474
+ [:friend {:attr :friend :recursion nil}])))))
@@ -0,0 +1,144 @@
1
+ (ns datahike.test.purge-test
2
+ (:require
3
+ #?(:cljs [cljs.test :as t :refer-macros [is are deftest testing]]
4
+ :clj [clojure.test :as t :refer [is are deftest testing]])
5
+ [datahike.api :as d]
6
+ [datahike.test.utils :as tu]))
7
+
8
+ #?(:cljs (def Throwable js/Error))
9
+
10
+ (def schema-tx [{:db/ident :name
11
+ :db/valueType :db.type/string
12
+ :db/unique :db.unique/identity
13
+ :db/index true
14
+ :db/cardinality :db.cardinality/one}
15
+ {:db/ident :age
16
+ :db/valueType :db.type/long
17
+ :db/cardinality :db.cardinality/one}
18
+ {:name "Alice"
19
+ :age 25}
20
+ {:name "Bob"
21
+ :age 35}])
22
+
23
+ (def cfg-template {:store {:backend :memory
24
+ :id #uuid "001b0000-0000-0000-0000-00000000001b"}
25
+ :keep-history? true
26
+ :schema-flexibility :write
27
+ :initial-tx schema-tx})
28
+
29
+ (defn find-age [db name]
30
+ (d/q '[:find ?a . :in $ ?n :where [?e :name ?n] [?e :age ?a]] db name))
31
+
32
+ (defn find-entity [db name]
33
+ (d/q '[:find (pull ?e [:name :age]) :in $ ?n :where [?e :name ?n]] db name))
34
+
35
+ (defn find-entities [db]
36
+ (into #{}
37
+ (d/q '[:find [(pull ?e [:name :age]) ...] :where [?e :name _]] db)))
38
+
39
+ (deftest test-purge
40
+ (let [conn (tu/setup-db (assoc-in cfg-template [:store :id] #uuid "09000000-0000-0000-0000-000000000001"))]
41
+ (testing "retract datom, data is removed from current db and found in history"
42
+ (let [name "Alice"]
43
+ (d/transact conn [[:db/retract [:name name] :age 25]])
44
+ (are [x y] (= x y)
45
+ true (nil? (find-age @conn name))
46
+ 25 (find-age (d/history @conn) name))))
47
+ (testing "purge datom from current index and from history"
48
+ (let [name "Bob"]
49
+ (d/transact conn [[:db/purge [:name name] :age 35]])
50
+ (are [x y] (= x y)
51
+ true (nil? (find-age @conn name))
52
+ true (nil? (find-age (d/history @conn) name)))))
53
+ (testing "purge retracted datom"
54
+ (let [name "Alice"]
55
+ (d/transact conn [[:db/purge [:name name] :age 25]])
56
+ (are [x y] (= x y)
57
+ nil (find-age @conn name)
58
+ nil (find-age (d/history @conn) name))))
59
+ (d/release conn)))
60
+
61
+ (deftest test-purge-attribute
62
+ (let [conn (tu/setup-db (assoc-in cfg-template [:store :id] #uuid "09000000-0000-0000-0000-000000000002"))]
63
+ (testing "purge attribute from current index"
64
+ (let [name "Alice"]
65
+ (d/transact conn [[:db.purge/attribute [:name name] :age]])
66
+ (are [x y] (= x y)
67
+ true (nil? (find-age @conn name))
68
+ true (nil? (find-age (d/history @conn) name))
69
+ #{["Alice"] ["Bob"]} (d/q '[:find ?n :where [_ :name ?n]] @conn))))
70
+ (testing "retract attribute from current index and purge from history"
71
+ (let [name "Bob"]
72
+ (testing "retracting from current index"
73
+ (d/transact conn [[:db.fn/retractAttribute [:name name] :age]])
74
+ (are [x y] (= x y)
75
+ true (nil? (find-age @conn name))
76
+ 35 (find-age (d/history @conn) name)))
77
+ (testing "purging from history"
78
+ (d/transact conn [[:db.purge/entity [:name name] :age]])
79
+ (are [x y] (= x y)
80
+ true (nil? (find-age @conn name))
81
+ true (nil? (find-age (d/history @conn) name))))))
82
+ (d/release conn)))
83
+
84
+ (deftest test-purge-entity
85
+ (let [conn (tu/setup-db (assoc-in cfg-template [:store :id] #uuid "09000000-0000-0000-0000-000000000003"))]
86
+ (testing "purge entity from current index"
87
+ (is (= #{{:name "Alice" :age 25} {:name "Bob" :age 35}} (find-entities @conn)))
88
+ (d/transact conn [[:db.purge/entity [:name "Alice"]]])
89
+ (is (= #{{:name "Bob" :age 35}} (find-entities @conn)))
90
+ (is (= #{{:name "Bob" :age 35}} (find-entities (d/history @conn)))))
91
+ (testing "retract entity from current index and purge from history"
92
+ (let [name "Bob"]
93
+ (testing "retracting from current index"
94
+ (d/transact conn [[:db/retractEntity [:name name]]])
95
+ (is (= #{} (find-entities @conn)))
96
+ (is (= #{{:name "Bob" :age 35}} (find-entities (d/history @conn)))))
97
+ (testing "purging from history"
98
+ (d/transact conn [[:db.purge/entity [:name name]]])
99
+ (is (= #{} (find-entities @conn)))
100
+ (is (= #{} (find-entities (d/history @conn)))))))
101
+ (testing "purge something that is not present in the database"
102
+ (is (thrown-with-msg? Throwable
103
+ #"Can't find entity with ID \[:name \"Alice\"\] to be purged"
104
+ (d/transact conn [[:db.purge/entity [:name "Alice"]]]))))
105
+ (d/release conn)))
106
+
107
+ (deftest test-purge-non-temporal-database
108
+ (let [conn (tu/setup-db (-> (assoc-in cfg-template [:store :id] #uuid "09000000-0000-0000-0000-000000000004")
109
+ (assoc :keep-history? false)))]
110
+ (testing "purge data in non temporal database"
111
+ (is (thrown-with-msg? Throwable #"Purge entity is only available in temporal databases\."
112
+ (d/transact conn [[:db.purge/entity [:name "Alice"]]]))))
113
+ (d/release conn)))
114
+
115
+ (defn find-ages [db name]
116
+ (d/q '[:find ?a ?op
117
+ :in $ ?n
118
+ :where
119
+ [?e :name ?n]
120
+ [?e :age ?a ?t ?op]]
121
+ db
122
+ name))
123
+
124
+ (deftest test-history-purge-before
125
+ (let [conn (tu/setup-db (assoc-in cfg-template [:store :id] #uuid "09000000-0000-0000-0000-000000000005"))
126
+ name "Alice"]
127
+ (testing "remove all historical data before date"
128
+ (is (= #{[25 true]}
129
+ (find-ages @conn name)))
130
+ (let [upsert-date (java.util.Date.)]
131
+ (d/transact conn [{:db/id [:name name] :age 30}])
132
+ (is (= #{[30 true]}
133
+ (find-ages @conn name)))
134
+ (is (= #{[25 true] [25 false] [30 true]}
135
+ (find-ages (d/history @conn) name)))
136
+ (d/transact conn [[:db.history.purge/before upsert-date]])
137
+ (is (= #{[30 true]}
138
+ (find-ages @conn name)))
139
+ (is (= #{[25 false] [30 true]}
140
+ (find-ages (d/history @conn) name)))
141
+ (d/transact conn [[:db.history.purge/before (java.util.Date.)]])
142
+ (is (= #{[30 true]}
143
+ (find-ages (d/history @conn) name)))))
144
+ (d/release conn)))