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,210 @@
1
+ # Why Datalog?
2
+
3
+ Datalog is a declarative query language that excels at expressing complex relationships in graph-structured data. While SQL handles tabular data well, modern applications increasingly need to model interconnected entities—social networks, organizational hierarchies, supply chains, knowledge graphs.
4
+
5
+ ## When SQL Falls Short
6
+
7
+ **The problem**: As applications evolve, relational schemas accumulate join complexity. What starts as simple tables becomes a maze of foreign keys, junction tables, and nested subqueries. Developers spend more time managing joins than expressing business logic.
8
+
9
+ **Common pattern**: Start with SQL for simplicity → encounter complex relationships → add more joins → build ad-hoc graph features → end up with fragile, hard-to-maintain queries.
10
+
11
+ **Datalog's approach**: Pattern matching over relationships. Instead of explicitly specifying how to join tables, you describe what patterns you're looking for. The query engine handles traversal.
12
+
13
+ ## Query Comparison
14
+
15
+ Let's find all projects where someone manages a team member who contributed to that project.
16
+
17
+ ### SQL Approach
18
+
19
+ ```sql
20
+ SELECT DISTINCT
21
+ m.name AS manager_name,
22
+ e.name AS employee_name,
23
+ p.name AS project_name
24
+ FROM employees m
25
+ JOIN manager_relationships mr ON m.id = mr.manager_id
26
+ JOIN employees e ON mr.employee_id = e.id
27
+ JOIN project_contributors pc ON e.id = pc.employee_id
28
+ JOIN projects p ON pc.project_id = p.id
29
+ WHERE m.id != e.id;
30
+ ```
31
+
32
+ This requires:
33
+ - Understanding the table structure (4 tables, 3 join conditions)
34
+ - Explicit join order management
35
+ - Mental model of how data flows through joins
36
+
37
+ ### Datalog Approach
38
+
39
+ ```clojure
40
+ (d/q '[:find ?manager-name ?employee-name ?project-name
41
+ :where
42
+ [?manager :employee/manages ?employee]
43
+ [?employee :project/contributed-to ?project]
44
+ [?manager :employee/name ?manager-name]
45
+ [?employee :employee/name ?employee-name]
46
+ [?project :project/name ?project-name]]
47
+ db)
48
+ ```
49
+
50
+ Pattern matching expresses intent:
51
+ - "Find managers who manage employees"
52
+ - "Find employees who contributed to projects"
53
+ - "Get their names"
54
+
55
+ No explicit joins. No table knowledge required. The relationships are first-class.
56
+
57
+ ## More Complex: Transitive Relationships
58
+
59
+ Find all skills accessible through management chain (managers inherit team skills).
60
+
61
+ ### SQL
62
+
63
+ ```sql
64
+ WITH RECURSIVE management_chain AS (
65
+ -- Base case: direct reports
66
+ SELECT manager_id, employee_id, 1 as depth
67
+ FROM manager_relationships
68
+
69
+ UNION ALL
70
+
71
+ -- Recursive case: indirect reports
72
+ SELECT mc.manager_id, mr.employee_id, mc.depth + 1
73
+ FROM management_chain mc
74
+ JOIN manager_relationships mr ON mc.employee_id = mr.manager_id
75
+ WHERE mc.depth < 10 -- Prevent infinite recursion
76
+ )
77
+ SELECT DISTINCT
78
+ m.name AS manager_name,
79
+ s.name AS accessible_skill
80
+ FROM employees m
81
+ JOIN management_chain mc ON m.id = mc.manager_id
82
+ JOIN employee_skills es ON mc.employee_id = es.employee_id
83
+ JOIN skills s ON es.skill_id = s.id;
84
+ ```
85
+
86
+ Requires:
87
+ - Understanding recursive CTEs
88
+ - Managing recursion depth manually
89
+ - Multiple joins to assemble result
90
+
91
+ ### Datalog with Rules
92
+
93
+ ```clojure
94
+ ;; Define a rule for transitive management
95
+ (d/q '[:find ?manager-name ?skill-name
96
+ :in $ %
97
+ :where
98
+ (manages-recursively ?manager ?employee)
99
+ [?employee :employee/has-skill ?skill]
100
+ [?manager :employee/name ?manager-name]
101
+ [?skill :skill/name ?skill-name]]
102
+ db
103
+ '[;; Rule definition
104
+ [(manages-recursively ?m ?e)
105
+ [?m :employee/manages ?e]]
106
+ [(manages-recursively ?m ?e)
107
+ [?m :employee/manages ?x]
108
+ (manages-recursively ?x ?e)]])
109
+ ```
110
+
111
+ **Rules encapsulate logic**: `manages-recursively` handles the transitive relationship. Reusable across queries.
112
+
113
+ ## Graph Traversal: Friend Recommendations
114
+
115
+ Find friends-of-friends who share interests, excluding existing friends.
116
+
117
+ ### SQL
118
+
119
+ ```sql
120
+ SELECT DISTINCT
121
+ p1.name AS person_name,
122
+ p3.name AS recommendation_name,
123
+ i.name AS shared_interest
124
+ FROM people p1
125
+ JOIN friendships f1 ON p1.id = f1.person_id
126
+ JOIN people p2 ON f1.friend_id = p2.id
127
+ JOIN friendships f2 ON p2.id = f2.person_id
128
+ JOIN people p3 ON f2.friend_id = p3.id
129
+ JOIN person_interests pi1 ON p1.id = pi1.person_id
130
+ JOIN person_interests pi3 ON p3.id = pi3.person_id
131
+ JOIN interests i ON pi1.interest_id = i.id AND pi3.interest_id = i.id
132
+ LEFT JOIN friendships f_check ON (p1.id = f_check.person_id AND p3.id = f_check.friend_id)
133
+ WHERE p1.id != p3.id
134
+ AND f_check.person_id IS NULL; -- Not already friends
135
+ ```
136
+
137
+ 8 joins, complex exclusion logic, hard to maintain.
138
+
139
+ ### Datalog
140
+
141
+ ```clojure
142
+ (d/q '[:find ?person-name ?recommendation-name ?interest-name
143
+ :where
144
+ [?person :person/friend ?friend]
145
+ [?friend :person/friend ?recommendation]
146
+ [?person :person/interest ?interest]
147
+ [?recommendation :person/interest ?interest]
148
+ [(not= ?person ?recommendation)]
149
+ (not [?person :person/friend ?recommendation])
150
+ [?person :person/name ?person-name]
151
+ [?recommendation :person/name ?recommendation-name]
152
+ [?interest :interest/name ?interest-name]]
153
+ db)
154
+ ```
155
+
156
+ **Natural expression**: Each line describes one relationship pattern. Negation uses `not` clause rather than LEFT JOIN tricks.
157
+
158
+ ## Multi-Database Queries
159
+
160
+ Datalog can query across multiple databases in a single query—useful for data federation or comparing environments.
161
+
162
+ ```clojure
163
+ ;; Compare production and staging: Find entities in staging not in production
164
+ (d/q '[:find ?name ?value
165
+ :in $staging $prod
166
+ :where
167
+ [$staging ?e :entity/name ?name]
168
+ [$staging ?e :entity/value ?value]
169
+ (not [$prod ?e2 :entity/name ?name])]
170
+ staging-db prod-db)
171
+ ```
172
+
173
+ SQL would require UNION queries, temporary tables, or separate queries with application-level comparison.
174
+
175
+ ## When to Use Datalog
176
+
177
+ **Choose Datalog when:**
178
+ - Modeling interconnected entities (social graphs, org charts, supply chains)
179
+ - Need recursive or transitive queries
180
+ - Schema evolves frequently (schema-less or flexible schema)
181
+ - Want to express logic through rules
182
+ - Query across multiple databases or time points
183
+ - Building knowledge graphs or semantic systems
184
+
185
+ **SQL still wins for:**
186
+ - Pure tabular data with minimal relationships
187
+ - Standard BI tool integration
188
+ - Window functions and complex aggregations over large sorted sets
189
+ - Existing SQL infrastructure and expertise
190
+
191
+ ## Performance Note
192
+
193
+ Datalog query engines (including Datahike) use sophisticated join optimization. Performance is comparable to well-tuned SQL for most queries. For specific workloads, see our [benchmarks](https://gitlab.com/arbetsformedlingen/taxonomy-dev/backend/experimental/datahike-benchmark/).
194
+
195
+ ## Learning Datalog
196
+
197
+ Datalog syntax is minimal:
198
+ - Pattern matching: `[?entity :attribute ?value]`
199
+ - Rules: Define reusable logic patterns
200
+ - Negation: `(not ...)`
201
+ - Functions: `[(function arg) result]`
202
+
203
+ Most developers become productive within hours. The conceptual shift from imperative joins to declarative patterns is the main learning curve, not syntax complexity.
204
+
205
+ ## Further Reading
206
+
207
+ - [Datalog Wikipedia](https://en.wikipedia.org/wiki/Datalog) - Academic background
208
+ - [Learn Datalog Today](http://www.learndatalogtoday.org/) - Interactive tutorial
209
+ - [Datomic Query Documentation](https://docs.datomic.com/query/query.html) - Datahike uses compatible query syntax
210
+ - [Datahike Query Guide](https://cljdoc.org/d/org.replikativ/datahike/CURRENT/doc/query) - Full query capabilities
@@ -0,0 +1,109 @@
1
+ # Differences to Datomic Client API
2
+
3
+ Although Datahike supports a part of [Datomic's
4
+ API](https://docs.datomic.com/client-api/datomic.client.api.html), some
5
+ behavior is different using the different functions. Datahike supports part of the `datomic.client.api`:
6
+
7
+ [![cljdoc](https://badgen.net/badge/cljdoc/datahike/blue)](https://cljdoc.org/d/org.replikativ/datahike)
8
+
9
+ Without differences in the signature you may use the following like in Datomic:
10
+
11
+ - as-of
12
+ - datoms
13
+ - [db](#db)
14
+ - history
15
+ - pull
16
+ - q
17
+ - since
18
+ - [transact](#transact)
19
+
20
+ Please be aware that `q` returns sets instead of vectors. Only when using aggregates or `:with`, `q` returns a
21
+ vector. That is the behavior of Datascript.
22
+
23
+ The following functions from the `datahike.api` namespace are different from Datomic's client API:
24
+
25
+ - [connect](#connect)
26
+ - [create-database](#create-database)
27
+ - [database-exists?](#database-exists)
28
+ - [db-with](https://cljdoc.org/d/org.replikativ/datahike/0.3.6/api/datahike.api#db-with)
29
+ - [delete-database](#delete-database)
30
+ - [entity](https://cljdoc.org/d/org.replikativ/datahike/0.3.6/api/datahike.api#entity)
31
+ - [entity-db](https://cljdoc.org/d/org.replikativ/datahike/0.3.6/api/datahike.api#entity-db)
32
+ - [filter](https://cljdoc.org/d/org.replikativ/datahike/0.3.6/api/datahike.api#filter)
33
+ - [is-filtered](https://cljdoc.org/d/org.replikativ/datahike/0.3.6/api/datahike.api#is-filtered)
34
+ - [load-entities](https://cljdoc.org/d/org.replikativ/datahike/0.3.6/api/datahike.api#load-entities)
35
+ - [pull-many](https://cljdoc.org/d/org.replikativ/datahike/0.3.6/api/datahike.api#pull-many)
36
+ - [release](https://cljdoc.org/d/org.replikativ/datahike/0.3.6/api/datahike.api#release)
37
+ - [seek-datoms](https://cljdoc.org/d/org.replikativ/datahike/0.3.6/api/datahike.api#seek-datoms)
38
+ - [tempid](https://cljdoc.org/d/org.replikativ/datahike/0.3.6/api/datahike.api#tempid)
39
+ - [with](#with)
40
+
41
+ Additionally, datahike supports most functions from [datascript](https://github.com/tonsky/datascript)
42
+ in the `datahike.api` namespace.
43
+
44
+ These functions of Datomic are not yet implemented but considered candidates for future development:
45
+ - tx-range
46
+ - index-pull
47
+ - with-db
48
+
49
+ These functions are part of Datomics' distributed implementation and are currently not part of the
50
+ Datahike API:
51
+ - client
52
+ - administer-system
53
+ - db-stats
54
+ - list-databases
55
+ - sync
56
+
57
+ Async support is on our roadmap as well as running distributed Datahike.
58
+
59
+ ## connect
60
+
61
+ Connects to an existing database given the configuration hash-map where Datomic
62
+ takes a client as argument. The specification for the configuration can be found
63
+ [here](./config.md).
64
+
65
+ [![cljdoc](https://badgen.net/badge/cljdoc/datahike/blue)](https://cljdoc.org/d/org.replikativ/datahike)
66
+
67
+ ## create-database
68
+
69
+ Creates a new database with the given configuration hash-map where Datomic takes a client and an
70
+ arg-map as arguments. Additional optional parameters are `schema-flexibility`, `keep-history?`
71
+ and `initial-tx`. Have a look at the [configuration documentation](./config.md) for details.
72
+
73
+ [![cljdoc](https://badgen.net/badge/cljdoc/datahike/blue)](https://cljdoc.org/d/org.replikativ/datahike)
74
+
75
+ ## delete-database
76
+
77
+ Deletes a database with the configuration hash-map as argument.
78
+
79
+ ## database-exists?
80
+
81
+ Checks if a database exists with the configuration hash-map as argument.
82
+
83
+ ## db
84
+
85
+ Since the database can be just de-referenced from the connection this function is
86
+ just a small wrapper for Datomic compliance.
87
+
88
+ ```clojure
89
+ (db conn)
90
+ ```
91
+ equivalent to:
92
+ ```
93
+ @conn
94
+ ```
95
+
96
+ ## transact
97
+
98
+ Returns a hash map different from Datomics' as a report. The `:tx-meta` is not part
99
+ of Datomics' transaction report but apart from that the same keys are present. The
100
+ values are different records though.
101
+
102
+ [![cljdoc](https://badgen.net/badge/cljdoc/datahike/blue)](https://cljdoc.org/d/org.replikativ/datahike)
103
+
104
+ ## with
105
+
106
+ Applies transactions to an immutable database value and returns a new database
107
+ snapshot. It does not change the mutable database inside the connection unlike
108
+ [transact](#transact). It works quite the same as Datomics' `with` but does
109
+ not need a `with-db` function to work.
@@ -0,0 +1,186 @@
1
+ # Pull-API Namespace
2
+
3
+ This document is aimed at Datahike core developers that want to debug or extend the Pull-API.
4
+ Hopefully, this will help people getting a grip of the existing code and work flow of the Pull-API.
5
+
6
+ ## Terminology
7
+
8
+ ### Selector
9
+
10
+ A quoted vector holding one or several of the following expressions:
11
+ 1) wildcard
12
+ - pulls all datoms for entity id
13
+ - e.g. `*` -> `{:db/id 1 :name "Petr" :child [{:db/id 2}]}`
14
+ 2) keyword for
15
+ - attributes to get
16
+ - e.g. `:child` (= has child) -> `{:child [#:db{:id 10}]}`
17
+ - reverse attributes to get (datom where requested entity is referenced)
18
+ - signaled by underscore
19
+ - e.g. `:_child` (= child of) -> `{:_child [#:db{:id 1}]}`
20
+ 3) map of keywords for (reverse) attributes to get and
21
+ - vectors of attributes
22
+ - attribute should be reference
23
+ - e.g. `{:child [:name :age]}` -> `{:child {:name "Thomas" :age 10}}`
24
+ - e.g. `{:_child [:name :age]}` -> `{:_child {:name "Charles" :age 10}}`
25
+ - three dots
26
+ - for the infinite recursion on an attribute
27
+ - number
28
+ - for the finite recursion on an attribute
29
+ 4) function call form:
30
+ - limit:
31
+ - restricts the amount of pulled datoms to the given number
32
+ - e.g. `(limit :child 2)`
33
+ - defaults:
34
+ - sets a default value if search returns nil
35
+ - e.g. `(default :name "unknown")`
36
+ 5) vectors of 3
37
+ - functions of 4) in vector form
38
+ - attribute, function name as keyword, parameter
39
+ - e.g. `[:child :limit 2]` or `[:name :default "unknown"]`
40
+ - renaming of attributes with :as
41
+ - attribute, :as, new name
42
+ - e.g. `[:aka :as :alias]` or `[:name :as "Name"]`
43
+
44
+ ### Pattern = (Pull-)Spec
45
+
46
+ Record with keys
47
+ - `:wildcard?` = boolean value indicating if wildcard expansion has to be done
48
+ - `:attrs` = map of attribute names as in selector and map with keys
49
+ - `:attr` = attribute name as in database; only different from key when key describes reverse attribute
50
+ - `:subpattern` (optional) = spec of a subpattern applied to an attribute
51
+ - `:recursion` = always nil, only checks if key exists, if it does: recursion is applied on attribute
52
+ - `:limit`= amount of maximum number of results returned
53
+ - `:default` = default value if nothing found
54
+
55
+
56
+ ### Frame
57
+
58
+ Map with keys
59
+ - `:multi?` = true if multiple entities requested
60
+ - `:eids` = vector of eids to pull pattern for
61
+ - `:state` = pattern/expand/expand-rev/recursion/done
62
+ - `:pattern` = (Pull-)Spec
63
+ - `:recursion` = map with keys :depth (depth per attribute) and :seen (eids)
64
+ - `:specs` = attrs from spec
65
+ - `:wildcard?` = wildcard from spec
66
+ - `:kvps` = final result map; in pull-pattern transfered to next frame when current frame is done
67
+ - `:results` = result map for current frame, i.e. for current attribute
68
+ - `:attr` = optional; current attribute (pull-attr-datoms) or enum, e.g. recursion
69
+ - `:datoms` = optional; datoms pulled from database; e.g. added by wildcard-expand
70
+ - `:expand-kvps` = optional; added by expand-frame, used by expand-rev-frame
71
+
72
+ #### Frame Creation and State Changes
73
+
74
+ - only 1 frame created for basic input pattern
75
+ - additional frames added on processing of
76
+ - recursion: 2 frames per depth
77
+ - wildcard: 1 frame
78
+
79
+ ![Frame State Diagram](https://raw.githubusercontent.com/replikativ/datahike/documentation/doc/development/pull-frame-state-diagram.jpg)
80
+
81
+ ## Pull API Usage
82
+
83
+ See also the official [Datahike documentation](https://cljdoc.org/d/org.replikativ/datahike/0.3.2/api/datahike.api#pull).
84
+
85
+ Setup for examples:
86
+
87
+ ```clojure
88
+ (require '(datahike [core :as d]))
89
+
90
+ (def schema
91
+ {:aka {:db/cardinality :db.cardinality/many}
92
+ :child {:db/cardinality :db.cardinality/many
93
+ :db/valueType :db.type/ref}
94
+ :friend {:db/cardinality :db.cardinality/many
95
+ :db/valueType :db.type/ref}
96
+ :father {:db/valueType :db.type/ref}
97
+ :spec {:db/valueType :db.type/ref
98
+ :db/isComponent true
99
+ :db/cardinality :db.cardinality/one}})
100
+
101
+ (def datoms
102
+ (->>
103
+ [[1 :name "Petr"]
104
+ [1 :aka "Devil"]
105
+ [1 :aka "Tupen"]
106
+ [1 :aka "P"]
107
+ [2 :name "David"]
108
+ [3 :name "Thomas"]
109
+ [4 :name "Lucy"]
110
+ [5 :name "Elizabeth"]
111
+ [6 :name "Matthew"]
112
+ [7 :name "Eunan"]
113
+ [8 :name "Kerri"]
114
+ [9 :name "Rebecca"]
115
+ [1 :child 2]
116
+ [1 :child 3]
117
+ [2 :father 1]
118
+ [3 :father 1]
119
+ [6 :father 3]
120
+ [4 :friend 5]
121
+ [5 :friend 6]]
122
+ (map (fn [[e a v]] (d/datom e a v tx0)))))
123
+
124
+ (def example-db (d/init-db datoms schema))
125
+ ```
126
+
127
+ ### Examples
128
+
129
+
130
+ Simple Pull
131
+ ```clojure
132
+ (d/pull example-db '[:name] 1)
133
+
134
+ ;; => {:name "Petr"}
135
+ ```
136
+
137
+ Pull reverse attribute
138
+ ```clojure
139
+ (d/pull example-db '[:_child] 2)
140
+
141
+ ;; => {:_child [#:db{:id 1}]}
142
+ ```
143
+
144
+ Pull db/id
145
+
146
+ ```clojure
147
+ (d/pull example-db '[:name :db/id] 6)
148
+
149
+ ;; => {:name "Matthew", :db/id 6}
150
+ ```
151
+
152
+ Pull wildcard
153
+ ```clojure
154
+ (d/pull example-db '[*] 2)
155
+
156
+ ;; => {:db/id 2, :father #:db{:id 1}, :name "David"}
157
+ ```
158
+
159
+ Pull recursion
160
+ ```clojure
161
+ (d/pull example-db '[:db/id :name {:friend ...}] 4)
162
+
163
+ ;; => {:db/id 4, :name "Lucy", :friend [{:db/id 5, :name "Elizabeth", :friend [{:db/id 6, :name "Matthew"}]}]}
164
+ ```
165
+
166
+ Pull with default
167
+ ```clojure
168
+ (d/pull example-db '[(default :foo "bar")] 1)
169
+
170
+ ;; => {:foo "bar"}
171
+ ```
172
+
173
+ Pull with limit
174
+ ```clojure
175
+ (d/pull example-db '[(limit :aka 2)] 1)
176
+
177
+ ;; => {:aka ["Devil" "Tupen"]}
178
+ ```
179
+
180
+ Pull with subpattern
181
+ ```clojure
182
+ (d/pull example-db '[{:father [:name]}] 6)
183
+
184
+ ;; => {:father {:name "Thomas"}}
185
+ ```
186
+