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,596 @@
1
+ # Store ID Refactoring - Design & Roadmap
2
+
3
+ **Status:** In Progress
4
+ **Target Version:** 0.7.0
5
+ **Breaking Change:** Yes
6
+
7
+ ## Executive Summary
8
+
9
+ Refactor Datahike's store identity system to use konserve's UUID-based `:id` field instead of backend-specific tuples and the overloaded `:scope` field. This simplifies store identification, enables seamless konserve backend integration, and provides stable identity across distributed replicas.
10
+
11
+ ## Current State Problems
12
+
13
+ ### 1. Fragmented Store Identity
14
+
15
+ **Datahike's `store-identity` multimethod returns different types:**
16
+ ```clojure
17
+ ;; :mem backend
18
+ [:mem "hostname" "random-id"]
19
+
20
+ ;; :file backend
21
+ [:file "hostname" "/path/to/db"]
22
+
23
+ ;; :indexeddb backend
24
+ [:indexeddb "db-name"]
25
+
26
+ ;; :tiered backend (BUG: duplicate backend, should be [frontend backend])
27
+ [:tiered [:indexeddb "name"] [:indexeddb "name"]]
28
+ ```
29
+
30
+ **Problems:**
31
+ - Inconsistent across backends
32
+ - Not stable when moving stores (path/hostname changes)
33
+ - Can't reliably match store across machines
34
+ - Tiered identity is buggy
35
+
36
+ ### 2. Overloaded `:scope` Field
37
+
38
+ **`:scope` is used for multiple purposes:**
39
+
40
+ **a) Datahike default configs (hostname):**
41
+ ```clojure
42
+ (defmethod default-config :file [config]
43
+ (merge {:path "..."
44
+ :scope (dt/get-hostname)} ;; String hostname
45
+ config))
46
+ ```
47
+
48
+ **b) Kabel writer (UUID for remote store):**
49
+ ```clojure
50
+ {:writer {:backend :kabel
51
+ :scope-id #uuid "550e8400-..." ;; UUID
52
+ :peer-id server-id}}
53
+ ```
54
+
55
+ **c) Kabel fressian registry (store lookup):**
56
+ ```clojure
57
+ (defn store-identity-for-registry [store-config]
58
+ (select-keys store-config [:backend :scope]))
59
+ ```
60
+
61
+ **d) konserve-sync topics:**
62
+ ```clojure
63
+ (keyword (str scope-id)) ;; UUID → keyword
64
+ ```
65
+
66
+ **Problems:**
67
+ - Overloaded semantics (hostname vs UUID vs identifier)
68
+ - Not standardized
69
+ - Kabel branch not released yet (can break)
70
+
71
+ ### 3. Duplicate Store Multimethod Infrastructure
72
+
73
+ **Datahike implements store lifecycle in `datahike.store`:**
74
+ ```clojure
75
+ ;; Multimethods dispatching on :backend
76
+ (defmulti store-identity :backend)
77
+ (defmulti empty-store :backend)
78
+ (defmulti delete-store :backend)
79
+ (defmulti connect-store :backend)
80
+ (defmulti ready-store ...)
81
+ (defmulti release-store ...)
82
+ (defmulti default-config :backend)
83
+ (defmulti config-spec :backend)
84
+
85
+ ;; Per-backend implementations for :mem, :file, :indexeddb, :tiered
86
+ ```
87
+
88
+ **Konserve now provides the same via `konserve.store`:**
89
+ ```clojure
90
+ (defmulti -connect-store ...)
91
+ (defmulti -create-store ...)
92
+ (defmulti -store-exists? ...)
93
+ (defmulti -delete-store ...)
94
+ (defmulti -release-store ...)
95
+
96
+ ;; All validate :id is UUID and use it for identity
97
+ ```
98
+
99
+ **Problems:**
100
+ - Duplication of lifecycle management
101
+ - External backends (datahike-jdbc, datahike-rocksdb, datahike-lmdb) must implement Datahike multimethods
102
+ - Prevents third-party konserve backends from working directly
103
+
104
+ ### 4. External Backend Coupling
105
+
106
+ **External backends must:**
107
+ 1. Implement Datahike's store multimethods
108
+ 2. Maintain separate repos/releases
109
+ 3. Stay synchronized with Datahike API changes
110
+
111
+ **With konserve.store:**
112
+ - Backends just implement konserve multimethods once
113
+ - Work with any konserve client (not just Datahike)
114
+ - Already exist: konserve-s3, konserve-dynamodb, konserve-redis, konserve-lmdb, konserve-rocksdb
115
+
116
+ ## Design Decisions
117
+
118
+ ### 1. UUID-Based Store Identity
119
+
120
+ **Decision:** Use `:id` UUID as sole store identifier.
121
+
122
+ ```clojure
123
+ ;; User provides :id in config
124
+ {:store {:backend :file
125
+ :path "/tmp/db"
126
+ :id #uuid "550e8400-e29b-41d4-a716-446655440000"}}
127
+
128
+ ;; store-identity just returns the :id
129
+ (store-identity config) ;; => #uuid "550e8400-..."
130
+
131
+ ;; Connection ID = [store-id branch]
132
+ [#uuid "550e8400-..." :db]
133
+ ```
134
+
135
+ **Rationale:**
136
+ - Stable across machines/paths (critical for distributed setups)
137
+ - User controls identity (explicit > implicit)
138
+ - Matches konserve's validation
139
+ - Simplifies code dramatically
140
+
141
+ ### 2. Remove `:scope` Completely
142
+
143
+ **Decision:** Eliminate `:scope` from all configs and code.
144
+
145
+ **Changes:**
146
+ - Remove from `default-config` implementations
147
+ - Remove from kabel writer (`:scope-id` → use store `:id`)
148
+ - Remove from fressian handler registry
149
+ - Remove from konserve-sync topic derivation
150
+
151
+ **Rationale:**
152
+ - Kabel branch not released yet (safe to break)
153
+ - Overloaded semantics cause confusion
154
+ - `:id` serves the identification purpose
155
+ - Simpler mental model
156
+
157
+ ### 3. Direct Konserve Integration
158
+
159
+ **Decision:** Use `konserve.store` multimethods directly, remove Datahike's store infrastructure.
160
+
161
+ **Keep in `datahike.store`:**
162
+ ```clojure
163
+ (defn add-cache-and-handlers [raw-store config]
164
+ ;; Datahike-specific: add LRU cache and BTSet handlers
165
+ ...)
166
+
167
+ (defmethod ready-store :tiered [config store]
168
+ ;; Tiered-specific: populate memory from IndexedDB before sync
169
+ ...)
170
+ ```
171
+
172
+ **Remove from `datahike.store`:**
173
+ - All `empty-store`, `connect-store`, `delete-store`, `release-store` multimethods
174
+ - All `default-config` multimethods
175
+ - All `config-spec` multimethods
176
+ - Backend-specific implementations (:mem, :file, :indexeddb)
177
+
178
+ **Use konserve directly:**
179
+ ```clojure
180
+ ;; In datahike.connector
181
+ (require '[konserve.store :as ks])
182
+
183
+ (ks/create-store (:store config) {:sync? false})
184
+ (ks/connect-store (:store config) {:sync? false})
185
+ (ks/delete-store (:store config) {:sync? false})
186
+ ```
187
+
188
+ **Rationale:**
189
+ - Eliminates duplication
190
+ - Third-party backends work automatically
191
+ - Simpler maintenance
192
+ - Konserve handles validation
193
+
194
+ ### 4. Backend Name: `:memory` vs `:mem`
195
+
196
+ **Decision:** Konserve uses `:memory`, Datahike currently uses `:mem`.
197
+
198
+ **Options:**
199
+ a) Switch to `:memory` (breaking but cleaner)
200
+ b) Keep `:mem` with backwards compat in konserve
201
+ c) Support both with deprecation path
202
+
203
+ **Recommendation:** **(a)** - Clean break for 0.7, cleaner going forward.
204
+
205
+ Users already need to add `:id`, changing `:mem` → `:memory` is minimal friction.
206
+
207
+ ### 5. Config Persistence & Migration
208
+
209
+ **Decision:** Support loading old databases without `:id`.
210
+
211
+ **Migration flow:**
212
+ ```clojure
213
+ ;; In connector.cljc after loading stored-db
214
+ (let [user-config (dc/load-config raw-config) ;; Has :id (required)
215
+ stored-config (:config stored-db) ;; Old DB lacks :id
216
+
217
+ ;; If stored config has :id, validate it matches user :id
218
+ ;; (Deactivated for now - too brittle with path changes)
219
+ ;; (when (and (:id stored-config)
220
+ ;; (not= (:id stored-config) (:id user-config)))
221
+ ;; (throw ...))
222
+
223
+ ;; Merge user :id into stored config
224
+ final-config (assoc stored-config :id (get-in user-config [:store :id]))]
225
+
226
+ ;; Use final-config
227
+ ;; On next transaction, db->stored will persist :id
228
+ ...)
229
+ ```
230
+
231
+ **Rationale:**
232
+ - Existing databases continue to work
233
+ - User provides :id once, gets stored permanently
234
+ - No auto-generation (user controls identity)
235
+ - Path to full validation later
236
+
237
+ ### 6. Tiered Store ID Consistency
238
+
239
+ **Decision:** Enforce frontend/backend `:id` matches tiered config `:id`.
240
+
241
+ ```clojure
242
+ ;; In konserve.store/-create-store :tiered
243
+ (when-not (= (:id config) (:id frontend))
244
+ (throw (ex-info "Frontend :id must match tiered :id" ...)))
245
+ (when-not (= (:id config) (:id backend))
246
+ (throw (ex-info "Backend :id must match tiered :id" ...)))
247
+ ```
248
+
249
+ **Example valid config:**
250
+ ```clojure
251
+ {:backend :tiered
252
+ :id #uuid "550e8400-e29b-41d4-a716-446655440000"
253
+ :frontend {:backend :memory
254
+ :id #uuid "550e8400-e29b-41d4-a716-446655440000"}
255
+ :backend {:backend :indexeddb
256
+ :name "mydb"
257
+ :id #uuid "550e8400-e29b-41d4-a716-446655440000"}}
258
+ ```
259
+
260
+ **Rationale:**
261
+ - All sub-stores represent the same logical store
262
+ - Prevents configuration errors
263
+ - Makes identity explicit
264
+
265
+ ### 7. konserve-sync Topics
266
+
267
+ **Decision:** Use UUID directly as topic, not `(keyword (str uuid))`.
268
+
269
+ **Before:**
270
+ ```clojure
271
+ (keyword (str scope-id)) ;; => :550e8400-e29b-41d4-a716-446655440000
272
+ ```
273
+
274
+ **After:**
275
+ ```clojure
276
+ (:id store-config) ;; => #uuid "550e8400-..."
277
+ ```
278
+
279
+ **Rationale:**
280
+ - Simpler (no conversion)
281
+ - Type-safe (UUID vs keyword)
282
+ - konserve-sync/kabel support any EDN value as topic
283
+ - Not released yet (safe to change)
284
+
285
+ **Verify:** Check if kabel pubsub requires keywords or accepts UUIDs.
286
+
287
+ ### 8. External Backends
288
+
289
+ **Decision:** Drop datahike-jdbc, datahike-rocksdb, datahike-lmdb.
290
+
291
+ **Rationale:**
292
+ - All use konserve underneath
293
+ - konserve-jdbc, konserve-rocksdb, konserve-lmdb exist
294
+ - Users can use konserve backends directly
295
+ - Eliminates maintenance burden
296
+
297
+ **Migration:** Update docs to reference konserve backends.
298
+
299
+ ## Roadmap
300
+
301
+ ### Phase 0: Preparation ✅
302
+
303
+ - [x] Create this design document
304
+ - [x] Compare `datahike.store` vs `konserve.store` for missing specs/features
305
+ - **Finding:** Konserve uses runtime validation only (no specs)
306
+ - **Decision:** Remove all Datahike specs, rely on konserve's `validate-store-config`
307
+ - **Rationale:** Datahike specs are outdated (wrong types, include `:scope`), konserve errors are clear
308
+ - [x] Verify kabel pubsub accepts UUID topics (not just keywords)
309
+ - **Finding:** Kabel topics are any EDN value (used as map keys)
310
+ - **Decision:** Use UUID directly as topic, no keyword conversion needed
311
+
312
+ ### Phase 1: Konserve Tiered Store Validation
313
+
314
+ **Goal:** Enforce ID consistency in tiered stores.
315
+
316
+ **Files:**
317
+ - `konserve/src/konserve/store.cljc`
318
+
319
+ **Changes:**
320
+ 1. Add ID validation to `-create-store :tiered`
321
+ 2. Add ID validation to `-connect-store :tiered`
322
+ 3. Add test case for mismatched IDs
323
+
324
+ **Testing:**
325
+ ```clojure
326
+ ;; Should throw
327
+ {:backend :tiered
328
+ :id #uuid "aaaa..."
329
+ :frontend {:backend :memory :id #uuid "bbbb..."}} ;; Mismatch!
330
+ ```
331
+
332
+ ### Phase 2: Datahike Store Cleanup ✅
333
+
334
+ **Goal:** Remove Datahike multimethods, use konserve directly.
335
+
336
+ **Status:** COMPLETE (commit 7edeebd)
337
+
338
+ **Files:**
339
+ - `src/datahike/store.cljc`
340
+
341
+ **Changes:**
342
+ 1. Compare with `konserve.store` - port any missing specs
343
+ 2. Remove multimethods: `empty-store`, `connect-store`, `delete-store`, `release-store`, `default-config`, `config-spec`
344
+ 3. Simplify `store-identity` to single implementation returning `:id`
345
+ 4. Keep `add-cache-and-handlers` and `ready-store :tiered`
346
+ 5. Update all callsites to use `konserve.store` directly
347
+
348
+ **Callsites to update:**
349
+ - `src/datahike/connector.cljc`
350
+ - `src/datahike/kabel/connector.cljc`
351
+ - `src/datahike/writing.cljc`
352
+ - Tests
353
+
354
+ **Testing:**
355
+ - Run existing test suite
356
+ - Verify `:mem` → `:memory` migration works
357
+ - Check error messages when `:id` missing
358
+
359
+ ### Phase 3: Kabel `:scope` Removal
360
+
361
+ **Goal:** Use store `:id` instead of separate `:scope-id`.
362
+
363
+ **Files:**
364
+ - `src/datahike/kabel/connector.cljc`
365
+ - `src/datahike/kabel/writer.cljc`
366
+ - `src/datahike/kabel/fressian_handlers.cljc`
367
+ - `src/datahike/kabel/handlers.cljc`
368
+ - `src/datahike/kabel/tx_broadcast.cljc`
369
+
370
+ **Changes:**
371
+
372
+ **connector.cljc:**
373
+ ```clojure
374
+ ;; Remove:
375
+ {:keys [peer-id scope-id local-peer]} (:writer config)
376
+
377
+ ;; Replace with:
378
+ {:keys [peer-id local-peer]} (:writer config)
379
+ store-id (get-in config [:store :id])
380
+
381
+ ;; Use UUID directly as topic:
382
+ store-topic store-id ;; Not (keyword (str store-id))
383
+ ```
384
+
385
+ **fressian_handlers.cljc:**
386
+ ```clojure
387
+ ;; Simplify registry:
388
+ (defn store-identity-for-registry [store-config]
389
+ (:id store-config)) ;; Was: (select-keys [:backend :scope])
390
+ ```
391
+
392
+ **handlers.cljc:**
393
+ ```clojure
394
+ ;; Replace scope-id extraction:
395
+ (let [store-id (get-in config [:store :id])] ;; Was: [:writer :scope-id] or [:store :scope]
396
+ ...)
397
+ ```
398
+
399
+ **Testing:**
400
+ - Browser integration tests
401
+ - JVM integration tests
402
+ - Verify sync still works with UUID topics
403
+
404
+ ### Phase 4: Connector Config Migration
405
+
406
+ **Goal:** Support loading old DBs without `:id`.
407
+
408
+ **Files:**
409
+ - `src/datahike/connector.cljc`
410
+
411
+ **Changes:**
412
+ ```clojure
413
+ (defn -connect* [raw-config opts]
414
+ (let [user-config (dc/load-config raw-config)
415
+ _ (when-not (get-in user-config [:store :id])
416
+ (throw (ex-info "Store :id is required" ...)))
417
+
418
+ ;; Load stored-db from konserve
419
+ stored-db (<?- (k/get store :db))
420
+ stored-config (:config stored-db)
421
+
422
+ ;; Merge user :id into stored config if missing
423
+ final-config (cond-> stored-config
424
+ (nil? (:id (:store stored-config)))
425
+ (assoc-in [:store :id] (get-in user-config [:store :id])))
426
+
427
+ ;; Optional: Validate :id match if both exist
428
+ ;; (Deactivated for now)
429
+
430
+ ;; Use final-config - will be persisted on next transaction
431
+ ...])
432
+ ```
433
+
434
+ **Testing:**
435
+ - Load 0.6 database with new 0.7 code
436
+ - Verify :id gets persisted
437
+ - Verify subsequent loads work
438
+
439
+ ### Phase 5: Documentation & Migration Guide
440
+
441
+ **Goal:** Document breaking changes and migration path.
442
+
443
+ **Files:**
444
+ - `CHANGELOG.md`
445
+ - `doc/config.md`
446
+ - `doc/distributed.md`
447
+ - `doc/cljs-support.md`
448
+ - `README.md`
449
+
450
+ **Changes:**
451
+ 1. Update config examples with `:id`
452
+ 2. Document `:mem` → `:memory` change
453
+ 3. Add migration guide for 0.6 → 0.7
454
+ 4. Remove references to external backends
455
+ 5. Update kabel writer examples (no `:scope-id`)
456
+
457
+ **Migration guide sections:**
458
+ - Required: Add `:id` to all store configs
459
+ - Optional: Change `:mem` → `:memory`
460
+ - Kabel: Remove `:scope-id` from writer config
461
+ - External backends: Use konserve-jdbc/rocksdb/lmdb directly
462
+
463
+ ### Phase 6: External Backend Cleanup
464
+
465
+ **Goal:** Remove/deprecate external backend repos.
466
+
467
+ **Actions:**
468
+ 1. Archive datahike-jdbc, datahike-rocksdb, datahike-lmdb repos
469
+ 2. Add README pointing to konserve equivalents
470
+ 3. Remove from Datahike deps/docs
471
+
472
+ ## Breaking Changes for Users
473
+
474
+ ### Required Changes
475
+
476
+ **1. Add `:id` to all store configs:**
477
+ ```clojure
478
+ ;; Before (0.6)
479
+ {:store {:backend :file :path "/tmp/db"}}
480
+
481
+ ;; After (0.7)
482
+ {:store {:backend :file :path "/tmp/db" :id #uuid "550e8400-..."}}
483
+ ```
484
+
485
+ **2. Change `:mem` → `:memory`:**
486
+ ```clojure
487
+ ;; Before
488
+ {:store {:backend :mem :id "test"}}
489
+
490
+ ;; After
491
+ {:store {:backend :memory :id #uuid "550e8400-..."}}
492
+ ```
493
+
494
+ **3. Kabel: Remove `:scope-id`:**
495
+ ```clojure
496
+ ;; Before
497
+ {:writer {:backend :kabel
498
+ :peer-id server-id
499
+ :scope-id #uuid "550e8400-..."
500
+ :local-peer peer}}
501
+
502
+ ;; After
503
+ {:writer {:backend :kabel
504
+ :peer-id server-id
505
+ :local-peer peer}}
506
+ ;; Uses store :id automatically
507
+ ```
508
+
509
+ ### Optional Changes
510
+
511
+ **External backends:**
512
+ ```clojure
513
+ ;; Before
514
+ {:store {:backend :jdbc :url "..." :scope "..."}}
515
+
516
+ ;; After (use konserve backend directly)
517
+ (require '[konserve-jdbc.core])
518
+ {:store {:backend :jdbc :url "..." :id #uuid "..."}}
519
+ ```
520
+
521
+ ## Testing Strategy
522
+
523
+ ### Unit Tests
524
+ - [ ] Konserve tiered ID validation
525
+ - [ ] store-identity returns UUID
526
+ - [ ] Config validation (missing :id)
527
+
528
+ ### Integration Tests
529
+ - [ ] Load 0.6 database with 0.7 code
530
+ - [ ] Create new database with :id
531
+ - [ ] Kabel sync with UUID topics
532
+ - [ ] Browser integration test
533
+ - [ ] Tiered store with matching IDs
534
+ - [ ] Error handling (mismatched IDs, missing :id)
535
+
536
+ ### Regression Tests
537
+ - [ ] All existing Datahike tests pass
538
+ - [ ] External backend tests (before deprecation)
539
+
540
+ ## Open Questions
541
+
542
+ ### 1. Backend Name: `:mem` vs `:memory`
543
+ **Status:** Need decision
544
+ **Options:**
545
+ - (a) Switch to `:memory` (clean break)
546
+ - (b) Support both with deprecation
547
+ - (c) Stay with `:mem`
548
+
549
+ **Recommendation:** (a) - Clean break for 0.7
550
+
551
+ ### 2. konserve-sync UUID Topics
552
+ **Status:** Need verification
553
+ **Question:** Does kabel pubsub accept UUID topics or require keywords?
554
+
555
+ **Action:** Test with UUID, verify it works.
556
+
557
+ ### 3. Config Spec Migration
558
+ **Status:** Need comparison
559
+ **Question:** Does konserve.store have equivalent specs to datahike.store?
560
+
561
+ **Action:** Compare spec definitions, port any missing ones to konserve.
562
+
563
+ ### 4. ready-store Future
564
+ **Status:** Low priority
565
+ **Question:** Should `ready-store :tiered` move to konserve or stay in Datahike?
566
+
567
+ **Decision:** Keep in Datahike for now, can migrate later.
568
+
569
+ ### 5. Backwards Compatibility Window
570
+ **Status:** Need policy decision
571
+ **Question:** How long to support `:scope` in deprecated form?
572
+
573
+ **Decision:** No backwards compat - clean break for 0.7 (kabel not released yet).
574
+
575
+ ## Success Criteria
576
+
577
+ - [x] Design document complete
578
+ - [ ] All phases implemented
579
+ - [ ] All tests passing
580
+ - [ ] Documentation updated
581
+ - [ ] Migration guide written
582
+ - [ ] Breaking changes clearly communicated
583
+ - [ ] konserve tiered ID validation working
584
+ - [ ] External backends deprecated/archived
585
+
586
+ ## Timeline
587
+
588
+ **Target:** Datahike 0.7.0 release
589
+ **Dependencies:** konserve store.cljc changes committed first
590
+
591
+ ## References
592
+
593
+ - konserve store.cljc: `konserve/src/konserve/store.cljc`
594
+ - Datahike store.cljc: `src/datahike/store.cljc`
595
+ - Kabel connector: `src/datahike/kabel/connector.cljc`
596
+ - This branch: `cljs-lean-cps` (not released)