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,564 @@
1
+ (ns datahike.test.tuples-test
2
+ (:require
3
+ #?(:cljs [cljs.test :as t :refer-macros [is are deftest testing]]
4
+ :clj [clojure.test :as t :refer [is are deftest testing]])
5
+ [datahike.api :as d]
6
+ [datahike.db :as db]
7
+ [datahike.test.utils :refer [get-time]])
8
+ #?(:clj
9
+ (:import [clojure.lang ExceptionInfo])))
10
+
11
+ (deftest test-schema-declaration
12
+ (testing "composite tuple"
13
+ (is (db/empty-db {:reg/semester+course+student {:db/valueType :db.type/tuple
14
+ :db/tupleAttrs [:reg/course :reg/semester :reg/student]}})))
15
+
16
+ (testing "heterogeneous tuples"
17
+ (is (db/empty-db {:player/location {:db/valueType :db.type/tuple
18
+ :db/tupleTypes [:db.type/long :db.type/long]}})))
19
+
20
+ (testing "homogeneous tuples"
21
+ (is (db/empty-db {:db/tupleAttrs {:db/valueType :db.type/tuple
22
+ :db/tupleType :db.type/keyword}}))))
23
+
24
+ (defn connect
25
+ []
26
+ (let [config {:schema-flexibility :write
27
+ :store {:backend :memory :id (random-uuid)}}]
28
+ (d/delete-database config)
29
+ (d/create-database config)
30
+ (d/connect config)))
31
+
32
+ (deftest test-transaction
33
+ (testing "homogeneous tuple"
34
+ (let [conn (connect)]
35
+ (d/transact conn [{:db/ident :prices
36
+ :db/valueType :db.type/tuple
37
+ :db/tupleType :db.type/number
38
+ :db/cardinality :db.cardinality/one}])
39
+ (testing "of less than 9 values"
40
+ (is (d/transact conn [{:prices [1 2 3 4 5 6 7 8]}]))
41
+ (testing "are of different types"
42
+ (is (thrown-with-msg? ExceptionInfo #".*Cannot store homogeneous tuple with values of different type.*"
43
+ (d/transact conn [{:prices [1 2 3 4 5 6 "fdsfdsf"]}]))))
44
+ (testing "are of wrong type"
45
+ (is (thrown-with-msg? ExceptionInfo #".*Cannot store homogeneous tuple. Values are of wrong type.*"
46
+ (d/transact conn [{:prices ["a" "b" "fdsfdsf"]}])))))
47
+ (testing "of more than 8 values"
48
+ (is (thrown-with-msg? ExceptionInfo #".*Cannot store more than 8 values .*"
49
+ (d/transact conn [{:prices [1 2 3 4 5 6 7 8 9]}]))))
50
+ (d/release conn)))
51
+
52
+ (testing "heterogeneous tuple"
53
+ (let [conn (connect)]
54
+ (d/transact conn [{:db/ident :coord
55
+ :db/valueType :db.type/tuple
56
+ :db/tupleTypes [:db.type/long :db.type/keyword]
57
+ :db/cardinality :db.cardinality/one}])
58
+ (is (d/transact conn [{:coord [100 :coord/west]}]))
59
+ (testing "with wrong number of values"
60
+ (is (thrown-with-msg? ExceptionInfo #".*Cannot store heterogeneous tuple: expecting 2 values, got 3.*"
61
+ (d/transact conn [{:coord [100 :coord/west 9]}]))))
62
+ (testing "with type mismatch"
63
+ (is (thrown-with-msg? ExceptionInfo #".*Cannot store heterogeneous tuple: there is a mismatch between values.* and their types.*"
64
+ (d/transact conn [{:coord [100 9]}]))))
65
+ (d/release conn)))
66
+
67
+ (testing "composite tuple"
68
+ (let [conn (connect)
69
+ reg-schema [{:db/ident :reg/course
70
+ :db/valueType :db.type/string
71
+ :db/cardinality :db.cardinality/one}
72
+ {:db/ident :reg/semester
73
+ :db/valueType :db.type/string
74
+ :db/cardinality :db.cardinality/one}
75
+ {:db/ident :reg/student
76
+ :db/valueType :db.type/string
77
+ :db/cardinality :db.cardinality/one}]]
78
+ (d/transact conn reg-schema)
79
+ (is (d/transact conn [{:db/ident :reg/semester+course+student
80
+ :db/valueType :db.type/tuple
81
+ :db/tupleAttrs [:reg/course :reg/semester :reg/student]
82
+ :db/cardinality :db.cardinality/one}]))
83
+ (is (d/transact conn [{:reg/course "BIO-101"
84
+ :reg/semester "2018-fall"
85
+ :reg/student "johndoe@university.edu"}]))
86
+ (d/release conn)))
87
+
88
+ (testing "composite tuple with :db/ident last (issue #754)"
89
+ (let [conn (connect)
90
+ reg-schema [{:db/ident :reg/course
91
+ :db/valueType :db.type/string
92
+ :db/cardinality :db.cardinality/one}
93
+ {:db/ident :reg/semester
94
+ :db/valueType :db.type/string
95
+ :db/cardinality :db.cardinality/one}
96
+ {:db/ident :reg/student
97
+ :db/valueType :db.type/string
98
+ :db/cardinality :db.cardinality/one}]]
99
+ (d/transact conn reg-schema)
100
+ ;; Same schema as above but with :db/ident LAST to test attribute ordering
101
+ (is (d/transact conn [{:db/valueType :db.type/tuple
102
+ :db/tupleAttrs [:reg/course :reg/semester :reg/student]
103
+ :db/cardinality :db.cardinality/one
104
+ :db/ident :reg/semester+course+student-2}]))
105
+ (is (d/transact conn [{:reg/course "MATH-201"
106
+ :reg/semester "2019-spring"
107
+ :reg/student "janedoe@university.edu"}]))
108
+ (d/release conn))))
109
+
110
+ (deftest test-transact-and-query-non-composite
111
+ (testing "heterogeneous"
112
+ (let [conn (connect)]
113
+ (d/transact conn [{:db/ident :coord
114
+ :db/valueType :db.type/tuple
115
+ :db/tupleTypes [:db.type/long :db.type/keyword]
116
+ :db/cardinality :db.cardinality/one}])
117
+ (d/transact conn [[:db/add 100 :coord [100 :coord/west]]])
118
+ (is (= #{[[100 :coord/west]]}
119
+ (d/q '[:find ?v
120
+ :where [_ :coord ?v]]
121
+ @conn)))
122
+ (d/release conn)))
123
+ (testing "homogeneous"
124
+ (let [conn (connect)]
125
+ (d/transact conn [{:db/ident :coord
126
+ :db/valueType :db.type/tuple
127
+ :db/tupleType :db.type/long
128
+ :db/cardinality :db.cardinality/one}])
129
+ (d/transact conn [[:db/add 100 :coord [100 200 300]]])
130
+ (is (= #{[[100 200 300]]}
131
+ (d/q '[:find ?v
132
+ :where [_ :coord ?v]]
133
+ @conn)))
134
+ (d/release conn))))
135
+
136
+ (deftest test-retract-entity-with-tuples
137
+ (testing "retractEntity with homogeneous tuple (3+ elements)"
138
+ (let [conn (connect)]
139
+ (d/transact conn [{:db/ident :taglist
140
+ :db/valueType :db.type/tuple
141
+ :db/tupleType :db.type/string
142
+ :db/cardinality :db.cardinality/one}
143
+ {:db/ident :expense/id
144
+ :db/valueType :db.type/string
145
+ :db/unique :db.unique/identity
146
+ :db/cardinality :db.cardinality/one}])
147
+ ;; Add entity with 3-element tuple
148
+ (d/transact conn [{:expense/id "exp-123"
149
+ :taglist ["" "tag139878778372080000" "tag139879675144920000"]}])
150
+ ;; Verify it was added
151
+ (is (= #{[["" "tag139878778372080000" "tag139879675144920000"]]}
152
+ (d/q '[:find ?v
153
+ :where [_ :taglist ?v]]
154
+ @conn)))
155
+ ;; Retract the entity - this previously failed with validation error
156
+ (is (d/transact conn [[:db.fn/retractEntity [:expense/id "exp-123"]]]))
157
+ ;; Verify it was retracted
158
+ (is (= #{}
159
+ (d/q '[:find ?v
160
+ :where [_ :taglist ?v]]
161
+ @conn)))
162
+ (d/release conn)))
163
+
164
+ (testing "retractEntity with heterogeneous tuple (3 elements)"
165
+ (let [conn (connect)]
166
+ (d/transact conn [{:db/ident :driver/live-location
167
+ :db/valueType :db.type/tuple
168
+ :db/tupleTypes [:db.type/instant :db.type/float :db.type/float]
169
+ :db/cardinality :db.cardinality/one}
170
+ {:db/ident :driver/uuid
171
+ :db/valueType :db.type/uuid
172
+ :db/unique :db.unique/identity
173
+ :db/cardinality :db.cardinality/one}])
174
+ ;; Add entity with heterogeneous tuple
175
+ (let [uuid (java.util.UUID/fromString "1530d376-2df8-4318-a51d-8db173c03876")
176
+ timestamp #inst "2025-12-15T05:39:53.898-00:00"]
177
+ (d/transact conn [{:driver/uuid uuid
178
+ :driver/live-location [timestamp 15.6683 73.7185]}])
179
+ ;; Verify it was added
180
+ (is (= #{[[timestamp 15.6683 73.7185]]}
181
+ (d/q '[:find ?v
182
+ :where [_ :driver/live-location ?v]]
183
+ @conn)))
184
+ ;; Retract the entity
185
+ (is (d/transact conn [[:db.fn/retractEntity [:driver/uuid uuid]]]))
186
+ ;; Verify it was retracted
187
+ (is (= #{}
188
+ (d/q '[:find ?v
189
+ :where [_ :driver/live-location ?v]]
190
+ @conn))))
191
+ (d/release conn)))
192
+
193
+ (testing "retract specific tuple value"
194
+ (let [conn (connect)]
195
+ (d/transact conn [{:db/ident :coords
196
+ :db/valueType :db.type/tuple
197
+ :db/tupleTypes [:db.type/float :db.type/float :db.type/float]
198
+ :db/cardinality :db.cardinality/one}])
199
+ ;; Add entity
200
+ (d/transact conn [[:db/add 100 :coords [1.0 2.0 3.0]]])
201
+ ;; Retract specific tuple value - this previously failed
202
+ (is (d/transact conn [[:db/retract 100 :coords [1.0 2.0 3.0]]]))
203
+ ;; Verify it was retracted
204
+ (is (= #{}
205
+ (d/q '[:find ?v
206
+ :where [100 :coords ?v]]
207
+ @conn)))
208
+ (d/release conn))))
209
+
210
+ (deftest test-transact-and-query-composite
211
+ (let [conn (connect)]
212
+ (d/transact conn [{:db/ident :a
213
+ :db/valueType :db.type/long
214
+ :db/cardinality :db.cardinality/one}
215
+ {:db/ident :a+b+c
216
+ :db/valueType :db.type/tuple
217
+ :db/tupleAttrs [:a :b :c]
218
+ :db/cardinality :db.cardinality/one}])
219
+ (is (d/transact conn [[:db/add 100 :a 123]]))
220
+ (is (= #{[123]}
221
+ (d/q '[:find ?v
222
+ :where [100 :a ?v]]
223
+ @conn)))
224
+ (is (= #{[100 [123 nil nil]]}
225
+ (d/q '[:find ?e ?v
226
+ :where [?e :a+b+c ?v]]
227
+ @conn)))
228
+ (is (= #{[[123 nil nil]]}
229
+ (d/q '[:find ?v
230
+ :where [100 :a+b+c ?v]]
231
+ @conn)))
232
+ (d/release conn)))
233
+
234
+ (defn some-datoms
235
+ [db es]
236
+ (into #{} (map (juxt :e :a :v)) (mapcat #(d/datoms db {:index :eavt :components [%]}) es)))
237
+
238
+ (deftest test-more-composite-transaction
239
+ (let [conn (connect)
240
+ e 100]
241
+ (d/transact conn [{:db/ident :a
242
+ :db/valueType :db.type/string
243
+ :db/cardinality :db.cardinality/one}
244
+ {:db/ident :b
245
+ :db/valueType :db.type/string
246
+ :db/cardinality :db.cardinality/one}
247
+ {:db/ident :c
248
+ :db/valueType :db.type/string
249
+ :db/cardinality :db.cardinality/one}
250
+ {:db/ident :d
251
+ :db/valueType :db.type/string
252
+ :db/cardinality :db.cardinality/one}
253
+ {:db/ident :a+b
254
+ :db/valueType :db.type/tuple
255
+ :db/tupleAttrs [:a :b]
256
+ :db/cardinality :db.cardinality/one}
257
+ {:db/ident :a+c+d
258
+ :db/valueType :db.type/tuple
259
+ :db/tupleAttrs [:a :c :d]
260
+ :db/cardinality :db.cardinality/one}])
261
+ (are [tx datoms] (= datoms (some-datoms (:db-after (d/transact conn tx)) [e]))
262
+ [[:db/add e :a "a"]]
263
+ #{[e :a "a"]
264
+ [e :a+b ["a" nil]]
265
+ [e :a+c+d ["a" nil nil]]}
266
+
267
+ [[:db/add e :b "b"]]
268
+ #{[e :a "a"]
269
+ [e :b "b"]
270
+ [e :a+b ["a" "b"]]
271
+ [e :a+c+d ["a" nil nil]]}
272
+
273
+ [[:db/add e :a "A"]]
274
+ #{[e :a "A"]
275
+ [e :b "b"]
276
+ [e :a+b ["A" "b"]]
277
+ [e :a+c+d ["A" nil nil]]}
278
+
279
+ [[:db/add e :c "c"]
280
+ [:db/add e :d "d"]]
281
+ #{[e :a "A"]
282
+ [e :b "b"]
283
+ [e :a+b ["A" "b"]]
284
+ [e :c "c"]
285
+ [e :d "d"]
286
+ [e :a+c+d ["A" "c" "d"]]}
287
+
288
+ [[:db/add e :a "a"]]
289
+ #{[e :a "a"]
290
+ [e :b "b"]
291
+ [e :a+b ["a" "b"]]
292
+ [e :c "c"]
293
+ [e :d "d"]
294
+ [e :a+c+d ["a" "c" "d"]]}
295
+
296
+ [[:db/add e :a "A"]
297
+ [:db/add e :b "B"]
298
+ [:db/add e :c "C"]
299
+ [:db/add e :d "D"]]
300
+ #{[e :a "A"]
301
+ [e :b "B"]
302
+ [e :a+b ["A" "B"]]
303
+ [e :c "C"]
304
+ [e :d "D"]
305
+ [e :a+c+d ["A" "C" "D"]]}
306
+
307
+ [[:db/retract e :a "A"]]
308
+ #{[e :b "B"]
309
+ [e :a+b [nil "B"]]
310
+ [e :c "C"]
311
+ [e :d "D"]
312
+ [e :a+c+d [nil "C" "D"]]}
313
+
314
+ [[:db/retract e :b "B"]]
315
+ #{[e :c "C"]
316
+ [e :d "D"]
317
+ [e :a+c+d [nil "C" "D"]]})
318
+
319
+ (is (thrown-with-msg? ExceptionInfo #"Can’t modify tuple attrs directly:.*"
320
+ (d/transact conn [{:db/id 100 :a+b ["A" "B"]}])))
321
+ (d/release conn)))
322
+
323
+ (deftest test-queries
324
+ (let [conn (connect)]
325
+ (d/transact conn [{:db/ident :a
326
+ :db/valueType :db.type/string
327
+ :db/cardinality :db.cardinality/one}
328
+ {:db/ident :b
329
+ :db/valueType :db.type/string
330
+ :db/cardinality :db.cardinality/one}
331
+ {:db/ident :a+b
332
+ :db/valueType :db.type/tuple
333
+ :db/tupleAttrs [:a :b]
334
+ :db/cardinality :db.cardinality/one
335
+ :db/unique :db.unique/value}])
336
+
337
+ (d/transact conn [{:db/id 1 :a "A" :b "B"}
338
+ {:db/id 2 :a "A" :b "b"}
339
+ {:db/id 3 :a "a" :b "B"}
340
+ {:db/id 4 :a "a" :b "b"}])
341
+
342
+ (is (= #{[3]}
343
+ (d/q '[:find ?e
344
+ :where [?e :a+b ["a" "B"]]] @conn)))
345
+
346
+ (is (= #{[["a" "B"]]}
347
+ (d/q '[:find ?a+b
348
+ :where [[:a+b ["a" "B"]] :a+b ?a+b]] @conn)))
349
+
350
+ (is (= #{[["A" "B"]] [["A" "b"]] [["a" "B"]] [["a" "b"]]}
351
+ (d/q '[:find ?a+b
352
+ :where [?e :a ?a]
353
+ [?e :b ?b]
354
+ [(tuple ?a ?b) ?a+b]] @conn)))
355
+
356
+ (is (= #{["A" "B"] ["A" "b"] ["a" "B"] ["a" "b"]}
357
+ (d/q '[:find ?a ?b
358
+ :where [?e :a+b ?a+b]
359
+ [(untuple ?a+b) [?a ?b]]] @conn)))
360
+ (d/release conn)))
361
+
362
+ (deftest test-lookup-refs
363
+ (let [conn (connect)]
364
+ (d/transact conn [{:db/ident :a
365
+ :db/valueType :db.type/string
366
+ :db/cardinality :db.cardinality/one}
367
+ {:db/ident :b
368
+ :db/valueType :db.type/string
369
+ :db/cardinality :db.cardinality/one}
370
+ {:db/ident :c
371
+ :db/valueType :db.type/string
372
+ :db/cardinality :db.cardinality/one
373
+ :db/unique :db.unique/identity}
374
+ {:db/ident :d
375
+ :db/valueType :db.type/string
376
+ :db/cardinality :db.cardinality/one
377
+ :db/unique :db.unique/identity}
378
+ {:db/ident :a+b
379
+ :db/valueType :db.type/tuple
380
+ :db/tupleAttrs [:a :b]
381
+ :db/cardinality :db.cardinality/one
382
+ :db/unique :db.unique/identity}])
383
+
384
+ (d/transact conn
385
+ [{:db/id 100 :a "A" :b "B"}
386
+ {:db/id 200 :a "a" :b "b"}])
387
+
388
+ (d/transact conn [[:db/add [:a+b ["A" "B"]] :c "C"]
389
+ {:db/id [:a+b ["a" "b"]] :c "c"}])
390
+
391
+ (is (= #{[100 :a "A"]
392
+ [100 :b "B"]
393
+ [100 :a+b ["A" "B"]]
394
+ [100 :c "C"]
395
+ [200 :a "a"]
396
+ [200 :b "b"]
397
+ [200 :a+b ["a" "b"]]
398
+ [200 :c "c"]}
399
+ (some-datoms (d/db conn) [100 200])))
400
+
401
+ (is (thrown-with-msg? ExceptionInfo #"Cannot add .* because of unique constraint: .*"
402
+ (d/transact conn [[:db/add [:a+b ["A" "B"]] :c "c"]])))
403
+
404
+ (is (thrown-with-msg? ExceptionInfo #".*Conflicting upsert: \[\:c \"c\"] .*"
405
+ (d/transact conn [{:db/id [:a+b ["A" "B"]] :c "c"}])))
406
+
407
+ ;; change tuple + upsert
408
+ (d/transact conn
409
+ [{:db/id [:a+b ["A" "B"]]
410
+ :b "b"
411
+ :d "D"}])
412
+
413
+ (is (= #{[100 :a "A"]
414
+ [100 :b "b"]
415
+ [100 :a+b ["A" "b"]]
416
+ [100 :c "C"]
417
+ [100 :d "D"]
418
+ [200 :a "a"]
419
+ [200 :b "b"]
420
+ [200 :a+b ["a" "b"]]
421
+ [200 :c "c"]}
422
+ (some-datoms (d/db conn) [100 200])))
423
+
424
+ (is (= {:db/id 200
425
+ :a "a"
426
+ :b "b"
427
+ :a+b ["a" "b"]
428
+ :c "c"}
429
+ (d/pull (d/db conn) '[*] [:a+b ["a" "b"]])))
430
+
431
+ (d/release conn)))
432
+
433
+ (deftest test-upsert-insert
434
+ (let [conn (connect)]
435
+ (d/transact conn [{:db/ident :a
436
+ :db/valueType :db.type/string
437
+ :db/cardinality :db.cardinality/one}
438
+ {:db/ident :b
439
+ :db/valueType :db.type/string
440
+ :db/cardinality :db.cardinality/one}
441
+ {:db/ident :c
442
+ :db/valueType :db.type/string
443
+ :db/cardinality :db.cardinality/one}
444
+ {:db/ident :a+b
445
+ :db/valueType :db.type/tuple
446
+ :db/tupleAttrs [:a :b]
447
+ :db/cardinality :db.cardinality/one
448
+ :db/unique :db.unique/identity}])
449
+
450
+ ;; insert side of upsert:
451
+ (d/transact conn
452
+ [{:a "x" :b "y"}])
453
+
454
+ (d/transact conn
455
+ [{:a "x" :b "y"}])
456
+
457
+ (d/transact conn
458
+ [{:a "x" :b "y" :c "xyz"}])
459
+
460
+ (is (=
461
+ #{[:a "x"]
462
+ [:b "y"]
463
+ [:a+b ["x" "y"]]
464
+ [:c "xyz"]}
465
+ (set
466
+ (d/q '[:find ?a ?v
467
+ :with ?t
468
+ :where
469
+ [?e ?a ?v ?t]
470
+ [?e :a+b ["x" "y"]]]
471
+ (d/history (d/db conn))))))
472
+
473
+ (d/release conn)))
474
+
475
+ (deftest test-unique
476
+ (let [conn (connect)]
477
+ (d/transact conn [{:db/ident :a
478
+ :db/valueType :db.type/string
479
+ :db/cardinality :db.cardinality/one}
480
+ {:db/ident :b
481
+ :db/valueType :db.type/string
482
+ :db/cardinality :db.cardinality/one}
483
+ {:db/ident :a+b
484
+ :db/valueType :db.type/tuple
485
+ :db/tupleAttrs [:a :b]
486
+ :db/cardinality :db.cardinality/one
487
+ :db/unique :db.unique/identity}])
488
+
489
+ (d/transact conn [[:db/add 100 :a "a"]])
490
+ (d/transact conn [[:db/add 200 :a "A"]])
491
+ (is (thrown-with-msg? ExceptionInfo #"Cannot add .* because of unique constraint: .*"
492
+ (d/transact conn [[:db/add 100 :a "A"]])))
493
+
494
+ (d/transact conn [[:db/add 100 :b "b"]
495
+ [:db/add 200 :b "b"]
496
+ {:db/id 300 :a "a" :b "B"}])
497
+
498
+ (is (= #{[100 :a "a"]
499
+ [100 :b "b"]
500
+ [100 :a+b ["a" "b"]]
501
+ [200 :a "A"]
502
+ [200 :b "b"]
503
+ [200 :a+b ["A" "b"]]
504
+ [300 :a "a"]
505
+ [300 :b "B"]
506
+ [300 :a+b ["a" "B"]]}
507
+ (some-datoms (d/db conn) [100 200 300])))
508
+
509
+ (is (thrown-with-msg? ExceptionInfo #"Cannot add .* because of unique constraint: .*"
510
+ (d/transact conn [[:db/add 100 :a "A"]])))
511
+ (is (thrown-with-msg? ExceptionInfo #"Cannot add .* because of unique constraint: .*"
512
+ (d/transact conn [[:db/add 100 :b "B"]])))
513
+ (is (thrown-with-msg? ExceptionInfo #"Cannot add .* because of unique constraint: .*"
514
+ (d/transact conn [[:db/add 100 :a "A"]
515
+ [:db/add 100 :b "B"]])))
516
+
517
+ (testing "multiple tuple updates"
518
+ ;; changing both tuple components in a single operation
519
+ (d/transact conn [{:db/id 100 :a "A" :b "B"}])
520
+ (is (= {:db/id 100 :a "A" :b "B" :a+b ["A" "B"]}
521
+ (d/pull (d/db conn) '[*] 100)))
522
+
523
+ ;; adding entity with two tuple components in a single operation
524
+ (d/transact conn [{:db/id 4 :a "a" :b "c"}])
525
+ (is (= {:db/id 4 :a "a" :b "c" :a+b ["a" "c"]}
526
+ (d/pull (d/db conn) '[*] 4))))
527
+ (d/release conn)))
528
+
529
+ (deftest test-validation
530
+ (let [db (db/empty-db {:a+b {:db/valueType :db.type/tuple
531
+ :db/tupleAttrs [:a :b]}})
532
+ db1 (d/db-with db [[:db/add 100 :a "a"]])
533
+ err-msg #"Can’t modify tuple attrs directly:.*"]
534
+ (is (thrown-with-msg? ExceptionInfo err-msg
535
+ (d/db-with db [[:db/add 100 :a+b [nil nil]]])))
536
+ (is (thrown-with-msg? ExceptionInfo err-msg
537
+ (d/db-with db1 [[:db/add 100 :a+b ["a" nil]]])))
538
+ (is (thrown-with-msg? ExceptionInfo err-msg
539
+ (d/db-with db [[:db/add 100 :a "a"]
540
+ [:db/add 100 :a+b ["a" nil]]])))
541
+ (is (thrown-with-msg? ExceptionInfo err-msg
542
+ (d/db-with db1 [[:db/retract 100 :a+b ["a" nil]]])))))
543
+
544
+ (deftest test-indexes
545
+ (let [db (-> (db/empty-db {:a+b+c {:db/tupleAttrs [:a :b :c]
546
+ :db/valueType :db.type/tuple
547
+ :db/index true}})
548
+ (d/db-with
549
+ [{:db/id 1 :a "a" :b "b" :c "c"}
550
+ {:db/id 2 :a "A" :b "b" :c "c"}
551
+ {:db/id 3 :a "a" :b "B" :c "c"}
552
+ {:db/id 4 :a "A" :b "B" :c "c"}
553
+ {:db/id 5 :a "a" :b "b" :c "C"}
554
+ {:db/id 6 :a "A" :b "b" :c "C"}
555
+ {:db/id 7 :a "a" :b "B" :c "C"}
556
+ {:db/id 8 :a "A" :b "B" :c "C"}]))]
557
+ (is (= [6]
558
+ (mapv :e (d/datoms db :avet :a+b+c ["A" "b" "C"]))))
559
+ (is (= []
560
+ (mapv :e (d/datoms db :avet :a+b+c ["A" "b" nil]))))
561
+ (is (= [8 4 6 2]
562
+ (mapv :e (d/index-range db {:attrid :a+b+c :start ["A" "B" "C"] :end ["A" "b" "c"]}))))
563
+ (is (= [8 4]
564
+ (mapv :e (d/index-range db {:attrid :a+b+c :start ["A" "B" nil] :end ["A" "b" nil]}))))))