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,808 @@
1
+ # Datahike Java API
2
+
3
+ **Status: Beta** - The Java API is functional and tested, but may receive breaking changes as we gather feedback from production use.
4
+
5
+ Datahike provides a comprehensive Java API that enables you to use the full power of Datalog databases from Java applications without writing Clojure code. The API offers both high-level convenience methods and low-level access for advanced use cases.
6
+
7
+ ## Features
8
+
9
+ - **Type-Safe Configuration** - Fluent builder pattern with compile-time checks
10
+ - **Modern Java API** - Works with Java Maps, UUIDs, and standard collections
11
+ - **Full Datalog Support** - Expressive declarative queries with joins, aggregates, and rules
12
+ - **Time Travel** - Query database history and point-in-time snapshots
13
+ - **Pull API** - Recursive pattern-based entity retrieval
14
+ - **Schema Support** - Optional strict or flexible schema enforcement
15
+ - **Multiple Backends** - Memory, file system, and extensible to custom stores
16
+
17
+ ## Installation
18
+
19
+ ### Maven
20
+
21
+ Add the Clojars repository and Datahike dependency to your `pom.xml`:
22
+
23
+ ```xml
24
+ <repositories>
25
+ <repository>
26
+ <id>clojars</id>
27
+ <name>Clojars</name>
28
+ <url>https://repo.clojars.org/</url>
29
+ </repository>
30
+ </repositories>
31
+
32
+ <dependencies>
33
+ <dependency>
34
+ <groupId>org.replikativ</groupId>
35
+ <artifactId>datahike</artifactId>
36
+ <version>CURRENT</version> <!-- Check https://clojars.org/org.replikativ/datahike for latest -->
37
+ </dependency>
38
+ </dependencies>
39
+ ```
40
+
41
+ ### Gradle
42
+
43
+ Add to your `build.gradle`:
44
+
45
+ ```gradle
46
+ repositories {
47
+ maven { url "https://repo.clojars.org/" }
48
+ mavenCentral()
49
+ }
50
+
51
+ dependencies {
52
+ implementation 'org.replikativ:datahike:CURRENT' // Check https://clojars.org/org.replikativ/datahike for latest
53
+ }
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ ```java
59
+ import datahike.java.Datahike;
60
+ import datahike.java.Database;
61
+ import datahike.java.SchemaFlexibility;
62
+ import java.util.*;
63
+
64
+ // Create and connect to database
65
+ Map<String, Object> config = Database.memory(UUID.randomUUID())
66
+ .schemaFlexibility(SchemaFlexibility.READ)
67
+ .build();
68
+
69
+ Datahike.createDatabase(config);
70
+ Object conn = Datahike.connect(config);
71
+
72
+ // Transact data using Java Maps
73
+ Datahike.transact(conn, List.of(
74
+ Map.of("name", "Alice", "age", 30),
75
+ Map.of("name", "Bob", "age", 25)
76
+ ));
77
+
78
+ // Query with Datalog
79
+ Set<?> results = (Set<?>) Datahike.q(
80
+ "[:find ?name ?age :where [?e :name ?name] [?e :age ?age]]",
81
+ Datahike.deref(conn)
82
+ );
83
+
84
+ System.out.println(results);
85
+ // => #{["Alice" 30] ["Bob" 25]}
86
+
87
+ // Cleanup
88
+ Datahike.deleteDatabase(config);
89
+ ```
90
+
91
+ ## Configuration
92
+
93
+ Datahike offers three approaches to configuration, each suited for different needs.
94
+
95
+ ### Approach 1: Database Builder (Recommended)
96
+
97
+ The fluent builder pattern provides type safety and IDE autocompletion:
98
+
99
+ ```java
100
+ import datahike.java.Database;
101
+ import datahike.java.SchemaFlexibility;
102
+ import java.util.UUID;
103
+
104
+ // In-memory database (requires UUID)
105
+ Map<String, Object> config = Database.memory(UUID.randomUUID())
106
+ .keepHistory(true)
107
+ .schemaFlexibility(SchemaFlexibility.READ)
108
+ .build();
109
+
110
+ // File-based database
111
+ Map<String, Object> config = Database.file("/var/lib/mydb")
112
+ .keepHistory(true)
113
+ .name("production-db")
114
+ .build();
115
+
116
+ // With initial schema
117
+ import static datahike.java.Keywords.*;
118
+ import static datahike.java.Util.*;
119
+
120
+ Object schema = vec(
121
+ map(DB_IDENT, kwd(":person/name"),
122
+ DB_VALUE_TYPE, STRING,
123
+ DB_CARDINALITY, ONE)
124
+ );
125
+
126
+ Map<String, Object> config = Database.memory(UUID.randomUUID())
127
+ .initialTx(schema)
128
+ .build();
129
+ ```
130
+
131
+ **When to use:** New projects, when you want type safety and clear code.
132
+
133
+ ### Approach 2: Java Maps
134
+
135
+ Use standard Java collections with string keys (automatically converted to Clojure keywords):
136
+
137
+ ```java
138
+ import java.util.*;
139
+
140
+ // Configuration with nested maps
141
+ Map<String, Object> config = Map.of(
142
+ "store", Map.of(
143
+ "backend", ":memory", // : prefix makes it a keyword
144
+ "id", UUID.randomUUID()
145
+ ),
146
+ "schema-flexibility", ":read",
147
+ "keep-history?", true
148
+ );
149
+
150
+ // Custom backends
151
+ Map<String, Object> config = Map.of(
152
+ "store", Map.of(
153
+ "backend", ":pg",
154
+ "host", "localhost",
155
+ "port", 5432,
156
+ "username", "user",
157
+ "password", "secret"
158
+ )
159
+ );
160
+ ```
161
+
162
+ **When to use:** Dynamic configuration, config files (JSON/YAML → Map), custom backends.
163
+
164
+ ### Approach 3: EDN Strings (Advanced)
165
+
166
+ For advanced use cases, work directly with Clojure's Extensible Data Notation:
167
+
168
+ ```java
169
+ import static datahike.java.Util.*;
170
+
171
+ // Parse EDN string
172
+ Object config = ednFromString(
173
+ "{:store {:backend :memory :id #uuid \"550e8400-e29b-41d4-a716-446655440000\"}}"
174
+ );
175
+
176
+ // Build EDN programmatically
177
+ Object config = map(
178
+ kwd(":store"), map(
179
+ kwd(":backend"), kwd(":memory"),
180
+ kwd(":id"), UUID.randomUUID()
181
+ )
182
+ );
183
+ ```
184
+
185
+ **When to use:** Interop with Clojure code, advanced EDN features, maximum control.
186
+
187
+ ## Database Lifecycle
188
+
189
+ ### Creating and Connecting
190
+
191
+ ```java
192
+ import datahike.java.Datahike;
193
+
194
+ // Create database (idempotent - safe to call multiple times)
195
+ Datahike.createDatabase(config);
196
+
197
+ // Check if database exists
198
+ boolean exists = Datahike.databaseExists(config);
199
+
200
+ // Connect to database (returns connection object)
201
+ Object conn = Datahike.connect(config);
202
+
203
+ // Get current database value
204
+ Object db = Datahike.deref(conn);
205
+ ```
206
+
207
+ ### Deleting Databases
208
+
209
+ ```java
210
+ // Delete all database files/data
211
+ Datahike.deleteDatabase(config);
212
+
213
+ // Release connection (required for some backends like LevelDB)
214
+ Datahike.release(conn);
215
+ ```
216
+
217
+ ## Transactions
218
+
219
+ Transactions are atomic and consistent. Add, update, or retract data.
220
+
221
+ ### Simple Transactions
222
+
223
+ ```java
224
+ import java.util.*;
225
+
226
+ // Add entities with auto-generated IDs
227
+ Datahike.transact(conn, List.of(
228
+ Map.of("name", "Alice", "age", 30),
229
+ Map.of("name", "Bob", "age", 25)
230
+ ));
231
+
232
+ // Update existing entity (requires :db/id)
233
+ Datahike.transact(conn, List.of(
234
+ Map.of(":db/id", 1, "age", 31)
235
+ ));
236
+
237
+ // Retract attribute
238
+ import static datahike.java.Util.*;
239
+
240
+ Datahike.transact(conn, vec(
241
+ vec(kwd(":db/retract"), 1, kwd(":age"), 30)
242
+ ));
243
+
244
+ // Retract entire entity
245
+ Datahike.transact(conn, vec(
246
+ vec(kwd(":db.fn/retractEntity"), 1)
247
+ ));
248
+ ```
249
+
250
+ ### EDN Conversion Rules
251
+
252
+ Datahike automatically converts between Java and Clojure data:
253
+
254
+ | Java Type | EDN Type | Example |
255
+ |-----------|----------|---------|
256
+ | `String` starting with `:` | Keyword | `":memory"` → `:memory` |
257
+ | Other `String` | String | `"Alice"` → `"Alice"` |
258
+ | `Integer`, `Long` | Long | `42` → `42` |
259
+ | `Boolean` | Boolean | `true` → `true` |
260
+ | `Map<String, ?>` | Map | `{"a": 1}` → `{:a 1}` |
261
+ | `List<?>`, `Object[]` | Vector | `[1, 2]` → `[1 2]` |
262
+ | `UUID` | UUID | `UUID` → `#uuid "..."` |
263
+
264
+ **Important:** Map keys are always converted to keywords. Use `:` prefix in string values to create keyword values.
265
+
266
+ See [EDN Conversion Documentation](bindings/edn-conversion.md) for complete rules and edge cases.
267
+
268
+ ## Queries
269
+
270
+ Datahike uses Datalog, a declarative query language similar to SQL but more expressive.
271
+
272
+ ### Basic Queries
273
+
274
+ ```java
275
+ // Find all names
276
+ Set<?> results = (Set<?>) Datahike.q(
277
+ "[:find ?name :where [?e :name ?name]]",
278
+ Datahike.deref(conn)
279
+ );
280
+
281
+ // Find with conditions
282
+ Set<?> results = (Set<?>) Datahike.q(
283
+ "[:find ?name ?age :where [?e :name ?name] [?e :age ?age] [(>= ?age 25)]]",
284
+ Datahike.deref(conn)
285
+ );
286
+
287
+ // Joins across entities
288
+ Set<?> results = (Set<?>) Datahike.q(
289
+ """
290
+ [:find ?person-name ?friend-name
291
+ :where
292
+ [?p :person/name ?person-name]
293
+ [?p :person/friends ?f]
294
+ [?f :person/name ?friend-name]]
295
+ """,
296
+ Datahike.deref(conn)
297
+ );
298
+ ```
299
+
300
+ ### Parameterized Queries
301
+
302
+ ```java
303
+ // Query with input parameters
304
+ Set<?> results = (Set<?>) Datahike.q(
305
+ "[:find ?e :in $ ?name :where [?e :name ?name]]",
306
+ Datahike.deref(conn),
307
+ "Alice"
308
+ );
309
+
310
+ // Multiple databases
311
+ Object conn2 = Datahike.connect(otherConfig);
312
+ Set<?> results = (Set<?>) Datahike.q(
313
+ "[:find ?name :in $ $2 :where [$ ?e :name ?name] [$2 ?e :active true]]",
314
+ Datahike.deref(conn),
315
+ Datahike.deref(conn2)
316
+ );
317
+ ```
318
+
319
+ ### Aggregates
320
+
321
+ ```java
322
+ // Count, sum, min, max, avg
323
+ Set<?> results = (Set<?>) Datahike.q(
324
+ "[:find (count ?e) (avg ?age) :where [?e :age ?age]]",
325
+ Datahike.deref(conn)
326
+ );
327
+
328
+ // Group by
329
+ Set<?> results = (Set<?>) Datahike.q(
330
+ """
331
+ [:find ?department (avg ?salary)
332
+ :where
333
+ [?e :employee/department ?department]
334
+ [?e :employee/salary ?salary]]
335
+ """,
336
+ Datahike.deref(conn)
337
+ );
338
+ ```
339
+
340
+ ## Pull API
341
+
342
+ The Pull API retrieves entities with nested relationships using pattern-based selectors.
343
+
344
+ ### Basic Pull
345
+
346
+ ```java
347
+ // Pull single entity by ID
348
+ Map<?, ?> entity = (Map<?, ?>) Datahike.pull(
349
+ Datahike.deref(conn),
350
+ "[:name :age]",
351
+ 1
352
+ );
353
+ // => {:name "Alice" :age 30}
354
+
355
+ // Pull all attributes
356
+ Map<?, ?> entity = (Map<?, ?>) Datahike.pull(
357
+ Datahike.deref(conn),
358
+ "[*]",
359
+ 1
360
+ );
361
+
362
+ // Pull multiple entities
363
+ List<?> entities = (List<?>) Datahike.pullMany(
364
+ Datahike.deref(conn),
365
+ "[:name :age]",
366
+ List.of(1, 2, 3)
367
+ );
368
+ ```
369
+
370
+ ### Nested Pull
371
+
372
+ ```java
373
+ // Pull with nested relationships
374
+ Map<?, ?> person = (Map<?, ?>) Datahike.pull(
375
+ Datahike.deref(conn),
376
+ """
377
+ [:person/name
378
+ {:person/friends [:person/name :person/email]}]
379
+ """,
380
+ 1
381
+ );
382
+ // => {:person/name "Alice"
383
+ // :person/friends [{:person/name "Bob" :person/email "bob@example.com"}]}
384
+
385
+ // Recursive pull (follow references up to 3 levels)
386
+ Map<?, ?> org = (Map<?, ?>) Datahike.pull(
387
+ Datahike.deref(conn),
388
+ "[:org/name {:org/parent 3}]", // 3 = recursion depth
389
+ orgId
390
+ );
391
+ ```
392
+
393
+ ## Time Travel
394
+
395
+ Query database state at any point in history.
396
+
397
+ ### Historical Queries
398
+
399
+ ```java
400
+ import java.time.Instant;
401
+ import java.util.Date;
402
+
403
+ // Query as of specific time
404
+ Date timestamp = Date.from(Instant.parse("2024-01-01T00:00:00Z"));
405
+ Object pastDb = Datahike.asOf(Datahike.deref(conn), timestamp);
406
+ Set<?> results = (Set<?>) Datahike.q(
407
+ "[:find ?name :where [?e :name ?name]]",
408
+ pastDb
409
+ );
410
+
411
+ // Query changes since timestamp
412
+ Object recentDb = Datahike.since(Datahike.deref(conn), timestamp);
413
+ Set<?> changes = (Set<?>) Datahike.q(
414
+ "[:find ?name :where [?e :name ?name]]",
415
+ recentDb
416
+ );
417
+
418
+ // Query full history (includes all assertions and retractions)
419
+ Object historyDb = Datahike.history(Datahike.deref(conn));
420
+ Set<?> allValues = (Set<?>) Datahike.q(
421
+ "[:find ?name :where [?e :name ?name]]",
422
+ historyDb
423
+ );
424
+ ```
425
+
426
+ ### Transaction Metadata
427
+
428
+ ```java
429
+ import static datahike.java.Util.*;
430
+
431
+ // Add metadata to transaction
432
+ Datahike.transact(conn, Map.of(
433
+ ":tx-data", List.of(Map.of("name", "Alice")),
434
+ ":tx-meta", Map.of("author", "user@example.com", "reason", "user signup")
435
+ ));
436
+
437
+ // Query transaction metadata
438
+ Set<?> txData = (Set<?>) Datahike.q(
439
+ """
440
+ [:find ?tx ?author ?time
441
+ :where
442
+ [?tx :author ?author]
443
+ [?tx :db/txInstant ?time]]
444
+ """,
445
+ Datahike.deref(conn)
446
+ );
447
+ ```
448
+
449
+ ## Schema Definition
450
+
451
+ Schemas define attributes and their properties, enabling validation and optimizations.
452
+
453
+ ### Defining Schema
454
+
455
+ ```java
456
+ import static datahike.java.Keywords.*;
457
+ import static datahike.java.Util.*;
458
+
459
+ // Define schema attributes
460
+ Object schema = vec(
461
+ map(
462
+ DB_IDENT, kwd(":person/name"),
463
+ DB_VALUE_TYPE, STRING,
464
+ DB_CARDINALITY, ONE,
465
+ DB_DOC, "Person's full name",
466
+ DB_UNIQUE, UNIQUE_IDENTITY
467
+ ),
468
+ map(
469
+ DB_IDENT, kwd(":person/age"),
470
+ DB_VALUE_TYPE, LONG,
471
+ DB_CARDINALITY, ONE
472
+ ),
473
+ map(
474
+ DB_IDENT, kwd(":person/friends"),
475
+ DB_VALUE_TYPE, REF,
476
+ DB_CARDINALITY, MANY,
477
+ DB_DOC, "Person's friends (entity references)"
478
+ )
479
+ );
480
+
481
+ // Option 1: Set schema at database creation
482
+ Map<String, Object> config = Database.memory(UUID.randomUUID())
483
+ .initialTx(schema)
484
+ .build();
485
+
486
+ Datahike.createDatabase(config);
487
+
488
+ // Option 2: Transact schema after creation
489
+ Datahike.createDatabase(config);
490
+ Object conn = Datahike.connect(config);
491
+ Datahike.transact(conn, schema);
492
+ ```
493
+
494
+ ### Schema Flexibility
495
+
496
+ ```java
497
+ import datahike.java.SchemaFlexibility;
498
+
499
+ // Strict: Only defined attributes allowed
500
+ Map<String, Object> config = Database.memory(UUID.randomUUID())
501
+ .build(); // Default: strict schema enforcement
502
+
503
+ // Flexible read: Allow reading undefined attributes, reject writes
504
+ Map<String, Object> config = Database.memory(UUID.randomUUID())
505
+ .schemaFlexibility(SchemaFlexibility.READ)
506
+ .build();
507
+
508
+ // Flexible write: Allow both reading and writing undefined attributes
509
+ Map<String, Object> config = Database.memory(UUID.randomUUID())
510
+ .schemaFlexibility(SchemaFlexibility.WRITE)
511
+ .build();
512
+ ```
513
+
514
+ ### Schema Constants
515
+
516
+ Use the `Keywords` class for type-safe schema definitions:
517
+
518
+ ```java
519
+ import static datahike.java.Keywords.*;
520
+
521
+ // Entity attributes
522
+ DB_ID, DB_IDENT
523
+
524
+ // Schema definition
525
+ DB_VALUE_TYPE, DB_CARDINALITY, DB_DOC, DB_UNIQUE, DB_INDEX
526
+
527
+ // Value types
528
+ STRING, BOOLEAN, LONG, BIGINT, FLOAT, DOUBLE, BIGDEC,
529
+ INSTANT, UUID_TYPE, KEYWORD_TYPE, SYMBOL_TYPE, REF, BYTES
530
+
531
+ // Cardinality
532
+ ONE, MANY
533
+
534
+ // Uniqueness
535
+ UNIQUE_VALUE, UNIQUE_IDENTITY
536
+
537
+ // Schema flexibility
538
+ SCHEMA_READ, SCHEMA_WRITE
539
+
540
+ // Storage backends
541
+ BACKEND_MEMORY, BACKEND_FILE
542
+ ```
543
+
544
+ ## Advanced Features
545
+
546
+ ### Index Access
547
+
548
+ ```java
549
+ // Get datoms from index (EAVT, AEVT, AVET)
550
+ Iterable<?> datoms = Datahike.datoms(
551
+ Datahike.deref(conn),
552
+ ":eavt"
553
+ );
554
+
555
+ // Seek to position in index
556
+ import static datahike.java.Util.*;
557
+
558
+ Iterable<?> datoms = Datahike.seekDatoms(
559
+ Datahike.deref(conn),
560
+ ":avet",
561
+ kwd(":name"), "Alice"
562
+ );
563
+
564
+ // Get index range
565
+ Iterable<?> range = Datahike.indexRange(
566
+ Datahike.deref(conn),
567
+ ":name",
568
+ "A", "M" // Lexicographic range
569
+ );
570
+ ```
571
+
572
+ ### Entity API
573
+
574
+ ```java
575
+ import datahike.java.IEntity;
576
+ import static datahike.java.Util.*;
577
+
578
+ // Get entity by ID
579
+ IEntity entity = (IEntity) Datahike.entity(Datahike.deref(conn), 1);
580
+
581
+ // Access attributes
582
+ String name = (String) entity.valAt(kwd(":name"));
583
+ Long age = (Long) entity.valAt(kwd(":age"));
584
+
585
+ // Touch entity (load all attributes)
586
+ Object touchedEntity = Datahike.touch(entity);
587
+ ```
588
+
589
+ ### Database Metrics
590
+
591
+ ```java
592
+ // Get database statistics
593
+ Map<?, ?> metrics = (Map<?, ?>) Datahike.metrics(
594
+ Datahike.deref(conn)
595
+ );
596
+
597
+ System.out.println(metrics);
598
+ // => {:datoms 1000 :indexed-datoms 1000 ...}
599
+ ```
600
+
601
+ ### Schema Introspection
602
+
603
+ ```java
604
+ // Get current schema
605
+ Map<?, ?> schema = (Map<?, ?>) Datahike.schema(
606
+ Datahike.deref(conn)
607
+ );
608
+
609
+ // Get reverse schema (ident -> attribute map)
610
+ Map<?, ?> reverseSchema = (Map<?, ?>) Datahike.reverseSchema(
611
+ Datahike.deref(conn)
612
+ );
613
+ ```
614
+
615
+ ## Storage Backends
616
+
617
+ ### Memory Backend
618
+
619
+ Fast in-memory storage, requires UUID identifier:
620
+
621
+ ```java
622
+ Map<String, Object> config = Database.memory(UUID.randomUUID())
623
+ .build();
624
+ ```
625
+
626
+ **Use cases:** Testing, caching, temporary data, development.
627
+
628
+ ### File Backend
629
+
630
+ Persistent file-based storage:
631
+
632
+ ```java
633
+ Map<String, Object> config = Database.file("/var/lib/myapp/db")
634
+ .build();
635
+ ```
636
+
637
+ **Use cases:** Local applications, single-server deployments, development persistence.
638
+
639
+ ### Custom Backends
640
+
641
+ Extend Datahike with custom storage implementations:
642
+
643
+ ```java
644
+ Map<String, Object> config = Database.custom(Map.of(
645
+ "backend", ":my-backend",
646
+ "custom-option-1", "value1",
647
+ "custom-option-2", "value2"
648
+ )).build();
649
+ ```
650
+
651
+ Available via plugins: PostgreSQL, S3, Redis, and more.
652
+
653
+ ## Examples
654
+
655
+ ### Complete Application
656
+
657
+ ```java
658
+ import datahike.java.*;
659
+ import static datahike.java.Keywords.*;
660
+ import static datahike.java.Util.*;
661
+ import java.util.*;
662
+
663
+ public class DatahikeExample {
664
+ public static void main(String[] args) {
665
+ // 1. Configure database
666
+ Object schema = vec(
667
+ map(DB_IDENT, kwd(":user/email"),
668
+ DB_VALUE_TYPE, STRING,
669
+ DB_CARDINALITY, ONE,
670
+ DB_UNIQUE, UNIQUE_IDENTITY),
671
+ map(DB_IDENT, kwd(":user/name"),
672
+ DB_VALUE_TYPE, STRING,
673
+ DB_CARDINALITY, ONE)
674
+ );
675
+
676
+ Map<String, Object> config = Database.file("/tmp/app-db")
677
+ .initialTx(schema)
678
+ .schemaFlexibility(SchemaFlexibility.READ)
679
+ .keepHistory(true)
680
+ .build();
681
+
682
+ // 2. Create and connect
683
+ Datahike.createDatabase(config);
684
+ Object conn = Datahike.connect(config);
685
+
686
+ // 3. Add data
687
+ Datahike.transact(conn, List.of(
688
+ Map.of(":user/email", "alice@example.com",
689
+ ":user/name", "Alice"),
690
+ Map.of(":user/email", "bob@example.com",
691
+ ":user/name", "Bob")
692
+ ));
693
+
694
+ // 4. Query data
695
+ Set<?> users = (Set<?>) Datahike.q(
696
+ "[:find ?email ?name :where [?e :user/email ?email] [?e :user/name ?name]]",
697
+ Datahike.deref(conn)
698
+ );
699
+
700
+ System.out.println("Users: " + users);
701
+
702
+ // 5. Update data
703
+ Datahike.transact(conn, List.of(
704
+ Map.of(":user/email", "alice@example.com", // Upsert by unique attr
705
+ ":user/name", "Alice Smith")
706
+ ));
707
+
708
+ // 6. Time travel
709
+ var pastDb = Datahike.asOf(Datahike.deref(conn), new Date(0));
710
+ var pastUsers = Datahike.q(
711
+ "[:find ?name :where [?e :user/name ?name]]",
712
+ pastDb
713
+ );
714
+ System.out.println("Past users: " + pastUsers);
715
+
716
+ // 7. Cleanup
717
+ Datahike.deleteDatabase(config);
718
+ }
719
+ }
720
+ ```
721
+
722
+ ## API Reference
723
+
724
+ Full Javadoc available at: `https://javadoc.io/doc/org.replikativ/datahike/latest/`
725
+
726
+ ### Key Classes
727
+
728
+ - **`Datahike`** - Main API with all database operations
729
+ - **`Database`** - Fluent builder for configuration
730
+ - **`Keywords`** - Pre-defined constants for schema and configuration
731
+ - **`EDN`** - EDN data type constructors and conversion
732
+ - **`Util`** - Low-level utilities (map, vec, kwd, etc.)
733
+ - **`SchemaFlexibility`** - Enum for schema modes
734
+ - **`IEntity`** - Entity interface for direct attribute access
735
+
736
+ ### Core Methods
737
+
738
+ See auto-generated bindings in `Datahike.java` for complete list. All Datahike API functions are available.
739
+
740
+ ## Comparison with Other JVM Databases
741
+
742
+ ### vs Datomic
743
+
744
+ Datahike is Datomic-compatible with similar semantics:
745
+ - ✅ Same query language and API
746
+ - ✅ Same time-travel capabilities
747
+ - ✅ Similar schema system
748
+ - ✅ Open source and free
749
+ - ✅ Multiple storage backends
750
+ - ⚠️ Smaller community and ecosystem, but API compatible
751
+
752
+ ### vs SQL Databases
753
+
754
+ | Feature | Datahike | SQL |
755
+ |---------|----------|-----|
756
+ | Query Language | Declarative Datalog | Declarative SQL |
757
+ | Schema | Optional, flexible | Usually required |
758
+ | Joins | Implicit, natural | Explicit with JOIN |
759
+ | Time Travel | Built-in | Requires audit tables |
760
+ | Immutability | Yes, all data versioned | No, updates in-place |
761
+ | Transactions | ACID | ACID |
762
+
763
+ ## Performance Tips
764
+
765
+ 1. **Use indexes** - Define `:db/index true` for frequently queried attributes
766
+ 2. **Batch transactions** - Transact multiple entities at once
767
+ 3. **Disable history** - Set `:keep-history? false` for write-heavy workloads
768
+ 4. **Pull API** - More efficient than multiple queries for related data
769
+ 5. **Index selection** - Use appropriate index (:eavt, :aevt, :avet) for datoms access
770
+
771
+ ## Troubleshooting
772
+
773
+ ### Common Issues
774
+
775
+ **"Could not locate Clojure runtime"**
776
+ - Ensure Clojure is on your classpath
777
+ - Datahike includes it transitively, but check for conflicts
778
+
779
+ **"Memory backend requires UUID"**
780
+ - Use `UUID.randomUUID()` not string IDs
781
+ - Required by konserve store for distributed tracking
782
+
783
+ **"Schema validation failed"**
784
+ - Check schema flexibility setting
785
+ - Verify attribute definitions match data types
786
+
787
+ **ClassCastException in results**
788
+ - Query results are Clojure collections (Set, List, Map)
789
+ - Cast appropriately: `(Set<?>) Datahike.q(...)`
790
+
791
+ ## Further Reading
792
+
793
+ - [Main README](../README.md) - Project overview and installation
794
+ - [Schema Documentation](schema.md) - Detailed schema guide
795
+ - [Time Travel Guide](time_variance.md) - Historical queries
796
+ - [Storage Backends](storage-backends.md) - Backend configuration
797
+ - [EDN Conversion](bindings/edn-conversion.md) - Java ↔ EDN mapping
798
+ - [Datalog Tutorial](https://docs.datomic.com/on-prem/query.html) - Query language guide
799
+
800
+ ## License
801
+
802
+ Eclipse Public License 1.0 (EPL-1.0)
803
+
804
+ ## Support
805
+
806
+ - **GitHub Issues**: https://github.com/replikativ/datahike/issues
807
+ - **Discussions**: https://github.com/replikativ/datahike/discussions
808
+ - **Professional Support**: Contact christian@weilbach.name for consulting