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,518 @@
1
+ (ns datahike.test.time-variance-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
+ #?(:cljs [datahike.cljs :refer [Throwable]])
7
+ [datahike.constants :as const]
8
+ [datahike.test.utils :as du]
9
+ [datahike.db.interface :as dbi]
10
+ [datahike.test.utils :refer [setup-db sleep]])
11
+ (:import [java.util Date]))
12
+
13
+ (set! *print-namespace-maps* false)
14
+
15
+ (def schema [{:db/ident :name
16
+ :db/valueType :db.type/string
17
+ :db/unique :db.unique/identity
18
+ :db/index true
19
+ :db/cardinality :db.cardinality/one}
20
+ {:db/ident :age
21
+ :db/valueType :db.type/long
22
+ :db/cardinality :db.cardinality/one}
23
+ {:name "Alice"
24
+ :age 25}
25
+ {:name "Bob"
26
+ :age 35}])
27
+
28
+ (def cfg-template {:store {:backend :memory
29
+ :id #uuid "00110000-0000-0000-0000-000000000011"}
30
+ :keep-history? true
31
+ :schema-flexibility :write
32
+ :initial-tx schema})
33
+
34
+ (defn now []
35
+ (Date.))
36
+
37
+ (defn permute-and-repeat [max-repeat elements]
38
+ (let [elements (vec elements)
39
+ n (count elements)]
40
+ (loop [stack [[[] (zipmap (range n) (repeat 0))]]
41
+ result []]
42
+ (if (empty? stack)
43
+ result
44
+ (let [[[fs freqs] & stack] stack]
45
+ (recur (into stack
46
+ (keep (fn [[index counter]]
47
+ (when (< counter max-repeat)
48
+ [(conj fs index) (update freqs index inc)])))
49
+ freqs)
50
+ (if (every? pos? (vals freqs))
51
+ (conj result (mapv #(nth elements %) fs))
52
+ result)))))))
53
+
54
+ (defn vary-db-ops [db & ops]
55
+ {:post [(seq %)
56
+ (<= (count ops) (count %))]}
57
+ (for [fs (permute-and-repeat 2 ops)]
58
+ ((apply comp fs) db)))
59
+
60
+ (deftest test-base-history
61
+ (let [cfg (assoc-in cfg-template [:store :id] #uuid "71000000-0000-0000-0000-000000000001")
62
+ conn (setup-db cfg)
63
+ tx-id0 (:max-tx @conn)]
64
+ (testing "Initial data"
65
+ (is (= #{["Alice" 25] ["Bob" 35]}
66
+ (d/q '[:find ?n ?a :where [?e :name ?n] [?e :age ?a]] @conn))))
67
+
68
+ (testing "historical values"
69
+ (d/transact conn [{:db/id [:name "Alice"] :age 30}])
70
+ (are [x y]
71
+ (= x y)
72
+ #{[30]}
73
+ (d/q '[:find ?a :in $ ?e :where [?e :age ?a]] @conn [:name "Alice"])
74
+ #{[30] [25]}
75
+ (d/q '[:find ?a :in $ ?e :where [?e :age ?a]] (d/history @conn) [:name "Alice"])))
76
+ (testing "historical values after with retraction"
77
+ (let [tx-id1 (:max-tx @conn)
78
+ _ (d/transact conn [[:db/retractEntity [:name "Alice"]]])
79
+ tx-id2 (:max-tx @conn)]
80
+ (is (thrown-with-msg? Throwable #"Nothing found for entity id"
81
+ (d/q '[:find ?a :in $ ?e :where [?e :age ?a]] @conn [:name "Alice"])))
82
+
83
+ (doseq [db (vary-db-ops @conn d/history)]
84
+ (is (= #{[30] [25]}
85
+ (d/q '[:find ?a :in $ ?e :where [?e :age ?a]]
86
+ db
87
+ [:name "Alice"]))))
88
+ (doseq [db (vary-db-ops @conn d/history #(d/as-of % tx-id0))]
89
+ (is (= #{[25]}
90
+ (d/q '[:find ?a :in $ ?e :where [?e :age ?a]]
91
+ db
92
+ [:name "Alice"]))))
93
+ (doseq [db (vary-db-ops @conn d/history #(d/since % tx-id1))]
94
+ (is (= #{[30]}
95
+ (d/q '[:find ?a :in $ ?e :where [?e :age ?a]]
96
+ db
97
+ [:name "Alice"]))))
98
+
99
+ (testing "find retracted values"
100
+ (doseq [db (vary-db-ops @conn d/history)]
101
+ (is (= #{["Alice" 25] ["Alice" 30]}
102
+ (d/q '[:find ?n ?a :where [?r :age ?a _ false] [?r :name ?n _ false]]
103
+ db)))))
104
+ (testing "find source transaction of retracted values"
105
+ (doseq [db (vary-db-ops @conn d/history)]
106
+ (is (= #{[25 true] [25 false] [30 true] [30 false]}
107
+ (d/q '[:find ?a ?op
108
+ :in $ ?e
109
+ :where
110
+ [?e :age ?a ?t ?op]
111
+ [?t :db/txInstant ?d]]
112
+ db
113
+ [:name "Alice"])))))))
114
+ (d/release conn)))
115
+
116
+ (defn replace-commit-id [s]
117
+ (clojure.string/replace s #":commit-id #uuid \"[^\"]+\"" ":commit-id :REPLACED"))
118
+
119
+ (deftest test-historical-queries
120
+ (let [cfg (-> cfg-template
121
+ (assoc-in [:store :id] #uuid "71000000-0000-0000-0000-000000000002"))
122
+ conn (setup-db cfg)]
123
+
124
+ (testing "get all values before specific time"
125
+ (let [_ (d/transact conn [{:db/id [:name "Alice"] :age 30}])
126
+ ;; sleep to make sure that transact thread has older timestamp
127
+ _ (sleep 10)
128
+ date (now)
129
+ ;; sleep to make sure that transact thread has newer timestamp
130
+ _ (sleep 10)
131
+ _ (d/transact conn [{:db/id [:name "Alice"] :age 35}])
132
+ history-db (d/history @conn)
133
+ current-db @conn
134
+ current-query '[:find ?a :in $ ?e :where [?e :age ?a]]
135
+ query '[:find ?a
136
+ :in $ ?e ?fd
137
+ :where
138
+ [?e :age ?a ?tx]
139
+ [?tx :db/txInstant ?t]
140
+ [(before? ?t ?fd)]]
141
+ query-with-< '[:find ?a
142
+ :in $ ?e ?fd
143
+ :where
144
+ [?e :age ?a ?tx]
145
+ [?tx :db/txInstant ?t]
146
+ [(< ?t ?fd)]]]
147
+ (is (= #{[35]}
148
+ (d/q current-query current-db [:name "Alice"])))
149
+ (is (= #{[25] [30]}
150
+ (d/q query history-db [:name "Alice"] date)))
151
+ (is (= #{[25] [30]}
152
+ (d/q query-with-< history-db [:name "Alice"] date)))))
153
+ (testing "print DB"
154
+ (is (= "#datahike/HistoricalDB {:origin #datahike/DB {:store-id [#uuid \"71000000-0000-0000-0000-000000000002\" :db] :commit-id :REPLACED :max-tx 536870915 :max-eid 4}}"
155
+ (replace-commit-id (pr-str (d/history @conn))))))
156
+ (d/release conn)))
157
+
158
+ (deftest test-as-of-db
159
+ (let [cfg (-> cfg-template
160
+ (assoc-in [:store :id] #uuid "71000000-0000-0000-0000-000000000003"))
161
+ conn (setup-db cfg)
162
+ first-date (now)
163
+ ;; sleep to make sure that transact thread has newer timestamp
164
+ _ (sleep 10)
165
+ tx-id 536870914
166
+ query '[:find ?a :in $ ?e :where [?e :age ?a ?tx]]]
167
+ (testing "get values at specific time"
168
+ (is (= #{[25]}
169
+ (d/q query (d/as-of @conn first-date) [:name "Alice"]))))
170
+ (testing "use transaction ID"
171
+ (is (= #{[25]}
172
+ (d/q query (d/as-of @conn tx-id) [:name "Alice"]))))
173
+ (testing "print DB"
174
+ (let [as-of-str (pr-str (d/as-of @conn tx-id))
175
+ origin-str (pr-str (dbi/-origin (d/as-of @conn tx-id)))]
176
+ (is (= "#datahike/AsOfDB {:origin #datahike/DB {:store-id [#uuid \"71000000-0000-0000-0000-000000000003\" :db] :commit-id :REPLACED :max-tx 536870913 :max-eid 4} :time-point 536870914}"
177
+ (replace-commit-id as-of-str)))
178
+ (is (= "#datahike/DB {:store-id [#uuid \"71000000-0000-0000-0000-000000000003\" :db] :commit-id :REPLACED :max-tx 536870913 :max-eid 4}"
179
+ (replace-commit-id origin-str)))
180
+ (is (not= as-of-str origin-str))))
181
+ (testing "retraction"
182
+ (let [find-alices-age '[:find ?a :in $ ?n :where [?e :name ?n] [?e :age ?a]]]
183
+ (testing "before"
184
+ (is (= #{[25]}
185
+ (d/q find-alices-age (d/as-of @conn tx-id) "Alice"))))
186
+ (d/transact conn [[:db/retractEntity [:name "Alice"]]])
187
+ (testing "after"
188
+ (is (= #{}
189
+ (d/q find-alices-age (d/as-of @conn tx-id) "Alice"))))))
190
+ (d/release conn)))
191
+
192
+ (deftest test-since-db
193
+ (let [cfg (-> cfg-template
194
+ (assoc-in [:store :id] #uuid "71000000-0000-0000-0000-000000000004"))
195
+ conn (setup-db cfg)
196
+ first-date (now)
197
+ ;; sleep to make sure that transact thread has newer timestamp
198
+ _ (sleep 10)
199
+ tx-id 536870913
200
+ query '[:find ?a :where [?e :age ?a]]]
201
+ (testing "empty after first insertion"
202
+ (is (= #{}
203
+ (d/q query (d/since @conn first-date)))))
204
+ (testing "added new value"
205
+ (let [new-age 30
206
+ _ (d/transact conn [{:db/id [:name "Alice"] :age new-age}])]
207
+ (is (= #{[new-age]}
208
+ (d/q query (d/since @conn first-date))))
209
+ (is (= #{[new-age]}
210
+ (d/q query (d/since @conn tx-id))))))
211
+ (testing "print DB"
212
+ (is (= "#datahike/SinceDB {:origin #datahike/DB {:store-id [#uuid \"71000000-0000-0000-0000-000000000004\" :db] :commit-id :REPLACED :max-tx 536870914 :max-eid 4} :time-point 536870913}"
213
+ (replace-commit-id (pr-str (d/since @conn tx-id))))))
214
+ (d/release conn)))
215
+
216
+ (deftest test-no-history
217
+ (let [initial-tx [{:db/ident :name
218
+ :db/cardinality :db.cardinality/one
219
+ :db/valueType :db.type/string
220
+ :db/unique :db.unique/identity}
221
+ {:db/ident :age
222
+ :db/cardinality :db.cardinality/one
223
+ :db/valueType :db.type/long
224
+ :db/noHistory true}
225
+ {:name "Alice" :age 25}
226
+ {:name "Bob" :age 35}]
227
+ cfg (-> cfg-template
228
+ (assoc-in [:store :id] #uuid "71000000-0000-0000-0000-000000000005")
229
+ (assoc :initial-tx initial-tx))
230
+ conn (setup-db cfg)
231
+ query '[:find ?n ?a :where [?e :name ?n] [?e :age ?a]]]
232
+ (testing "all names and ages are present in history"
233
+ (is (= #{["Alice" 25] ["Bob" 35]}
234
+ (d/q query (d/history @conn)))))
235
+ (d/transact conn [[:db/retractEntity [:name "Alice"]]])
236
+ (testing "no-history attributes are not present in history"
237
+ (is (= #{["Bob" 35]}
238
+ (d/q query (d/history @conn)))))
239
+ (testing "all other attributes are present in history"
240
+ (is (= #{["Alice"] ["Bob"]}
241
+ (d/q '[:find ?n :where [?e :name ?n]] (d/history @conn)))))
242
+ (d/release conn)))
243
+
244
+ (deftest upsert-history
245
+ (let [cfg {:store {:backend :memory
246
+ :id #uuid "00120000-0000-0000-0000-000000000012"}
247
+ :keep-history? true
248
+ :schema-flexibility :read
249
+ :initial-tx schema}
250
+ conn (setup-db cfg)
251
+ query '[:find ?a ?t ?op
252
+ :where
253
+ [?e :name "Alice"]
254
+ [?e :age ?a ?t ?op]]]
255
+ (testing "add history datoms without upsert operation happening"
256
+ (let [datoms (d/datoms (d/history @conn) {:index :aevt :components [:age [:name "Alice"]]})
257
+ xf (map (comp vec seq))]
258
+ (is (= [[(+ const/e0 3) :age 25 (+ const/tx0 1) true]]
259
+ (into [] xf datoms)))))
260
+ (testing "upsert entity"
261
+ (d/transact conn [[:db/add [:name "Alice"] :age 30]])
262
+ (is (= #{[30 (+ const/tx0 2) true]}
263
+ (d/q query @conn)))
264
+ (is (= #{[25 (+ const/tx0 1) true]
265
+ [25 (+ const/tx0 2) false]
266
+ [30 (+ const/tx0 2) true]}
267
+ (d/q query (d/history @conn)))))
268
+ (testing "second upsert"
269
+ (d/transact conn [[:db/add [:name "Alice"] :age 35]])
270
+ (is (= #{[35 (+ const/tx0 3) true]}
271
+ (d/q query @conn)))
272
+ (is (= #{[25 (+ const/tx0 1) true]
273
+ [25 (+ const/tx0 2) false]
274
+ [30 (+ const/tx0 2) true]
275
+ [30 (+ const/tx0 3) false]
276
+ [35 (+ const/tx0 3) true]}
277
+ (d/q query (d/history @conn)))))
278
+ (testing "re-insert previous value"
279
+ (d/transact conn [[:db/add [:name "Alice"] :age 25]])
280
+ (is (= #{[25 (+ const/tx0 4) true]}
281
+ (d/q query @conn)))
282
+ (is (= #{[25 (+ const/tx0 1) true]
283
+ [25 (+ const/tx0 2) false]
284
+ [30 (+ const/tx0 2) true]
285
+ [30 (+ const/tx0 3) false]
286
+ [35 (+ const/tx0 3) true]
287
+ [35 (+ const/tx0 4) false]
288
+ [25 (+ const/tx0 4) true]}
289
+ (d/q query (d/history @conn)))))
290
+ (testing "retract upserted values"
291
+ (d/transact conn [[:db/retract [:name "Alice"] :age 25]])
292
+ (is (= #{}
293
+ (d/q query @conn)))
294
+ (is (= #{[25 (+ const/tx0 1) true]
295
+ [25 (+ const/tx0 2) false]
296
+ [30 (+ const/tx0 2) true]
297
+ [30 (+ const/tx0 3) false]
298
+ [35 (+ const/tx0 3) true]
299
+ [35 (+ const/tx0 4) false]
300
+ [25 (+ const/tx0 4) true]
301
+ [25 (+ const/tx0 5) false]}
302
+ (d/q query (d/history @conn)))))
303
+ (testing "historical eavt datoms"
304
+ (is (= #{[1 :db/cardinality :db.cardinality/one 536870913 true]
305
+ [1 :db/ident :name 536870913 true]
306
+ [1 :db/index true 536870913 true]
307
+ [1 :db/unique :db.unique/identity 536870913 true]
308
+ [1 :db/valueType :db.type/string 536870913 true]
309
+ [2 :db/cardinality :db.cardinality/one 536870913 true]
310
+ [2 :db/ident :age 536870913 true]
311
+ [2 :db/valueType :db.type/long 536870913 true]
312
+ [3 :age 25 536870913 true]
313
+ [3 :age 25 536870914 false]
314
+ [3 :age 25 536870916 true]
315
+ [3 :age 25 536870917 false]
316
+ [3 :age 30 536870914 true]
317
+ [3 :age 30 536870915 false]
318
+ [3 :age 35 536870915 true]
319
+ [3 :age 35 536870916 false]
320
+ [3 :name "Alice" 536870913 true]
321
+ [4 :age 35 536870913 true]
322
+ [4 :name "Bob" 536870913 true]}
323
+ (->> (d/datoms (d/history @conn) {:index :eavt :components nil})
324
+ (map (comp vec seq))
325
+ (remove (fn [[e _ _ _]]
326
+ (< const/tx0 e)))
327
+ set))))
328
+ (testing "historical aevt datoms"
329
+ (is (= #{[3 :age 25 536870913 true]
330
+ [3 :age 25 536870914 false]
331
+ [3 :age 25 536870916 true]
332
+ [3 :age 25 536870917 false]
333
+ [3 :age 30 536870914 true]
334
+ [3 :age 30 536870915 false]
335
+ [3 :age 35 536870915 true]
336
+ [3 :age 35 536870916 false]
337
+ [4 :age 35 536870913 true]
338
+ [3 :name "Alice" 536870913 true]
339
+ [4 :name "Bob" 536870913 true]
340
+ [1 :db/cardinality :db.cardinality/one 536870913 true]
341
+ [2 :db/cardinality :db.cardinality/one 536870913 true]
342
+ [1 :db/ident :name 536870913 true]
343
+ [2 :db/ident :age 536870913 true]
344
+ [1 :db/index true 536870913 true]
345
+ [1 :db/unique :db.unique/identity 536870913 true]
346
+ [1 :db/valueType :db.type/string 536870913 true]
347
+ [2 :db/valueType :db.type/long 536870913 true]}
348
+ (->> (d/datoms (d/history @conn) {:index :aevt :components nil})
349
+ (map (comp vec seq))
350
+ (remove (fn [[e _ _ _]]
351
+ (< const/tx0 e)))
352
+ set))))
353
+ (testing "historical avet datoms"
354
+ (is (= #{[3 :name "Alice" 536870913 true]
355
+ [4 :name "Bob" 536870913 true]
356
+ [2 :db/ident :age 536870913 true]
357
+ [1 :db/ident :name 536870913 true]}
358
+ (->> (d/datoms (d/history @conn) {:index :avet :components nil})
359
+ (map (comp vec seq))
360
+ (remove (fn [[e _ _ _]]
361
+ (< const/tx0 e)))
362
+ set))))
363
+ (testing "Datoms extracted like Wanderung does it"
364
+ (let [datoms (du/get-all-datoms @conn (map du/unmap-tx-timestamp))]
365
+ (is (= [[536870913 :db/txInstant :timestamp 536870913 true]
366
+ [1 :db/unique :db.unique/identity 536870913 true]
367
+ [1 :db/ident :name 536870913 true]
368
+ [1 :db/valueType :db.type/string 536870913 true]
369
+ [1 :db/index true 536870913 true]
370
+ [1 :db/cardinality :db.cardinality/one 536870913 true]
371
+ [2 :db/valueType :db.type/long 536870913 true]
372
+ [2 :db/cardinality :db.cardinality/one 536870913 true]
373
+ [2 :db/ident :age 536870913 true]
374
+ [3 :name "Alice" 536870913 true]
375
+ [3 :age 25 536870913 true]
376
+ [4 :age 35 536870913 true]
377
+ [4 :name "Bob" 536870913 true]
378
+ [536870914 :db/txInstant :timestamp 536870914 true]
379
+ [3 :age 25 536870914 false]
380
+ [3 :age 30 536870914 true]
381
+ [536870915 :db/txInstant :timestamp 536870915 true]
382
+ [3 :age 30 536870915 false]
383
+ [3 :age 35 536870915 true]
384
+ [536870916 :db/txInstant :timestamp 536870916 true]
385
+ [3 :age 35 536870916 false]
386
+ [3 :age 25 536870916 true]
387
+ [536870917 :db/txInstant :timestamp 536870917 true]
388
+ [3 :age 25 536870917 false]]
389
+ datoms))))))
390
+
391
+ (deftest test-no-duplicates-on-history-search
392
+ (let [schema [{:db/ident :name
393
+ :db/cardinality :db.cardinality/one
394
+ :db/index true
395
+ :db/unique :db.unique/identity
396
+ :db/valueType :db.type/string}
397
+ {:db/ident :sibling
398
+ :db/cardinality :db.cardinality/many
399
+ :db/valueType :db.type/ref}
400
+ {:db/ident :age
401
+ :db/cardinality :db.cardinality/one
402
+ :db/valueType :db.type/long}]
403
+ cfg {:store {:backend :memory :id #uuid "00130000-0000-0000-0000-000000000013"}
404
+ :keep-history? true
405
+ :schema-flexibility :write
406
+ :attribute-refs? false}
407
+ conn (do
408
+ (d/delete-database cfg)
409
+ (d/create-database cfg)
410
+ (d/connect cfg))]
411
+
412
+ (d/transact conn schema)
413
+ (d/transact conn [{:name "Alice"
414
+ :age 25}
415
+ {:name "Charlie"
416
+ :age 45
417
+ :sibling [[:name "Alice"] [:name "Charlie"]]}])
418
+ (is (= 1 (count (d/datoms (d/history @conn) :eavt [:name "Alice"] :name "Alice"))))
419
+ (is (= 1 (count (filter :added (d/datoms (d/history @conn) :eavt [:name "Alice"] :name "Alice")))))
420
+
421
+ (d/release conn)
422
+ (d/delete-database cfg)))
423
+ ;; => #'datahike.test.time-variance/test-no-duplicates-with-cardinality-many
424
+
425
+ ;; https://github.com/replikativ/datahike/issues/470
426
+ (deftest test-history-record-attribute-access
427
+ (let [cfg {:store {:backend :memory :id (random-uuid)}
428
+ :keep-history? true
429
+ :schema-flexibility :read
430
+ :attribute-refs? false}
431
+ conn (setup-db cfg)
432
+ {{:keys [db/current-tx]} :tempids} (d/transact conn [{:name "Anne"}])
433
+ _ (d/transact conn [{:name "Bernard"}])
434
+ db @conn]
435
+ (testing "history db attributes"
436
+ (is (= db (:origin-db (d/history db))))
437
+ (is (= (:eavt db) (-> db d/history :origin-db :eavt))))
438
+ (testing "as-of db attributes"
439
+ (is (= db (:origin-db (d/as-of db current-tx))))
440
+ (is (= current-tx (:time-point (d/as-of db current-tx))))
441
+ (is (= (:eavt db) (-> db (d/as-of current-tx) :origin-db :eavt))))
442
+ (testing "since db attributes"
443
+ (is (= db (:origin-db (d/since db current-tx))))
444
+ (is (= current-tx (:time-point (d/since db current-tx))))
445
+ (is (= (:eavt db) (-> db (d/since current-tx) :origin-db :eavt))))
446
+ (d/release conn)))
447
+
448
+ (deftest test-filter-current-values-of-same-transaction
449
+ (let [keyword-cfg {:store {:backend :memory :id (random-uuid)}
450
+ :keep-history? true
451
+ :schema-flexibility :write
452
+ :attribute-refs? false}
453
+ name-schema {:db/ident :name
454
+ :db/cardinality :db.cardinality/one
455
+ :db/unique :db.unique/identity
456
+ :db/valueType :db.type/string}]
457
+ (testing "cardinality one"
458
+ (let [schema [name-schema
459
+ {:db/ident :aka
460
+ :db/cardinality :db.cardinality/one
461
+ :db/valueType :db.type/string}]
462
+ conn (setup-db keyword-cfg)
463
+ _ (d/transact conn schema)
464
+ {:keys [tx-data] :as _tx-report} (d/transact conn [{:name "Michal" :aka "Tupen"}])
465
+ michal (:e (first (filter #(= "Michal" (:v %)) tx-data)))
466
+ {{:keys [db/current-tx]} :tempids} (d/transact conn [[:db/retract michal :aka "Tupen"]
467
+ [:db/add michal :aka "Devil"]
468
+ [:db/retract michal :aka "Tupen"]])
469
+ _ (d/transact conn [[:db/retract michal :aka "Devil"]])
470
+ as-of-db (d/as-of @conn current-tx)]
471
+ (is (= {:aka "Devil"}
472
+ (d/pull as-of-db [:aka] michal)))
473
+ (is (= nil
474
+ (d/pull @conn [:aka] michal)))
475
+ (d/release conn)))
476
+ (testing "cardinality many"
477
+ (testing "keyword attributes"
478
+ (let [schema [name-schema
479
+ {:db/ident :aka
480
+ :db/cardinality :db.cardinality/many
481
+ :db/valueType :db.type/string}]
482
+ conn (setup-db keyword-cfg)
483
+ _ (d/transact conn schema)
484
+ {:keys [tx-data]} (d/transact conn [{:name "Michal" :aka "Tupen"}])
485
+ michal (:e (first (filter #(= "Michal" (:v %)) tx-data)))
486
+ {{:keys [db/current-tx]} :tempids} (d/transact conn [[:db/retract michal :aka "Tupen"]
487
+ [:db/add michal :aka "Devil"]
488
+ [:db/retract michal :aka "Tupen"]])
489
+ _ (d/transact conn [[:db/retract michal :aka "Devil"]])
490
+ as-of-db (d/as-of @conn current-tx)]
491
+ (is (= {:aka ["Devil"]}
492
+ (d/pull as-of-db [:aka] michal)))
493
+ (is (= nil
494
+ (d/pull @conn [:aka] michal)))
495
+ (d/release conn)))
496
+
497
+ (testing "reference attributes show all options"
498
+ (let [schema [name-schema
499
+ {:db/ident :aka
500
+ :db/cardinality :db.cardinality/many
501
+ :db/valueType :db.type/string}]
502
+ conn (setup-db (assoc keyword-cfg :attribute-refs? true))
503
+ _ (d/transact conn schema)
504
+ {tx-data :tx-data
505
+ {:keys [db/current-tx]} :tempids} (d/transact conn [{:name "Michal" :aka ["Tupen" "Devil"]}])
506
+ michal (:e (first (filter #(= "Michal" (:v %)) tx-data)))
507
+ as-of-db (d/as-of @conn current-tx)]
508
+ (is (= {:aka ["Devil" "Tupen"]}
509
+ (d/pull as-of-db [:aka] michal)))
510
+ (d/release conn))))))
511
+
512
+ ;; https://github.com/replikativ/datahike/issues/572
513
+ (deftest as-of-should-fail-on-invalid-time-points
514
+ (let [cfg (assoc-in cfg-template [:store :id] #uuid "71000000-0000-0000-0000-000000000006")
515
+ conn (setup-db cfg)]
516
+ (is (thrown-with-msg? Throwable #"Invalid transaction ID. Must be bigger than 536870912."
517
+ (d/as-of @conn 42)))
518
+ (d/release conn)))
@@ -0,0 +1,134 @@
1
+ (ns datahike.test.tools-test
2
+ (:require [datahike.tools :as dt]
3
+ [clojure.test :refer :all]))
4
+
5
+ (deftest test-with-destructured-vector
6
+ (is (= [11 19]
7
+ (dt/with-destructured-vector [10 20]
8
+ a (inc a)
9
+ b (dec b))))
10
+ (is (= [11]
11
+ (dt/with-destructured-vector [10]
12
+ a (inc a)
13
+ b (+ a b))))
14
+ (is (= [300 40]
15
+ (dt/with-destructured-vector [10 30]
16
+ a (* a b)
17
+ b (+ a b))))
18
+ (is (= [100 400]
19
+ (dt/with-destructured-vector [10 20]
20
+ a (* a a)
21
+ b (* b b)
22
+ c (throw (ex-info "This element should not be evaluated" {}))))))
23
+
24
+ (defn add-resolver [context [result-var a b]]
25
+ (when (and (contains? context a)
26
+ (contains? context b))
27
+ (assoc context result-var (+ (context a)
28
+ (context b)))))
29
+
30
+ (deftest resolve-clauses-test
31
+ (is (= {:x 9 :y 10 :z 19 :w 28}
32
+ (dt/resolve-clauses add-resolver
33
+ {:x 9 :y 10}
34
+ [[:w :z :x]
35
+ [:z :x :y]])))
36
+ (is (= {:x 9 :y 10 :z 19 :w 28}
37
+ (dt/resolve-clauses add-resolver
38
+ {:x 9 :y 10}
39
+ [[:z :x :y]
40
+ [:w :z :x]])))
41
+ (is (thrown? Exception
42
+ (dt/resolve-clauses add-resolver
43
+ {:x 9 :y 10}
44
+ [[:w :z :x]]))))
45
+
46
+ (deftest group-by-step-test
47
+ (is (= {true [1000 1002 1004 1006 1008]
48
+ false [1001 1003 1005 1007 1009]}
49
+ (transduce (map #(+ 1000 %))
50
+ (dt/group-by-step even?)
51
+ (range 10)))))
52
+
53
+ (deftest test-match-vector
54
+ (is (= 0 (dt/match-vector [nil nil]
55
+ [_ _] 0
56
+ [_ 1] 1
57
+ [1 *] 2)))
58
+ (is (= 1 (dt/match-vector [nil 9]
59
+ [_ _] 0
60
+ [_ 1] 1
61
+ [1 *] 2)))
62
+ (is (= 2 (dt/match-vector [10 nil]
63
+ [_ _] 0
64
+ [_ 1] 1
65
+ [1 *] 2)))
66
+ (is (= 2 (dt/match-vector [10 :asdf]
67
+ [_ _] 0
68
+ [_ 1] 1
69
+ [1 *] 2)))
70
+ (is (= 3 (dt/match-vector [10 :asdf]
71
+ [_ _] 0
72
+ [_ 1] 1
73
+ [1 _] 2
74
+ [1 1] 3)))
75
+ (is (= 2 (dt/match-vector [10 nil]
76
+ [_ _] 0
77
+ [_ 1] 1
78
+ [1 _] 2
79
+ [1 1] 3))))
80
+
81
+ (defmacro wrap-range-tree [input-symbol]
82
+ (dt/range-subset-tree 3 input-symbol (fn [x y] [:inds x :mask y])))
83
+
84
+ (deftest range-subset-tree-test
85
+ (is (= (dt/range-subset-tree 1 'x (fn [inds _] [:inds inds]))
86
+ '(if
87
+ (clojure.core/empty? x)
88
+ [:inds []]
89
+ (if
90
+ (clojure.core/= 0 (clojure.core/first x))
91
+ (clojure.core/let [x (clojure.core/rest x)] [:inds [0]])
92
+ [:inds []]))))
93
+ (is (= [:inds [1 2] :mask [nil 0 1]]
94
+ (wrap-range-tree [1 2])))
95
+ (is (= [:inds [1] :mask [nil 0 nil]]
96
+ (wrap-range-tree [1])))
97
+ (is (= [:inds [0 2] :mask [0 nil 1]]
98
+ (wrap-range-tree [0 2]))))
99
+
100
+ (deftest merge-distinct-sorted-seqs-test
101
+ (testing "Custom comparator"
102
+ (let [m {:one 1
103
+ :two 2
104
+ :three 3
105
+ :four 4
106
+ :five 5
107
+ :six 6
108
+ :seven 7
109
+ :eight 8
110
+ :nine 9
111
+ :ten 10}
112
+ cmp (fn [a b] (compare (m a) (m b)))]
113
+ (is (= [] (dt/merge-distinct-sorted-seqs cmp [] [])))
114
+ (is (= [:one] (dt/merge-distinct-sorted-seqs cmp [:one] [])))
115
+ (is (= [:one] (dt/merge-distinct-sorted-seqs cmp [:one] [:one])))
116
+ (is (= [:one] (dt/merge-distinct-sorted-seqs cmp [] [:one])))
117
+ (is (= [:one :two] (dt/merge-distinct-sorted-seqs cmp [:two] [:one])))
118
+ (is (= [:one :two :three :four :five :nine :ten]
119
+ (dt/merge-distinct-sorted-seqs cmp
120
+ [:one :two :three :nine :ten]
121
+ [:two :three :four :five])))
122
+ (is (dt/distinct-sorted-seq? cmp []))
123
+ (is (dt/distinct-sorted-seq? cmp [:one]))
124
+ (is (dt/distinct-sorted-seq? cmp [:one :two]))
125
+ (is (dt/distinct-sorted-seq? cmp [:one :two :three]))
126
+ (is (not (dt/distinct-sorted-seq? cmp [:one :two :three :three])))
127
+ (is (not (dt/distinct-sorted-seq? cmp [:one :one :two :three])))
128
+ (is (not (dt/distinct-sorted-seq? cmp [:one :two :two :three])))
129
+ (is (not (dt/distinct-sorted-seq? cmp [:one :two :three :five :four])))))
130
+ (testing "Infinite length sequences"
131
+ (let [evens (iterate #(+ 2 %) 0)
132
+ odds (iterate #(+ 2 %) 1)
133
+ result (dt/merge-distinct-sorted-seqs compare odds evens)]
134
+ (is (= (range 1000) (take 1000 result))))))