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,557 @@
1
+ // Comprehensive test for reorganized JS API - covers all nodejs_test.cljs functionality
2
+ const d = require('./datahike.js.api.js');
3
+ const crypto = require('crypto');
4
+ const fs = require('fs');
5
+ const os = require('os');
6
+ const path = require('path');
7
+
8
+ // Helper to generate UUID for store :id
9
+ function generateUUID() {
10
+ return crypto.randomUUID();
11
+ }
12
+
13
+ // Helper to find entity ID by name
14
+ async function findEntityByName(db, name) {
15
+ const datoms = await d.datoms(db, ':eavt');
16
+ if (!datoms) return null;
17
+
18
+ // Find datom where attribute is :name and value matches
19
+ for (const datom of datoms) {
20
+ if (datom.a && datom.a.fqn === 'name' && datom.v === name) {
21
+ return datom.e;
22
+ }
23
+ }
24
+ return null;
25
+ }
26
+
27
+ // Helper to create temp directory
28
+ function tmpDir() {
29
+ return path.join(os.tmpdir(), `datahike-js-test-${Date.now()}-${Math.floor(Math.random() * 10000)}`);
30
+ }
31
+
32
+ async function testBasicOperations() {
33
+ console.log('\n=== Test 1: Basic Database Operations ===');
34
+
35
+ const config = {
36
+ store: { backend: ':memory', id: generateUUID() }
37
+ };
38
+
39
+ console.log(' Creating database...');
40
+ await d.createDatabase(config);
41
+
42
+ console.log(' Checking existence...');
43
+ const exists = await d.databaseExists(config);
44
+ if (!exists) throw new Error('Database should exist');
45
+ console.log(' ✓ Database exists');
46
+
47
+ console.log(' Connecting...');
48
+ const conn = await d.connect(config);
49
+ console.log(' ✓ Connected');
50
+
51
+ console.log(' Getting DB value...');
52
+ const db = await d.db(conn);
53
+ if (!db) throw new Error('DB value should exist');
54
+ console.log(' ✓ DB value retrieved');
55
+
56
+ d.release(conn);
57
+ await d.deleteDatabase(config);
58
+
59
+ const existsAfter = await d.databaseExists(config);
60
+ if (existsAfter) throw new Error('Database should not exist after deletion');
61
+ console.log(' ✓ Database deleted');
62
+ }
63
+
64
+ async function testSchemaAndTransactions() {
65
+ console.log('\n=== Test 2: Schema and Transactions ===');
66
+
67
+ const config = {
68
+ store: { backend: ':memory', id: generateUUID() }
69
+ };
70
+
71
+ await d.createDatabase(config);
72
+ const conn = await d.connect(config);
73
+
74
+ console.log(' Transacting schema...');
75
+ const schema = [
76
+ {
77
+ 'db/ident': ':name',
78
+ 'db/valueType': ':db.type/string',
79
+ 'db/cardinality': ':db.cardinality/one'
80
+ },
81
+ {
82
+ 'db/ident': ':age',
83
+ 'db/valueType': ':db.type/long',
84
+ 'db/cardinality': ':db.cardinality/one'
85
+ },
86
+ {
87
+ 'db/ident': ':email',
88
+ 'db/valueType': ':db.type/string',
89
+ 'db/cardinality': ':db.cardinality/one'
90
+ }
91
+ ];
92
+
93
+ const schemaTx = await d.transact(conn, schema);
94
+ if (!schemaTx['tx-data'] || schemaTx['tx-data'].length === 0) {
95
+ throw new Error('Schema transaction should have datoms');
96
+ }
97
+ console.log(` ✓ Schema transacted (${schemaTx['tx-data'].length} datoms)`);
98
+
99
+ console.log(' Transacting data...');
100
+ const data = [
101
+ { name: 'Alice', age: 30, email: 'alice@example.com' },
102
+ { name: 'Bob', age: 25, email: 'bob@example.com' },
103
+ { name: 'Charlie', age: 35, email: 'charlie@example.com' }
104
+ ];
105
+
106
+ const dataTx = await d.transact(conn, data);
107
+ console.log(` ✓ Data transacted (${dataTx['tx-data'].length} datoms)`);
108
+
109
+ d.release(conn);
110
+ await d.deleteDatabase(config);
111
+ }
112
+
113
+ async function testDatomsAPI() {
114
+ console.log('\n=== Test 3: Datoms API ===');
115
+
116
+ const config = {
117
+ store: { backend: ':memory', id: generateUUID() }
118
+ };
119
+
120
+ await d.createDatabase(config);
121
+ const conn = await d.connect(config);
122
+
123
+ const schema = [
124
+ { 'db/ident': ':name', 'db/valueType': ':db.type/string', 'db/cardinality': ':db.cardinality/one' },
125
+ { 'db/ident': ':age', 'db/valueType': ':db.type/long', 'db/cardinality': ':db.cardinality/one' }
126
+ ];
127
+ await d.transact(conn, schema);
128
+
129
+ const data = [
130
+ { name: 'Alice', age: 30 },
131
+ { name: 'Bob', age: 25 }
132
+ ];
133
+ await d.transact(conn, data);
134
+
135
+ console.log(' Getting datoms from EAVT index...');
136
+ const db = await d.db(conn);
137
+ const eavtDatoms = await d.datoms(db, ':eavt');
138
+ console.log(` ✓ EAVT datoms: ${eavtDatoms.length}`);
139
+
140
+ console.log(' Getting datoms from AVET index...');
141
+ const avetDatoms = await d.datoms(db, ':avet');
142
+ console.log(` ✓ AVET datoms: ${avetDatoms.length}`);
143
+
144
+ console.log(' Finding name datoms from EAVT...');
145
+ const eavtForNames = await d.datoms(db, ':eavt');
146
+ const nameDatoms = eavtForNames.filter(d => d.a && d.a.fqn === 'name');
147
+ if (nameDatoms.length !== 2) {
148
+ throw new Error(`Expected 2 name datoms, got ${nameDatoms.length}`);
149
+ }
150
+ console.log(` ✓ Name datoms: ${nameDatoms.length}`);
151
+
152
+ d.release(conn);
153
+ await d.deleteDatabase(config);
154
+ }
155
+
156
+ async function testPullAPI() {
157
+ console.log('\n=== Test 4: Pull API ===');
158
+
159
+ const config = {
160
+ store: { backend: ':memory', id: generateUUID() }
161
+ };
162
+
163
+ await d.createDatabase(config);
164
+ const conn = await d.connect(config);
165
+
166
+ const schema = [
167
+ { 'db/ident': ':name', 'db/valueType': ':db.type/string', 'db/cardinality': ':db.cardinality/one' },
168
+ { 'db/ident': ':age', 'db/valueType': ':db.type/long', 'db/cardinality': ':db.cardinality/one' },
169
+ { 'db/ident': ':email', 'db/valueType': ':db.type/string', 'db/cardinality': ':db.cardinality/one' }
170
+ ];
171
+ await d.transact(conn, schema);
172
+
173
+ const data = [
174
+ { name: 'Alice', age: 30, email: 'alice@example.com' }
175
+ ];
176
+ await d.transact(conn, data);
177
+
178
+ console.log(' Finding entity ID...');
179
+ const db = await d.db(conn);
180
+ const eid = await findEntityByName(db, 'Alice');
181
+ if (!eid) throw new Error('Entity not found');
182
+ console.log(` ✓ Found entity: ${eid}`);
183
+
184
+ console.log(' Pulling entity with pattern...');
185
+ const pulled = await d.pull(db, [':name', ':age', ':email'], eid);
186
+ if (!pulled || !pulled.name || pulled.name !== 'Alice') {
187
+ throw new Error('Pull failed or incorrect data');
188
+ }
189
+ console.log(` ✓ Pulled: ${pulled.name}, age ${pulled.age}, email ${pulled.email}`);
190
+
191
+ console.log(' Pulling with wildcard...');
192
+ const pulledAll = await d.pull(db, ['*'], eid);
193
+ if (!pulledAll || !pulledAll.name) {
194
+ throw new Error('Pull with wildcard failed');
195
+ }
196
+ console.log(` ✓ Pulled with wildcard: ${Object.keys(pulledAll).length} keys`);
197
+
198
+ console.log(' Pull many...');
199
+ const pulledMany = await d.pullMany(db, [':name'], [eid]);
200
+ if (!pulledMany || pulledMany.length !== 1) {
201
+ throw new Error('Pull many failed');
202
+ }
203
+ console.log(` ✓ Pull many: ${pulledMany.length} entities`);
204
+
205
+ d.release(conn);
206
+ await d.deleteDatabase(config);
207
+ }
208
+
209
+ async function testEntityAPI() {
210
+ console.log('\n=== Test 5: Entity API ===');
211
+
212
+ const config = {
213
+ store: { backend: ':memory', id: generateUUID() }
214
+ };
215
+
216
+ await d.createDatabase(config);
217
+ const conn = await d.connect(config);
218
+
219
+ const schema = [
220
+ { 'db/ident': ':name', 'db/valueType': ':db.type/string', 'db/cardinality': ':db.cardinality/one' },
221
+ { 'db/ident': ':age', 'db/valueType': ':db.type/long', 'db/cardinality': ':db.cardinality/one' },
222
+ { 'db/ident': ':email', 'db/valueType': ':db.type/string', 'db/cardinality': ':db.cardinality/one' }
223
+ ];
224
+ await d.transact(conn, schema);
225
+
226
+ const data = [
227
+ { name: 'Bob', age: 25, email: 'bob@example.com' }
228
+ ];
229
+ await d.transact(conn, data);
230
+
231
+ console.log(' Finding entity ID...');
232
+ const db = await d.db(conn);
233
+ const eid = await findEntityByName(db, 'Bob');
234
+ if (!eid) throw new Error('Entity not found');
235
+ console.log(` ✓ Found entity: ${eid}`);
236
+
237
+ console.log(' Getting entity...');
238
+ const entity = await d.entity(db, eid);
239
+ if (!entity) throw new Error('Entity retrieval failed');
240
+ console.log(` ✓ Entity retrieved (type: ${typeof entity})`);
241
+
242
+ // Note: Entity API returns a ClojureScript Entity object, not a plain JS object
243
+ // Use Pull API for getting entity data as plain JS object
244
+ console.log(' Using pull to get entity data...');
245
+ const pulled = await d.pull(db, [':name'], eid);
246
+ if (pulled.name !== 'Bob') {
247
+ throw new Error(`Expected name 'Bob' via pull, got '${pulled.name}'`);
248
+ }
249
+ console.log(` ✓ Entity has correct name via pull: ${pulled.name}`);
250
+
251
+ d.release(conn);
252
+ await d.deleteDatabase(config);
253
+ }
254
+
255
+ async function testTemporalDatabases() {
256
+ console.log('\n=== Test 6: Temporal Databases (History, as-of) ===');
257
+
258
+ const config = {
259
+ store: { backend: ':memory', id: generateUUID() },
260
+ 'keep-history?': true
261
+ };
262
+
263
+ await d.createDatabase(config);
264
+ const conn = await d.connect(config);
265
+
266
+ const schema = [
267
+ { 'db/ident': ':value', 'db/valueType': ':db.type/long', 'db/cardinality': ':db.cardinality/one' }
268
+ ];
269
+ await d.transact(conn, schema);
270
+
271
+ console.log(' Transacting initial value...');
272
+ await d.transact(conn, [{ value: 10 }]);
273
+ const db1 = await d.db(conn);
274
+ console.log(' ✓ Initial transaction complete');
275
+
276
+ console.log(' Transacting updated value...');
277
+ await d.transact(conn, [{ value: 20 }]);
278
+ const db2 = await d.db(conn);
279
+ console.log(' ✓ Updated transaction complete');
280
+
281
+ console.log(' Checking current datoms...');
282
+ const currentDatoms = await d.datoms(db2, ':eavt');
283
+ const valueDatoms2 = currentDatoms.filter(d => d.a && d.a.fqn === 'value');
284
+ const values2 = valueDatoms2.map(d => d.v);
285
+ console.log(` ✓ Current values in DB: ${values2.join(', ')}`);
286
+
287
+ console.log(' Using as-of to view old state...');
288
+ const dbAsOf = await d.asOf(db2, db1);
289
+ const asOfDatoms = await d.datoms(dbAsOf, ':eavt');
290
+ const valueDatoms1 = asOfDatoms.filter(d => d.a && d.a.fqn === 'value');
291
+ const values1 = valueDatoms1.map(d => d.v);
292
+ console.log(` ✓ as-of values: ${values1.join(', ')}`);
293
+
294
+ console.log(' Getting history database...');
295
+ const histDb = await d.history(db2);
296
+ const histDatoms = await d.datoms(histDb, ':eavt');
297
+ if (histDatoms.length < 2) {
298
+ throw new Error('History should have multiple datoms');
299
+ }
300
+ console.log(` ✓ History DB has ${histDatoms.length} datoms`);
301
+
302
+ d.release(conn);
303
+ await d.deleteDatabase(config);
304
+ }
305
+
306
+ async function testFilePersistence() {
307
+ console.log('\n=== Test 7: File Backend Persistence ===');
308
+
309
+ const dir = tmpDir();
310
+ const config = {
311
+ store: { backend: ':file', path: dir, id: generateUUID() }
312
+ };
313
+
314
+ console.log(` Using temp directory: ${dir}`);
315
+
316
+ console.log(' Creating database and adding data...');
317
+ await d.createDatabase(config);
318
+ let conn = await d.connect(config);
319
+
320
+ const schema = [
321
+ { 'db/ident': ':name', 'db/valueType': ':db.type/string', 'db/cardinality': ':db.cardinality/one' }
322
+ ];
323
+ await d.transact(conn, schema);
324
+
325
+ const data = [{ name: 'Persisted Alice' }];
326
+ await d.transact(conn, data);
327
+
328
+ console.log(' ✓ Data transacted');
329
+
330
+ console.log(' Releasing connection...');
331
+ d.release(conn);
332
+
333
+ console.log(' Reconnecting to same database...');
334
+ conn = await d.connect(config);
335
+ const db = await d.db(conn);
336
+
337
+ console.log(' Checking persisted data...');
338
+ const eid = await findEntityByName(db, 'Persisted Alice');
339
+ if (!eid) throw new Error('Persisted data not found after reconnect');
340
+ console.log(' ✓ Data persisted across reconnection');
341
+
342
+ d.release(conn);
343
+
344
+ console.log(' Deleting database...');
345
+ await d.deleteDatabase(config);
346
+
347
+ if (fs.existsSync(dir)) {
348
+ throw new Error('Directory should be cleaned up');
349
+ }
350
+ console.log(' ✓ Database and directory cleaned up');
351
+ }
352
+
353
+ async function testSchemaRetrieval() {
354
+ console.log('\n=== Test 8: Schema Retrieval ===');
355
+
356
+ const config = {
357
+ store: { backend: ':memory', id: generateUUID() }
358
+ };
359
+
360
+ await d.createDatabase(config);
361
+ const conn = await d.connect(config);
362
+
363
+ const schema = [
364
+ { 'db/ident': ':name', 'db/valueType': ':db.type/string', 'db/cardinality': ':db.cardinality/one' },
365
+ { 'db/ident': ':age', 'db/valueType': ':db.type/long', 'db/cardinality': ':db.cardinality/one' }
366
+ ];
367
+ await d.transact(conn, schema);
368
+
369
+ console.log(' Retrieving schema...');
370
+ const db = await d.db(conn);
371
+ const retrievedSchema = await d.schema(db);
372
+
373
+ if (!retrievedSchema || Object.keys(retrievedSchema).length === 0) {
374
+ throw new Error('Schema retrieval failed');
375
+ }
376
+ console.log(` ✓ Schema retrieved: ${Object.keys(retrievedSchema).length} attributes`);
377
+
378
+ d.release(conn);
379
+ await d.deleteDatabase(config);
380
+ }
381
+
382
+ async function testMultipleTransactions() {
383
+ console.log('\n=== Test 9: Multiple Sequential Transactions ===');
384
+
385
+ const config = {
386
+ store: { backend: ':memory', id: generateUUID() }
387
+ };
388
+
389
+ await d.createDatabase(config);
390
+ const conn = await d.connect(config);
391
+
392
+ const schema = [
393
+ { 'db/ident': ':counter', 'db/valueType': ':db.type/long', 'db/cardinality': ':db.cardinality/one' }
394
+ ];
395
+ await d.transact(conn, schema);
396
+
397
+ console.log(' Transacting multiple values...');
398
+ for (let i = 1; i <= 5; i++) {
399
+ await d.transact(conn, [{ counter: i * 10 }]);
400
+ }
401
+
402
+ const db = await d.db(conn);
403
+ const datoms = await d.datoms(db, ':eavt');
404
+ const counterDatoms = datoms.filter(d => d.a && d.a.fqn === 'counter');
405
+
406
+ if (!counterDatoms || counterDatoms.length < 5) {
407
+ throw new Error(`Expected at least 5 counter values, got ${counterDatoms ? counterDatoms.length : 0}`);
408
+ }
409
+ console.log(` ✓ Multiple transactions completed: ${counterDatoms.length} counter datoms`);
410
+
411
+ d.release(conn);
412
+ await d.deleteDatabase(config);
413
+ }
414
+
415
+ async function testQueryAPI() {
416
+ console.log('\n=== Test 10: Query API (Datalog queries as EDN strings) ===');
417
+
418
+ const config = {
419
+ store: { backend: ':memory', id: generateUUID() }
420
+ };
421
+
422
+ await d.createDatabase(config);
423
+ const conn = await d.connect(config);
424
+
425
+ const schema = [
426
+ { 'db/ident': ':name', 'db/valueType': ':db.type/string', 'db/cardinality': ':db.cardinality/one' },
427
+ { 'db/ident': ':age', 'db/valueType': ':db.type/long', 'db/cardinality': ':db.cardinality/one' },
428
+ { 'db/ident': ':email', 'db/valueType': ':db.type/string', 'db/cardinality': ':db.cardinality/one' }
429
+ ];
430
+ await d.transact(conn, schema);
431
+
432
+ const data = [
433
+ { name: 'Alice', age: 30, email: 'alice@example.com' },
434
+ { name: 'Bob', age: 25, email: 'bob@example.com' },
435
+ { name: 'Charlie', age: 35, email: 'charlie@example.com' }
436
+ ];
437
+ await d.transact(conn, data);
438
+
439
+ const db = await d.db(conn);
440
+
441
+ console.log(' Testing find-rel (return tuples)...');
442
+ const q1 = await d.q('[:find ?e ?name :where [?e :name ?name]]', db);
443
+ if (!q1 || q1.length !== 3) {
444
+ throw new Error(`Expected 3 results, got ${q1 ? q1.length : 0}`);
445
+ }
446
+ console.log(` ✓ Find-rel query returned ${q1.length} tuples`);
447
+
448
+ console.log(' Testing find-coll (return single column)...');
449
+ const q2 = await d.q('[:find [?name ...] :where [_ :name ?name]]', db);
450
+ if (!q2 || q2.length !== 3) {
451
+ throw new Error(`Expected 3 names, got ${q2 ? q2.length : 0}`);
452
+ }
453
+ console.log(` ✓ Find-coll query returned ${q2.length} values`);
454
+
455
+ console.log(' Testing find-tuple (return single tuple)...');
456
+ const q3 = await d.q('[:find [?name ?age] :where [?e :name "Alice"] [?e :age ?age] [?e :name ?name]]', db);
457
+ if (!q3 || q3.length !== 2) {
458
+ throw new Error(`Expected tuple [name, age], got ${JSON.stringify(q3)}`);
459
+ }
460
+ if (q3[0] !== 'Alice' || q3[1] !== 30) {
461
+ throw new Error(`Expected ["Alice", 30], got ${JSON.stringify(q3)}`);
462
+ }
463
+ console.log(` ✓ Find-tuple query returned [${q3[0]}, ${q3[1]}]`);
464
+
465
+ console.log(' Testing find-scalar (return single value)...');
466
+ const q4 = await d.q('[:find ?name . :where [?e :name ?name] [?e :age 25]]', db);
467
+ if (q4 !== 'Bob') {
468
+ throw new Error(`Expected "Bob", got ${q4}`);
469
+ }
470
+ console.log(` ✓ Find-scalar query returned: ${q4}`);
471
+
472
+ console.log(' Testing query with multiple clauses...');
473
+ const q5 = await d.q('[:find ?name ?age :where [?e :name ?name] [?e :age ?age] [(> ?age 28)]]', db);
474
+ if (!q5 || q5.length !== 2) {
475
+ throw new Error(`Expected 2 results (age > 28), got ${q5 ? q5.length : 0}`);
476
+ }
477
+ console.log(` ✓ Multi-clause query returned ${q5.length} results`);
478
+
479
+ console.log(' Testing query with input parameter...');
480
+ const q6 = await d.q('[:find ?e :in $ ?name :where [?e :name ?name]]', db, 'Charlie');
481
+ if (!q6 || q6.length !== 1) {
482
+ throw new Error(`Expected 1 result for Charlie, got ${q6 ? q6.length : 0}`);
483
+ }
484
+ console.log(` ✓ Parameterized query found entity for Charlie`);
485
+
486
+ d.release(conn);
487
+ await d.deleteDatabase(config);
488
+ }
489
+
490
+ // Main test runner
491
+ async function runAllTests() {
492
+ console.log('╔════════════════════════════════════════════════════════╗');
493
+ console.log('║ Comprehensive Datahike JavaScript API Test Suite ║');
494
+ console.log('╚════════════════════════════════════════════════════════╝');
495
+
496
+ const startTime = Date.now();
497
+ let passed = 0;
498
+ let failed = 0;
499
+
500
+ const tests = [
501
+ testBasicOperations,
502
+ testSchemaAndTransactions,
503
+ testDatomsAPI,
504
+ testPullAPI,
505
+ testEntityAPI,
506
+ testTemporalDatabases,
507
+ testFilePersistence,
508
+ testSchemaRetrieval,
509
+ testMultipleTransactions,
510
+ testQueryAPI
511
+ ];
512
+
513
+ for (const test of tests) {
514
+ try {
515
+ await test();
516
+ passed++;
517
+ } catch (err) {
518
+ failed++;
519
+ console.error(`\n❌ Test failed: ${err.message}`);
520
+ console.error(err.stack);
521
+ }
522
+ }
523
+
524
+ const duration = Date.now() - startTime;
525
+
526
+ console.log('\n╔════════════════════════════════════════════════════════╗');
527
+ console.log('║ Test Summary ║');
528
+ console.log('╚════════════════════════════════════════════════════════╝');
529
+ console.log(` Total: ${tests.length} tests`);
530
+ console.log(` Passed: ${passed} ✓`);
531
+ console.log(` Failed: ${failed} ✗`);
532
+ console.log(` Duration: ${duration}ms`);
533
+ console.log('');
534
+
535
+ if (failed === 0) {
536
+ console.log('🎉 All tests passed!');
537
+ } else {
538
+ console.log(`⚠️ ${failed} test(s) failed`);
539
+ }
540
+
541
+ return failed === 0;
542
+ }
543
+
544
+ // Run tests and exit with timeout
545
+ runAllTests()
546
+ .then(success => {
547
+ // Force exit after 2 seconds to handle any lingering event loop activity
548
+ setTimeout(() => {
549
+ process.exit(success ? 0 : 1);
550
+ }, 2000);
551
+ })
552
+ .catch(err => {
553
+ console.error('Fatal error:', err);
554
+ setTimeout(() => {
555
+ process.exit(1);
556
+ }, 2000);
557
+ });
@@ -0,0 +1,70 @@
1
+ // TypeScript type checking test for Datahike
2
+ // This file demonstrates TypeScript IDE support and improved types
3
+
4
+ import * as d from './index';
5
+
6
+ async function typescriptTest() {
7
+ // DatabaseConfig type is now properly typed
8
+ const config: d.DatabaseConfig = {
9
+ store: {
10
+ backend: ':mem',
11
+ id: 'ts-test'
12
+ },
13
+ 'keep-history': true,
14
+ 'schema-flexibility': 'write'
15
+ };
16
+
17
+ // Check if database exists - returns boolean
18
+ const exists: boolean = await d.databaseExists(config);
19
+
20
+ // Create database
21
+ await d.createDatabase(config);
22
+
23
+ // Connect returns Connection type
24
+ const conn: d.Connection = await d.connect(config);
25
+
26
+ // Transaction with typed Transaction array
27
+ const transactions: d.Transaction[] = [
28
+ { ':db/ident': ':name', ':db/valueType': ':db.type/string', ':db/cardinality': ':db.cardinality/one' },
29
+ { ':name': 'Alice', ':age': 30 }
30
+ ];
31
+
32
+ // TransactionReport is properly typed
33
+ const txResult: d.TransactionReport = await d.transact(conn, transactions);
34
+ console.log('Temp IDs:', txResult.tempids);
35
+ console.log('TX data:', txResult['tx-data']); // Datom[]
36
+
37
+ // Get database - returns Database type
38
+ const db: d.Database = d.db(conn);
39
+
40
+ // Query with typed arguments (query as string or array, optional limit/offset)
41
+ const queryResults = await d.q({
42
+ query: '[:find ?name ?age :where [?e :name ?name] [?e :age ?age]]',
43
+ args: [db],
44
+ limit: 10
45
+ });
46
+
47
+ // Pull API with typed options
48
+ const pullResult = await d.pull(db, {
49
+ selector: [':name', ':age'],
50
+ eid: 1 // number | string
51
+ });
52
+
53
+ // Schema returns Schema type
54
+ const schema: d.Schema = await d.schema(db);
55
+
56
+ // History returns Array<any>
57
+ const historyDb: Array<any> = await d.history(db);
58
+
59
+ // Temporal query - asOf returns Database
60
+ const pastDb: d.Database = await d.asOf(db, Date.now());
61
+
62
+ // Version is string (not Promise)
63
+ const version: string = d.version();
64
+
65
+ console.log('TypeScript types work perfectly!');
66
+ console.log('All parameters and return types are properly typed');
67
+ }
68
+
69
+ // This file demonstrates type checking - uncomment to test IDE support:
70
+ // typescriptTest();
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "datahike-browser-tests",
3
+ "version": "1.0.0",
4
+ "description": "Browser testing for Datahike",
5
+ "devDependencies": {
6
+ "karma": "^6.4.2",
7
+ "karma-chrome-launcher": "^3.2.0",
8
+ "karma-cljs-test": "^0.1.0",
9
+ "shadow-cljs": "^2.28.20"
10
+ },
11
+ "scripts": {
12
+ "test:browser": "karma start --single-run"
13
+ },
14
+ "author": "",
15
+ "license": "EPL-1.0"
16
+ }