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,311 @@
1
+ """EDN type helpers and common keyword constants.
2
+
3
+ This module provides explicit type constructors for EDN values and
4
+ pre-defined constants for frequently-used Datahike keywords.
5
+
6
+ Use these when you need fine-grained control over EDN conversion or
7
+ want to avoid string prefixes.
8
+
9
+ Example:
10
+ >>> from datahike import edn, kw
11
+ >>>
12
+ >>> # Explicit types
13
+ >>> schema = [{
14
+ ... "db/ident": edn.keyword("person/name"),
15
+ ... "db/valueType": kw.STRING,
16
+ ... "db/cardinality": kw.ONE,
17
+ ... "db/doc": edn.string(":literal-colon-in-doc")
18
+ ... }]
19
+ >>>
20
+ >>> db.transact(schema)
21
+ """
22
+
23
+ from typing import Optional
24
+ from .database import EDNType
25
+
26
+
27
+ # =============================================================================
28
+ # Explicit EDN Types
29
+ # =============================================================================
30
+
31
+ class Keyword(EDNType):
32
+ """Explicit EDN keyword.
33
+
34
+ Use when you need to construct keywords programmatically or force
35
+ a value to be a keyword regardless of the string prefix rules.
36
+
37
+ Args:
38
+ name: Keyword name
39
+ namespace: Optional namespace
40
+
41
+ Examples:
42
+ >>> edn.keyword("name")
43
+ # → :name
44
+
45
+ >>> edn.keyword("name", "person")
46
+ # → :person/name
47
+ """
48
+
49
+ def __init__(self, name: str, namespace: Optional[str] = None):
50
+ if namespace:
51
+ self.value = f"{namespace}/{name}"
52
+ else:
53
+ self.value = name
54
+
55
+ def to_edn(self) -> str:
56
+ return f":{self.value}"
57
+
58
+ def __repr__(self):
59
+ return f"Keyword('{self.value}')"
60
+
61
+
62
+ class Symbol(EDNType):
63
+ """Explicit EDN symbol.
64
+
65
+ Symbols are used for function names and special forms in Clojure.
66
+ Rarely needed in data transactions.
67
+
68
+ Args:
69
+ name: Symbol name
70
+ namespace: Optional namespace
71
+
72
+ Examples:
73
+ >>> edn.symbol("my-fn")
74
+ # → my-fn
75
+
76
+ >>> edn.symbol("assoc", "clojure.core")
77
+ # → clojure.core/assoc
78
+ """
79
+
80
+ def __init__(self, name: str, namespace: Optional[str] = None):
81
+ if namespace:
82
+ self.value = f"{namespace}/{name}"
83
+ else:
84
+ self.value = name
85
+
86
+ def to_edn(self) -> str:
87
+ return self.value
88
+
89
+ def __repr__(self):
90
+ return f"Symbol('{self.value}')"
91
+
92
+
93
+ class UUID(EDNType):
94
+ """Explicit EDN UUID.
95
+
96
+ Args:
97
+ value: UUID string (with or without #uuid prefix)
98
+
99
+ Examples:
100
+ >>> edn.uuid("550e8400-e29b-41d4-a716-446655440000")
101
+ # → #uuid "550e8400-e29b-41d4-a716-446655440000"
102
+ """
103
+
104
+ def __init__(self, value: str):
105
+ # Strip #uuid prefix if present
106
+ if value.startswith('#uuid'):
107
+ value = value[5:].strip().strip('"')
108
+ self.value = value
109
+
110
+ def to_edn(self) -> str:
111
+ return f'#uuid "{self.value}"'
112
+
113
+ def __repr__(self):
114
+ return f"UUID('{self.value}')"
115
+
116
+
117
+ class Inst(EDNType):
118
+ """Explicit EDN instant (timestamp).
119
+
120
+ Args:
121
+ value: ISO 8601 timestamp string
122
+
123
+ Examples:
124
+ >>> edn.inst("2024-01-01T00:00:00Z")
125
+ # → #inst "2024-01-01T00:00:00Z"
126
+ """
127
+
128
+ def __init__(self, value: str):
129
+ # Strip #inst prefix if present
130
+ if value.startswith('#inst'):
131
+ value = value[5:].strip().strip('"')
132
+ self.value = value
133
+
134
+ def to_edn(self) -> str:
135
+ return f'#inst "{self.value}"'
136
+
137
+ def __repr__(self):
138
+ return f"Inst('{self.value}')"
139
+
140
+
141
+ # =============================================================================
142
+ # Convenience Functions
143
+ # =============================================================================
144
+
145
+ def keyword(name: str, namespace: Optional[str] = None) -> Keyword:
146
+ """Create an EDN keyword.
147
+
148
+ Args:
149
+ name: Keyword name
150
+ namespace: Optional namespace
151
+
152
+ Returns:
153
+ Keyword instance
154
+
155
+ Examples:
156
+ >>> keyword("name")
157
+ # → :name
158
+
159
+ >>> keyword("name", "person")
160
+ # → :person/name
161
+ """
162
+ return Keyword(name, namespace)
163
+
164
+
165
+ def symbol(name: str, namespace: Optional[str] = None) -> Symbol:
166
+ """Create an EDN symbol.
167
+
168
+ Args:
169
+ name: Symbol name
170
+ namespace: Optional namespace
171
+
172
+ Returns:
173
+ Symbol instance
174
+ """
175
+ return Symbol(name, namespace)
176
+
177
+
178
+ def uuid(value: str) -> UUID:
179
+ """Create an EDN UUID.
180
+
181
+ Args:
182
+ value: UUID string
183
+
184
+ Returns:
185
+ UUID instance
186
+ """
187
+ return UUID(value)
188
+
189
+
190
+ def inst(value: str) -> Inst:
191
+ """Create an EDN instant.
192
+
193
+ Args:
194
+ value: ISO 8601 timestamp string
195
+
196
+ Returns:
197
+ Inst instance
198
+ """
199
+ return Inst(value)
200
+
201
+
202
+ def string(value: str) -> str:
203
+ """Force a value to be treated as a string.
204
+
205
+ Use this to create strings that start with ':' without them
206
+ becoming keywords.
207
+
208
+ Args:
209
+ value: String value (can start with :)
210
+
211
+ Returns:
212
+ Marked string that will be quoted in EDN
213
+
214
+ Examples:
215
+ >>> edn.string(":literal-colon")
216
+ # → ":literal-colon" (not :literal-colon keyword)
217
+ """
218
+ # Use special marker that database.py recognizes
219
+ return f"<STRING>{value}"
220
+
221
+
222
+ # =============================================================================
223
+ # Common Keyword Constants
224
+ # =============================================================================
225
+
226
+ class Keywords:
227
+ """Pre-defined Datahike keyword constants.
228
+
229
+ Use these for common Datahike schema and transaction attributes
230
+ to avoid typos and get IDE autocompletion.
231
+
232
+ Examples:
233
+ >>> from datahike import kw
234
+ >>>
235
+ >>> schema = [{
236
+ ... kw.DB_IDENT: edn.keyword("person/name"),
237
+ ... kw.DB_VALUE_TYPE: kw.STRING,
238
+ ... kw.DB_CARDINALITY: kw.ONE
239
+ ... }]
240
+ """
241
+
242
+ # Entity attributes
243
+ DB_ID = ":db/id"
244
+ DB_IDENT = ":db/ident"
245
+
246
+ # Schema attributes
247
+ DB_VALUE_TYPE = ":db/valueType"
248
+ DB_CARDINALITY = ":db/cardinality"
249
+ DB_DOC = ":db/doc"
250
+ DB_UNIQUE = ":db/unique"
251
+ DB_IS_COMPONENT = ":db/isComponent"
252
+ DB_NO_HISTORY = ":db/noHistory"
253
+ DB_INDEX = ":db/index"
254
+ DB_FULLTEXT = ":db/fulltext"
255
+
256
+ # Value types
257
+ STRING = ":db.type/string"
258
+ BOOLEAN = ":db.type/boolean"
259
+ LONG = ":db.type/long"
260
+ BIGINT = ":db.type/bigint"
261
+ FLOAT = ":db.type/float"
262
+ DOUBLE = ":db.type/double"
263
+ BIGDEC = ":db.type/bigdec"
264
+ INSTANT = ":db.type/instant"
265
+ UUID_TYPE = ":db.type/uuid"
266
+ KEYWORD_TYPE = ":db.type/keyword"
267
+ SYMBOL_TYPE = ":db.type/symbol"
268
+ REF = ":db.type/ref"
269
+ BYTES = ":db.type/bytes"
270
+
271
+ # Cardinality
272
+ ONE = ":db.cardinality/one"
273
+ MANY = ":db.cardinality/many"
274
+
275
+ # Uniqueness
276
+ UNIQUE_VALUE = ":db.unique/value"
277
+ UNIQUE_IDENTITY = ":db.unique/identity"
278
+
279
+ # Transaction metadata
280
+ TX = ":db/tx"
281
+ TX_INSTANT = ":db/txInstant"
282
+
283
+ # Schema flexibility
284
+ SCHEMA_READ = ":read"
285
+ SCHEMA_WRITE = ":write"
286
+
287
+
288
+ # Export singleton instance
289
+ kw = Keywords()
290
+
291
+
292
+ # =============================================================================
293
+ # Public API
294
+ # =============================================================================
295
+
296
+ __all__ = [
297
+ # Types
298
+ 'Keyword',
299
+ 'Symbol',
300
+ 'UUID',
301
+ 'Inst',
302
+ # Functions
303
+ 'keyword',
304
+ 'symbol',
305
+ 'uuid',
306
+ 'inst',
307
+ 'string',
308
+ # Constants
309
+ 'Keywords',
310
+ 'kw',
311
+ ]
File without changes
@@ -0,0 +1,17 @@
1
+ """Pytest configuration and shared fixtures."""
2
+ import pytest
3
+ import uuid
4
+
5
+
6
+ @pytest.fixture
7
+ def mem_config():
8
+ """Generate a unique in-memory database config."""
9
+ db_id = str(uuid.uuid4())
10
+ return f'{{:store {{:backend :memory :id #uuid "{db_id}"}}}}'
11
+
12
+
13
+ @pytest.fixture
14
+ def mem_config_flexible():
15
+ """Generate a unique in-memory database config with schema flexibility."""
16
+ db_id = str(uuid.uuid4())
17
+ return f'{{:store {{:backend :memory :id #uuid "{db_id}"}} :schema-flexibility :read}}'
@@ -0,0 +1,170 @@
1
+ """Basic tests for Datahike Python bindings."""
2
+ import json
3
+ import uuid
4
+ import sys
5
+ import os
6
+
7
+ # Add src to path for development
8
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
9
+
10
+ from datahike import (
11
+ create_database,
12
+ delete_database,
13
+ database_exists,
14
+ transact,
15
+ q,
16
+ pull,
17
+ schema,
18
+ DatahikeException,
19
+ )
20
+
21
+
22
+ def test_database_lifecycle():
23
+ """Test create, exists, delete database."""
24
+ db_id = str(uuid.uuid4())
25
+ config = f'{{:store {{:backend :memory :id #uuid "{db_id}"}}}}'
26
+
27
+ print(f"Using config: {config}")
28
+
29
+ # Create
30
+ print("Creating database...")
31
+ create_database(config)
32
+
33
+ # Check exists
34
+ print("Checking if database exists...")
35
+ exists = database_exists(config)
36
+ print(f"Database exists: {exists}")
37
+ assert exists == True
38
+
39
+ # Delete
40
+ print("Deleting database...")
41
+ delete_database(config)
42
+
43
+ # Check deleted
44
+ exists = database_exists(config)
45
+ print(f"Database exists after delete: {exists}")
46
+ assert exists == False
47
+
48
+ print("SUCCESS: Database lifecycle test passed!")
49
+
50
+
51
+ def test_transact_and_query_with_schema_flexibility():
52
+ """Test transact and query with schema-flexibility :read (flexible schema)."""
53
+ db_id = str(uuid.uuid4())
54
+ config = f'{{:store {{:backend :memory :id #uuid "{db_id}"}} :schema-flexibility :read}}'
55
+
56
+ print(f"\nUsing config: {config}")
57
+
58
+ try:
59
+ # Create database
60
+ print("Creating database...")
61
+ create_database(config)
62
+
63
+ # Transact data using JSON format
64
+ print("Transacting data...")
65
+ tx_data = json.dumps([
66
+ {"name": "Alice", "age": 30},
67
+ {"name": "Bob", "age": 25}
68
+ ])
69
+ result = transact(config, tx_data, input_format='json')
70
+ print(f"Transaction result: {result}")
71
+
72
+ # Query for Alice
73
+ print("Querying for Alice...")
74
+ query_result = q(
75
+ '[:find ?e ?name :where [?e :name ?name] [?e :name "Alice"]]',
76
+ [('db', config)],
77
+ output_format='json'
78
+ )
79
+ print(f"Query result: {query_result}")
80
+ assert len(query_result) > 0, "Should find Alice"
81
+
82
+ # Pull entity
83
+ print("Pulling entity...")
84
+ # Query result is ['!set', [[eid, name], ...]]
85
+ actual_results = query_result[1] if query_result[0] == '!set' else query_result
86
+ entity_id = actual_results[0][0]
87
+ entity = pull(config, '[*]', entity_id, output_format='json')
88
+ print(f"Pulled entity: {entity}")
89
+ # In JSON mode, keywords don't have : prefix
90
+ assert entity.get('name') == 'Alice' or entity.get(':name') == 'Alice'
91
+
92
+ print("SUCCESS: Transact and query test passed!")
93
+
94
+ finally:
95
+ # Cleanup
96
+ print("Cleaning up...")
97
+ delete_database(config)
98
+
99
+
100
+ def test_transact_with_explicit_schema():
101
+ """Test transact and query with explicit schema."""
102
+ db_id = str(uuid.uuid4())
103
+ config = f'{{:store {{:backend :memory :id #uuid "{db_id}"}}}}'
104
+
105
+ print(f"\nUsing config: {config}")
106
+
107
+ try:
108
+ # Create database
109
+ print("Creating database...")
110
+ create_database(config)
111
+
112
+ # First transact schema using EDN format (keywords need proper representation)
113
+ print("Transacting schema...")
114
+ schema_tx = '[{:db/ident :name :db/valueType :db.type/string :db/cardinality :db.cardinality/one} {:db/ident :age :db/valueType :db.type/long :db/cardinality :db.cardinality/one}]'
115
+ transact(config, schema_tx, input_format='edn')
116
+
117
+ # Check schema was added
118
+ print("Checking schema...")
119
+ db_schema = schema(config, output_format='json')
120
+ print(f"Schema: {db_schema}")
121
+
122
+ # Transact data using JSON - schema validates types
123
+ print("Transacting data...")
124
+ tx_data = json.dumps([
125
+ {"name": "Charlie", "age": 35},
126
+ {"name": "Diana", "age": 28}
127
+ ])
128
+ transact(config, tx_data, input_format='json')
129
+
130
+ # Query
131
+ print("Querying...")
132
+ query_result = q(
133
+ '[:find ?e ?name ?age :where [?e :name ?name] [?e :age ?age]]',
134
+ [('db', config)],
135
+ output_format='json'
136
+ )
137
+ print(f"Query result: {query_result}")
138
+ actual_results = query_result[1] if query_result[0] == '!set' else query_result
139
+ assert len(actual_results) == 2, f"Expected 2 results, got {len(actual_results)}"
140
+
141
+ print("SUCCESS: Explicit schema test passed!")
142
+
143
+ finally:
144
+ # Cleanup
145
+ print("Cleaning up...")
146
+ delete_database(config)
147
+
148
+
149
+ def test_exception_handling():
150
+ """Test that exceptions are properly raised."""
151
+ db_id = str(uuid.uuid4())
152
+ config = f'{{:store {{:backend :memory :id #uuid "{db_id}"}}}}'
153
+
154
+ print("\nTesting exception handling...")
155
+
156
+ try:
157
+ # Try to query non-existent database
158
+ q('[:find ?e :where [?e :name "test"]]', [('db', config)])
159
+ assert False, "Should have raised exception"
160
+ except DatahikeException as e:
161
+ print(f"Caught expected exception: {e}")
162
+ print("SUCCESS: Exception handling test passed!")
163
+
164
+
165
+ if __name__ == '__main__':
166
+ test_database_lifecycle()
167
+ test_transact_and_query_with_schema_flexibility()
168
+ test_transact_with_explicit_schema()
169
+ test_exception_handling()
170
+ print("\n=== ALL TESTS PASSED ===")
@@ -0,0 +1,51 @@
1
+ """Tests for database lifecycle operations."""
2
+ import pytest
3
+ from datahike import (
4
+ create_database,
5
+ delete_database,
6
+ database_exists,
7
+ database,
8
+ DatahikeException,
9
+ )
10
+
11
+
12
+ def test_create_and_delete(mem_config):
13
+ """Test create and delete database."""
14
+ # Create
15
+ create_database(mem_config)
16
+
17
+ # Check exists
18
+ assert database_exists(mem_config) is True
19
+
20
+ # Delete
21
+ delete_database(mem_config)
22
+
23
+ # Check deleted
24
+ assert database_exists(mem_config) is False
25
+
26
+
27
+ def test_database_context_manager(mem_config):
28
+ """Test database context manager for automatic cleanup."""
29
+ # Database should not exist before
30
+ assert database_exists(mem_config) is False
31
+
32
+ # Use context manager
33
+ with database(mem_config) as cfg:
34
+ # Should exist inside context
35
+ assert database_exists(cfg) is True
36
+ assert cfg == mem_config
37
+
38
+ # Should be deleted after context
39
+ assert database_exists(mem_config) is False
40
+
41
+
42
+ def test_exception_on_nonexistent_database(mem_config):
43
+ """Test that operations on nonexistent database raise exception."""
44
+ from datahike import q
45
+
46
+ # Database doesn't exist
47
+ assert database_exists(mem_config) is False
48
+
49
+ # Try to query should raise exception
50
+ with pytest.raises(DatahikeException):
51
+ q('[:find ?e :where [?e :name "test"]]', [('db', mem_config)])