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,559 @@
1
+ (ns datahike.codegen.native
2
+ "Generate GraalVM C entry points from api.specification.
3
+
4
+ This namespace generates LibDatahike.java containing @CEntryPoint methods
5
+ that expose the Datahike API to native callers via GraalVM Native Image.
6
+
7
+ Key design decisions:
8
+ - Callback-based API (OutputReader) to avoid shared mutable memory
9
+ - String-based data exchange (EDN/JSON/CBOR) for safety
10
+ - Input format strings for temporal variants (history, since, asof)
11
+ - No exposed connection objects - connections are internal"
12
+ (:require [datahike.api.specification :refer [api-specification]]
13
+ [datahike.codegen.naming :as naming]
14
+ [datahike.codegen.validation :as validation]
15
+ [clojure.string :as str]
16
+ [clojure.java.io :as io]))
17
+
18
+ ;; =============================================================================
19
+ ;; Native Operation Configuration
20
+ ;; =============================================================================
21
+
22
+ (def native-operations
23
+ "Operations exposed via native C API.
24
+ Maps operation names to their binding pattern and extra parameters."
25
+ '{;; Database lifecycle - take config, return result
26
+ database-exists?
27
+ {:pattern :config-query
28
+ :java-call "Datahike.databaseExists(readConfig(db_config))"}
29
+
30
+ create-database
31
+ {:pattern :config-mutation
32
+ :java-call "Datahike.createDatabase(readConfig(db_config))"}
33
+
34
+ delete-database
35
+ {:pattern :config-mutation
36
+ :java-call "Datahike.deleteDatabase(readConfig(db_config))"}
37
+
38
+ ;; Query - variable inputs
39
+ q
40
+ {:pattern :query
41
+ :java-call "Datahike.q(CTypeConversion.toJavaString(query_edn), loadInputs(num_inputs, input_formats, raw_inputs))"}
42
+
43
+ ;; Transaction
44
+ transact
45
+ {:pattern :transact
46
+ :java-call "((java.util.Map)Datahike.transact(Datahike.connect(readConfig(db_config)), (java.util.List)loadInput(tx_format, tx_data))).get(Util.kwd(\":tx-meta\"))"}
47
+
48
+ ;; Pull API
49
+ pull
50
+ {:pattern :db-selector-eid
51
+ :java-call "Datahike.pull(loadInput(input_format, raw_input), CTypeConversion.toJavaString(selector_edn), eid)"}
52
+
53
+ pull-many
54
+ {:pattern :db-selector-eids
55
+ :java-call "Datahike.pullMany(loadInput(input_format, raw_input), CTypeConversion.toJavaString(selector_edn), parseIterable(eids_edn))"}
56
+
57
+ ;; Entity
58
+ entity
59
+ {:pattern :db-eid
60
+ :java-call "entityToMap(Datahike.entity(loadInput(input_format, raw_input), eid))"}
61
+
62
+ ;; Index operations
63
+ datoms
64
+ {:pattern :db-index
65
+ :java-call "datomsToVecs((Iterable<?>)Datahike.datoms(loadInput(input_format, raw_input), parseKeyword(index_edn)))"}
66
+
67
+ seek-datoms
68
+ {:pattern :db-index
69
+ :c-name "seek_datoms"
70
+ :java-call "datomsToVecs((Iterable<?>)Datahike.seekDatoms(loadInput(input_format, raw_input), parseKeyword(index_edn)))"}
71
+
72
+ index-range
73
+ {:pattern :db-index-range
74
+ :c-name "index_range"
75
+ :java-call "datomsToVecs((Iterable<?>)Datahike.indexRange(loadInput(input_format, raw_input), Util.map(Util.kwd(\":attrid\"), parseKeyword(attrid_edn), Util.kwd(\":start\"), libdatahike.parseEdn(CTypeConversion.toJavaString(start_edn)), Util.kwd(\":end\"), libdatahike.parseEdn(CTypeConversion.toJavaString(end_edn)))))"}
76
+
77
+ ;; Schema
78
+ schema
79
+ {:pattern :db-only
80
+ :java-call "Datahike.schema(loadInput(input_format, raw_input))"}
81
+
82
+ reverse-schema
83
+ {:pattern :db-only
84
+ :c-name "reverse_schema"
85
+ :java-call "Datahike.reverseSchema(loadInput(input_format, raw_input))"}
86
+
87
+ ;; Diagnostics
88
+ metrics
89
+ {:pattern :db-only
90
+ :java-call "Datahike.metrics(loadInput(input_format, raw_input))"}
91
+
92
+ ;; Maintenance
93
+ gc-storage
94
+ {:pattern :config-timestamp
95
+ :c-name "gc_storage"
96
+ :java-call "Datahike.gcStorage(Datahike.connect(readConfig(db_config)), new Date(before_tx_unix_time_ms))"}})
97
+
98
+ (def native-excluded-operations
99
+ "Operations explicitly excluded from native C API with documented reasons.
100
+
101
+ Each entry maps operation symbol to exclusion reason string."
102
+ '{connect "Connection lifecycle managed internally per C API call"
103
+ release "Connections automatically released after each operation"
104
+ db "Database dereferencing handled internally via input_format parameter"
105
+ listen "Requires persistent callbacks across FFI boundary - not supported"
106
+ unlisten "Requires persistent callbacks across FFI boundary - not supported"
107
+ as-of "Returns DB object - use input_format='asof:timestamp_ms' instead"
108
+ since "Returns DB object - use input_format='since:timestamp_ms' instead"
109
+ history "Returns DB object - use input_format='history' instead"
110
+ filter "Returns DB object - cannot be serialized across FFI boundary"
111
+ with "Pure function better implemented client-side"
112
+ db-with "Pure function better implemented client-side"
113
+ tempid "Temporary IDs only useful within transaction context"
114
+ entity-db "Returns DB from entity - limited utility in FFI context"
115
+ is-filtered "Returns boolean about DB state - limited utility in FFI context"
116
+ transact! "Alias for transact - only need one binding"
117
+ load-entities "Batch loading better done via repeated transact calls"
118
+ query-stats "Query statistics not yet exposed in native API"})
119
+
120
+ ;; =============================================================================
121
+ ;; Naming Conventions
122
+ ;; =============================================================================
123
+
124
+ (defn clj-name->c-name
125
+ "Convert Clojure kebab-case to C snake_case."
126
+ [op-name]
127
+ (-> (name op-name)
128
+ (str/replace #"[!?]$" "")
129
+ (str/replace #"-" "_")))
130
+
131
+ (defn get-c-name
132
+ "Get C function name, using override if specified."
133
+ [op-name config]
134
+ (or (:c-name config) (clj-name->c-name op-name)))
135
+
136
+ ;; =============================================================================
137
+ ;; Documentation Formatting
138
+ ;; =============================================================================
139
+
140
+ (defn format-c-doc
141
+ "Format operation documentation as C-style comment.
142
+
143
+ Includes:
144
+ - Main documentation text
145
+ - Examples from specification (kept as Clojure syntax)
146
+
147
+ Args:
148
+ doc - Documentation string from api-specification
149
+ examples - Example vector from api-specification
150
+
151
+ Returns formatted C doc comment string"
152
+ [doc examples]
153
+ (let [doc-lines (str/split (or doc "No documentation available.") #"\n")
154
+ example-text (when (seq examples)
155
+ (str "\n * \n * Examples:\n"
156
+ (str/join "\n"
157
+ (for [{:keys [desc code]} examples]
158
+ (str " * " desc ":\n"
159
+ " * " code)))))]
160
+ (str " /**\n"
161
+ (str/join "\n" (map #(str " * " %) doc-lines))
162
+ (or example-text "")
163
+ "\n */")))
164
+
165
+ ;; =============================================================================
166
+ ;; Code Generation Templates
167
+ ;; =============================================================================
168
+
169
+ (defn generate-config-query
170
+ "Generate entry point for config-based query operations.
171
+ Pattern: (db_config) -> result"
172
+ [op-name {:keys [java-call doc-comment] :as config}]
173
+ (let [c-name (get-c-name op-name config)]
174
+ (format "%s
175
+ @CEntryPoint(name = \"%s\")
176
+ public static void %s(
177
+ @CEntryPoint.IsolateThreadContext long isolateId,
178
+ @CConst CCharPointer db_config,
179
+ @CConst CCharPointer output_format,
180
+ @CConst OutputReader output_reader) {
181
+ try {
182
+ output_reader.call(toOutput(output_format, %s));
183
+ } catch (Exception e) {
184
+ output_reader.call(toException(e));
185
+ }
186
+ }"
187
+ (or doc-comment "") c-name c-name java-call)))
188
+
189
+ (defn generate-config-mutation
190
+ "Generate entry point for config-based mutation operations.
191
+ Pattern: (db_config) -> void (returns empty string)"
192
+ [op-name {:keys [java-call doc-comment] :as config}]
193
+ (let [c-name (get-c-name op-name config)]
194
+ (format "%s
195
+ @CEntryPoint(name = \"%s\")
196
+ public static void %s(
197
+ @CEntryPoint.IsolateThreadContext long isolateId,
198
+ @CConst CCharPointer db_config,
199
+ @CConst CCharPointer output_format,
200
+ @CConst OutputReader output_reader) {
201
+ try {
202
+ %s;
203
+ output_reader.call(toOutput(output_format, \"\"));
204
+ } catch (Exception e) {
205
+ output_reader.call(toException(e));
206
+ }
207
+ }"
208
+ (or doc-comment "") c-name c-name java-call)))
209
+
210
+ (defn generate-query
211
+ "Generate entry point for query operation.
212
+ Pattern: (query, num_inputs, input_formats[], inputs[]) -> result"
213
+ [op-name {:keys [java-call doc-comment] :as config}]
214
+ (let [c-name (get-c-name op-name config)]
215
+ (format "%s
216
+ @CEntryPoint(name = \"%s\")
217
+ public static void %s(
218
+ @CEntryPoint.IsolateThreadContext long isolateId,
219
+ @CConst CCharPointer query_edn,
220
+ long num_inputs,
221
+ @CConst CCharPointerPointer input_formats,
222
+ @CConst CCharPointerPointer raw_inputs,
223
+ @CConst CCharPointer output_format,
224
+ @CConst OutputReader output_reader) {
225
+ try {
226
+ output_reader.call(toOutput(output_format, %s));
227
+ } catch (Exception e) {
228
+ output_reader.call(toException(e));
229
+ }
230
+ }"
231
+ (or doc-comment "") c-name c-name java-call)))
232
+
233
+ (defn generate-transact
234
+ "Generate entry point for transact operation.
235
+ Pattern: (db_config, tx_format, tx_data) -> tx-meta"
236
+ [op-name {:keys [java-call doc-comment] :as config}]
237
+ (let [c-name (get-c-name op-name config)]
238
+ (format "%s
239
+ @CEntryPoint(name = \"%s\")
240
+ public static void %s(
241
+ @CEntryPoint.IsolateThreadContext long isolateId,
242
+ @CConst CCharPointer db_config,
243
+ @CConst CCharPointer tx_format,
244
+ @CConst CCharPointer tx_data,
245
+ @CConst CCharPointer output_format,
246
+ @CConst OutputReader output_reader) {
247
+ try {
248
+ output_reader.call(toOutput(output_format, %s));
249
+ } catch (Exception e) {
250
+ output_reader.call(toException(e));
251
+ }
252
+ }"
253
+ (or doc-comment "") c-name c-name java-call)))
254
+
255
+ (defn generate-db-only
256
+ "Generate entry point for db-only operations.
257
+ Pattern: (input_format, raw_input) -> result"
258
+ [op-name {:keys [java-call doc-comment] :as config}]
259
+ (let [c-name (get-c-name op-name config)]
260
+ (format "%s
261
+ @CEntryPoint(name = \"%s\")
262
+ public static void %s(
263
+ @CEntryPoint.IsolateThreadContext long isolateId,
264
+ @CConst CCharPointer input_format,
265
+ @CConst CCharPointer raw_input,
266
+ @CConst CCharPointer output_format,
267
+ @CConst OutputReader output_reader) {
268
+ try {
269
+ output_reader.call(toOutput(output_format, %s));
270
+ } catch (Exception e) {
271
+ output_reader.call(toException(e));
272
+ }
273
+ }"
274
+ (or doc-comment "") c-name c-name java-call)))
275
+
276
+ (defn generate-db-eid
277
+ "Generate entry point for db + eid operations.
278
+ Pattern: (input_format, raw_input, eid) -> result"
279
+ [op-name {:keys [java-call doc-comment] :as config}]
280
+ (let [c-name (get-c-name op-name config)]
281
+ (format "%s
282
+ @CEntryPoint(name = \"%s\")
283
+ public static void %s(
284
+ @CEntryPoint.IsolateThreadContext long isolateId,
285
+ @CConst CCharPointer input_format,
286
+ @CConst CCharPointer raw_input,
287
+ long eid,
288
+ @CConst CCharPointer output_format,
289
+ @CConst OutputReader output_reader) {
290
+ try {
291
+ output_reader.call(toOutput(output_format, %s));
292
+ } catch (Exception e) {
293
+ output_reader.call(toException(e));
294
+ }
295
+ }"
296
+ (or doc-comment "") c-name c-name java-call)))
297
+
298
+ (defn generate-db-selector-eid
299
+ "Generate entry point for pull operation.
300
+ Pattern: (input_format, raw_input, selector, eid) -> result"
301
+ [op-name {:keys [java-call doc-comment] :as config}]
302
+ (let [c-name (get-c-name op-name config)]
303
+ (format "%s
304
+ @CEntryPoint(name = \"%s\")
305
+ public static void %s(
306
+ @CEntryPoint.IsolateThreadContext long isolateId,
307
+ @CConst CCharPointer input_format,
308
+ @CConst CCharPointer raw_input,
309
+ @CConst CCharPointer selector_edn,
310
+ long eid,
311
+ @CConst CCharPointer output_format,
312
+ @CConst OutputReader output_reader) {
313
+ try {
314
+ output_reader.call(toOutput(output_format, %s));
315
+ } catch (Exception e) {
316
+ output_reader.call(toException(e));
317
+ }
318
+ }"
319
+ (or doc-comment "") c-name c-name java-call)))
320
+
321
+ (defn generate-db-selector-eids
322
+ "Generate entry point for pull-many operation.
323
+ Pattern: (input_format, raw_input, selector, eids) -> result"
324
+ [op-name {:keys [java-call doc-comment] :as config}]
325
+ (let [c-name (get-c-name op-name config)]
326
+ (format "%s
327
+ @CEntryPoint(name = \"%s\")
328
+ public static void %s(
329
+ @CEntryPoint.IsolateThreadContext long isolateId,
330
+ @CConst CCharPointer input_format,
331
+ @CConst CCharPointer raw_input,
332
+ @CConst CCharPointer selector_edn,
333
+ @CConst CCharPointer eids_edn,
334
+ @CConst CCharPointer output_format,
335
+ @CConst OutputReader output_reader) {
336
+ try {
337
+ output_reader.call(toOutput(output_format, %s));
338
+ } catch (Exception e) {
339
+ output_reader.call(toException(e));
340
+ }
341
+ }"
342
+ (or doc-comment "") c-name c-name java-call)))
343
+
344
+ (defn generate-db-index
345
+ "Generate entry point for index operations.
346
+ Pattern: (input_format, raw_input, index) -> result"
347
+ [op-name {:keys [java-call doc-comment] :as config}]
348
+ (let [c-name (get-c-name op-name config)]
349
+ (format "%s
350
+ @CEntryPoint(name = \"%s\")
351
+ public static void %s(
352
+ @CEntryPoint.IsolateThreadContext long isolateId,
353
+ @CConst CCharPointer input_format,
354
+ @CConst CCharPointer raw_input,
355
+ @CConst CCharPointer index_edn,
356
+ @CConst CCharPointer output_format,
357
+ @CConst OutputReader output_reader) {
358
+ try {
359
+ output_reader.call(toOutput(output_format, %s));
360
+ } catch (Exception e) {
361
+ output_reader.call(toException(e));
362
+ }
363
+ }"
364
+ (or doc-comment "") c-name c-name java-call)))
365
+
366
+ (defn generate-db-index-range
367
+ "Generate entry point for index-range operation.
368
+ Pattern: (input_format, raw_input, attrid, start, end) -> result"
369
+ [op-name {:keys [java-call doc-comment] :as config}]
370
+ (let [c-name (get-c-name op-name config)]
371
+ (format "%s
372
+ @CEntryPoint(name = \"%s\")
373
+ public static void %s(
374
+ @CEntryPoint.IsolateThreadContext long isolateId,
375
+ @CConst CCharPointer input_format,
376
+ @CConst CCharPointer raw_input,
377
+ @CConst CCharPointer attrid_edn,
378
+ @CConst CCharPointer start_edn,
379
+ @CConst CCharPointer end_edn,
380
+ @CConst CCharPointer output_format,
381
+ @CConst OutputReader output_reader) {
382
+ try {
383
+ output_reader.call(toOutput(output_format, %s));
384
+ } catch (Exception e) {
385
+ output_reader.call(toException(e));
386
+ }
387
+ }"
388
+ (or doc-comment "") c-name c-name java-call)))
389
+
390
+ (defn generate-config-timestamp
391
+ "Generate entry point for config + timestamp operations.
392
+ Pattern: (db_config, timestamp_ms) -> result"
393
+ [op-name {:keys [java-call doc-comment] :as config}]
394
+ (let [c-name (get-c-name op-name config)]
395
+ (format "%s
396
+ @CEntryPoint(name = \"%s\")
397
+ public static void %s(
398
+ @CEntryPoint.IsolateThreadContext long isolateId,
399
+ @CConst CCharPointer db_config,
400
+ long before_tx_unix_time_ms,
401
+ @CConst CCharPointer output_format,
402
+ @CConst OutputReader output_reader) {
403
+ try {
404
+ output_reader.call(toOutput(output_format, %s));
405
+ } catch (Exception e) {
406
+ output_reader.call(toException(e));
407
+ }
408
+ }"
409
+ (or doc-comment "") c-name c-name java-call)))
410
+
411
+ ;; =============================================================================
412
+ ;; Entry Point Generation
413
+ ;; =============================================================================
414
+
415
+ (defn generate-entry-point
416
+ "Generate a single @CEntryPoint method.
417
+
418
+ Args:
419
+ op-name - Operation symbol from api-specification
420
+ spec - Full specification from api-specification
421
+ overlay - Native-specific overlay configuration
422
+
423
+ Returns generated Java code string"
424
+ [op-name spec overlay]
425
+ (let [;; Merge spec and overlay, adding formatted documentation
426
+ doc-comment (format-c-doc (:doc spec) (:examples spec))
427
+ config (assoc overlay :doc-comment doc-comment)
428
+ ;; Select appropriate generator based on pattern
429
+ generator (case (:pattern overlay)
430
+ :config-query generate-config-query
431
+ :config-mutation generate-config-mutation
432
+ :query generate-query
433
+ :transact generate-transact
434
+ :db-only generate-db-only
435
+ :db-eid generate-db-eid
436
+ :db-selector-eid generate-db-selector-eid
437
+ :db-selector-eids generate-db-selector-eids
438
+ :db-index generate-db-index
439
+ :db-index-range generate-db-index-range
440
+ :config-timestamp generate-config-timestamp
441
+ (throw (ex-info (str "Unknown pattern: " (:pattern overlay))
442
+ {:op-name op-name :overlay overlay})))]
443
+ (generator op-name config)))
444
+
445
+ (defn generate-all-entry-points
446
+ "Generate all @CEntryPoint methods using overlay model.
447
+
448
+ Iterates over api-specification, checking each operation against:
449
+ - native-operations (overlay config)
450
+ - native-excluded-operations (exclusions)
451
+
452
+ Operations must be either implemented or excluded."
453
+ []
454
+ (let [all-ops api-specification
455
+ implemented (keys native-operations)
456
+ excluded (keys native-excluded-operations)]
457
+ (->> all-ops
458
+ (keep (fn [[op-name spec]]
459
+ (cond
460
+ ;; Explicitly excluded - skip
461
+ (contains? (set excluded) op-name)
462
+ nil
463
+
464
+ ;; Has overlay config - generate it
465
+ (contains? native-operations op-name)
466
+ (let [overlay (get native-operations op-name)]
467
+ (generate-entry-point op-name spec overlay))
468
+
469
+ ;; Missing overlay - warn (but continue)
470
+ :else
471
+ (do
472
+ (println (str "⚠️ WARNING: No native overlay for operation: " op-name))
473
+ nil))))
474
+ (str/join "\n"))))
475
+
476
+ ;; =============================================================================
477
+ ;; File Generation
478
+ ;; =============================================================================
479
+
480
+ (def file-header
481
+ "package datahike.impl;
482
+
483
+ import org.graalvm.nativeimage.c.function.CEntryPoint;
484
+ import org.graalvm.nativeimage.c.type.CCharPointer;
485
+ import org.graalvm.nativeimage.c.type.CCharPointerPointer;
486
+ import org.graalvm.nativeimage.c.type.CConst;
487
+ import org.graalvm.nativeimage.c.type.CTypeConversion;
488
+ import datahike.java.Datahike;
489
+ import datahike.java.Util;
490
+ import datahike.impl.libdatahike;
491
+ import java.util.Date;
492
+
493
+ /**
494
+ * Generated C entry points for libdatahike.
495
+ *
496
+ * This file is auto-generated from datahike.api.specification.
497
+ * DO NOT EDIT MANUALLY - changes will be overwritten.
498
+ *
499
+ * To regenerate: bb codegen-native
500
+ *
501
+ * All entry points use callback-based return (OutputReader) to:
502
+ * - Avoid shared mutable memory between native and JVM
503
+ * - Support multiple output formats (json, edn, cbor)
504
+ * - Enable proper exception handling
505
+ *
506
+ * Input format strings for temporal queries:
507
+ * - \"db\" : Current database state
508
+ * - \"history\" : Full history including retractions
509
+ * - \"since:{timestamp_ms}\" : Database since timestamp
510
+ * - \"asof:{timestamp_ms}\" : Database as-of timestamp
511
+ */
512
+ public final class LibDatahike extends LibDatahikeBase {
513
+ ")
514
+
515
+ (def file-footer
516
+ "
517
+ // Note: history/since/as-of are handled via input format strings
518
+ // e.g., input_format=\"history\" or \"since:1234567890\"
519
+
520
+ // seekdatoms returns lazy sequence - results are fully realized
521
+ // release not exposed - connections are created internally per call
522
+ }
523
+ ")
524
+
525
+ (defn generate-file-content
526
+ "Generate complete LibDatahike.java content."
527
+ []
528
+ (str file-header
529
+ (generate-all-entry-points)
530
+ file-footer))
531
+
532
+ (defn write-libdatahike!
533
+ "Write generated LibDatahike.java to output directory."
534
+ [output-dir]
535
+ (let [output-path (str output-dir "/datahike/impl/LibDatahike.java")
536
+ content (generate-file-content)]
537
+ (io/make-parents output-path)
538
+ (spit output-path content)
539
+ (println "Generated:" output-path)))
540
+
541
+ ;; =============================================================================
542
+ ;; Main Entry Point
543
+ ;; =============================================================================
544
+
545
+ (defn -main
546
+ "Generate native bindings with coverage validation.
547
+ Usage: clojure -M -m datahike.codegen.native <output-dir>"
548
+ [& args]
549
+ (let [output-dir (or (first args) "libdatahike/src-generated")]
550
+ (println "Generating native C entry points from specification...")
551
+
552
+ ;; Validate coverage
553
+ (validation/validate-coverage "Native" native-operations native-excluded-operations)
554
+ (validation/validate-exclusion-reasons "Native" native-excluded-operations)
555
+ (validation/validate-overlay-completeness "Native" native-operations [:pattern :java-call])
556
+
557
+ ;; Generate bindings
558
+ (write-libdatahike! output-dir)
559
+ (println "Done.")))