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.
- package/.circleci/config.yml +405 -0
- package/.circleci/scripts/gen_ci.clj +194 -0
- package/.cirrus.yml +60 -0
- package/.clj-kondo/babashka/sci/config.edn +1 -0
- package/.clj-kondo/babashka/sci/sci/core.clj +9 -0
- package/.clj-kondo/config.edn +95 -0
- package/.dir-locals.el +2 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/ISSUE_TEMPLATE/1-bug-report.yml +68 -0
- package/.github/ISSUE_TEMPLATE/2-feature-request.yml +28 -0
- package/.github/ISSUE_TEMPLATE/config.yml +6 -0
- package/.github/pull_request_template.md +24 -0
- package/.github/workflows/native-image.yml +84 -0
- package/LICENSE +203 -0
- package/README.md +273 -0
- package/bb/deps.edn +9 -0
- package/bb/resources/github-fingerprints +3 -0
- package/bb/resources/native-image-tests/run-bb-pod-tests.clj +162 -0
- package/bb/resources/native-image-tests/run-libdatahike-tests +12 -0
- package/bb/resources/native-image-tests/run-native-image-tests +74 -0
- package/bb/resources/native-image-tests/run-python-tests +22 -0
- package/bb/resources/native-image-tests/testconfig.attr-refs.edn +6 -0
- package/bb/resources/native-image-tests/testconfig.edn +5 -0
- package/bb/resources/template/.settings/org.eclipse.jdt.apt.core.prefs +2 -0
- package/bb/resources/template/.settings/org.eclipse.jdt.core.prefs +9 -0
- package/bb/resources/template/.settings/org.eclipse.m2e.core.prefs +4 -0
- package/bb/resources/template/pom.xml +22 -0
- package/bb/src/tools/build.clj +132 -0
- package/bb/src/tools/clj_kondo.clj +32 -0
- package/bb/src/tools/deploy.clj +26 -0
- package/bb/src/tools/examples.clj +19 -0
- package/bb/src/tools/npm.clj +100 -0
- package/bb/src/tools/python.clj +14 -0
- package/bb/src/tools/release.clj +94 -0
- package/bb/src/tools/test.clj +148 -0
- package/bb/src/tools/version.clj +47 -0
- package/bb.edn +269 -0
- package/benchmark/src/benchmark/cli.clj +195 -0
- package/benchmark/src/benchmark/compare.clj +157 -0
- package/benchmark/src/benchmark/config.clj +316 -0
- package/benchmark/src/benchmark/measure.clj +187 -0
- package/benchmark/src/benchmark/store.clj +190 -0
- package/benchmark/test/benchmark/measure_test.clj +156 -0
- package/build.clj +30 -0
- package/config.edn +49 -0
- package/deps.edn +138 -0
- package/dev/sandbox.clj +82 -0
- package/dev/sandbox.cljs +127 -0
- package/dev/sandbox_benchmarks.clj +27 -0
- package/dev/sandbox_client.clj +87 -0
- package/dev/sandbox_transact_bench.clj +109 -0
- package/dev/user.clj +79 -0
- package/doc/README.md +96 -0
- package/doc/adl/README.md +6 -0
- package/doc/adl/adr-000-adr.org +28 -0
- package/doc/adl/adr-001-attribute-references.org +15 -0
- package/doc/adl/adr-002-build-tooling.org +54 -0
- package/doc/adl/adr-003-db-meta-data.md +52 -0
- package/doc/adl/adr-004-github-flow.md +40 -0
- package/doc/adl/adr-XYZ-template.md +30 -0
- package/doc/adl/index.org +3 -0
- package/doc/assets/datahike-logo.svg +3 -0
- package/doc/assets/datahiking-invoice.org +85 -0
- package/doc/assets/hhtree2.png +0 -0
- package/doc/assets/network_topology.svg +624 -0
- package/doc/assets/perf.png +0 -0
- package/doc/assets/schema_mindmap.mm +132 -0
- package/doc/assets/schema_mindmap.svg +970 -0
- package/doc/assets/temporal_index.mm +74 -0
- package/doc/backend-development.md +78 -0
- package/doc/bb-pod.md +89 -0
- package/doc/benchmarking.md +360 -0
- package/doc/bindings/edn-conversion.md +383 -0
- package/doc/cli.md +162 -0
- package/doc/cljdoc.edn +27 -0
- package/doc/cljs-support.md +133 -0
- package/doc/config.md +406 -0
- package/doc/contributing.md +114 -0
- package/doc/datalog-vs-sql.md +210 -0
- package/doc/datomic_differences.md +109 -0
- package/doc/development/pull-api-ns.md +186 -0
- package/doc/development/pull-frame-state-diagram.jpg +0 -0
- package/doc/distributed.md +566 -0
- package/doc/entity_spec.md +92 -0
- package/doc/gc.md +273 -0
- package/doc/java-api.md +808 -0
- package/doc/javascript-api.md +421 -0
- package/doc/libdatahike.md +86 -0
- package/doc/logging_and_error_handling.md +43 -0
- package/doc/norms.md +66 -0
- package/doc/schema-migration.md +85 -0
- package/doc/schema.md +287 -0
- package/doc/storage-backends.md +363 -0
- package/doc/store-id-refactoring.md +596 -0
- package/doc/time_variance.md +325 -0
- package/doc/unstructured.md +167 -0
- package/doc/versioning.md +261 -0
- package/examples/basic/README.md +19 -0
- package/examples/basic/deps.edn +6 -0
- package/examples/basic/docker-compose.yml +13 -0
- package/examples/basic/src/examples/core.clj +60 -0
- package/examples/basic/src/examples/schema.clj +155 -0
- package/examples/basic/src/examples/store.clj +60 -0
- package/examples/basic/src/examples/time_travel.clj +185 -0
- package/examples/java/.settings/org.eclipse.core.resources.prefs +3 -0
- package/examples/java/.settings/org.eclipse.jdt.apt.core.prefs +2 -0
- package/examples/java/.settings/org.eclipse.jdt.core.prefs +9 -0
- package/examples/java/.settings/org.eclipse.m2e.core.prefs +4 -0
- package/examples/java/README.md +162 -0
- package/examples/java/pom.xml +62 -0
- package/examples/java/src/main/java/examples/QuickStart.java +115 -0
- package/examples/java/src/main/java/examples/SchemaExample.java +148 -0
- package/examples/java/src/main/java/examples/TimeTravelExample.java +121 -0
- package/flake.lock +27 -0
- package/flake.nix +27 -0
- package/http-server/datahike/http/middleware.clj +75 -0
- package/http-server/datahike/http/server.clj +269 -0
- package/java/src/datahike/java/Database.java +274 -0
- package/java/src/datahike/java/Datahike.java +281 -0
- package/java/src/datahike/java/DatahikeGeneratedTest.java +349 -0
- package/java/src/datahike/java/DatahikeTest.java +370 -0
- package/java/src/datahike/java/EDN.java +170 -0
- package/java/src/datahike/java/IEntity.java +11 -0
- package/java/src/datahike/java/Keywords.java +161 -0
- package/java/src/datahike/java/SchemaFlexibility.java +52 -0
- package/java/src/datahike/java/Util.java +219 -0
- package/karma.conf.js +19 -0
- package/libdatahike/compile-cpp +7 -0
- package/libdatahike/src/datahike/impl/LibDatahikeBase.java +203 -0
- package/libdatahike/src/datahike/impl/libdatahike.clj +59 -0
- package/libdatahike/src/test_cpp.cpp +61 -0
- package/npm-package/PUBLISHING.md +140 -0
- package/npm-package/README.md +226 -0
- package/npm-package/package.template.json +34 -0
- package/npm-package/test-isomorphic.ts +281 -0
- package/npm-package/test.js +557 -0
- package/npm-package/typescript-test.ts +70 -0
- package/package.json +16 -0
- package/pydatahike/README.md +569 -0
- package/pydatahike/pyproject.toml +91 -0
- package/pydatahike/setup.py +42 -0
- package/pydatahike/src/datahike/__init__.py +134 -0
- package/pydatahike/src/datahike/_native.py +250 -0
- package/pydatahike/src/datahike/_version.py +2 -0
- package/pydatahike/src/datahike/database.py +722 -0
- package/pydatahike/src/datahike/edn.py +311 -0
- package/pydatahike/src/datahike/py.typed +0 -0
- package/pydatahike/tests/conftest.py +17 -0
- package/pydatahike/tests/test_basic.py +170 -0
- package/pydatahike/tests/test_database.py +51 -0
- package/pydatahike/tests/test_edn_conversion.py +299 -0
- package/pydatahike/tests/test_query.py +99 -0
- package/pydatahike/tests/test_schema.py +55 -0
- package/resources/clj-kondo.exports/io.replikativ/datahike/config.edn +5 -0
- package/resources/example_server.edn +4 -0
- package/shadow-cljs.edn +56 -0
- package/src/data_readers.clj +7 -0
- package/src/datahike/api/impl.cljc +176 -0
- package/src/datahike/api/specification.cljc +633 -0
- package/src/datahike/api/types.cljc +261 -0
- package/src/datahike/api.cljc +41 -0
- package/src/datahike/array.cljc +99 -0
- package/src/datahike/cli.clj +166 -0
- package/src/datahike/cljs.cljs +6 -0
- package/src/datahike/codegen/cli.clj +406 -0
- package/src/datahike/codegen/clj_kondo.clj +291 -0
- package/src/datahike/codegen/java.clj +403 -0
- package/src/datahike/codegen/naming.cljc +33 -0
- package/src/datahike/codegen/native.clj +559 -0
- package/src/datahike/codegen/pod.clj +488 -0
- package/src/datahike/codegen/python.clj +838 -0
- package/src/datahike/codegen/report.clj +55 -0
- package/src/datahike/codegen/typescript.clj +262 -0
- package/src/datahike/codegen/validation.clj +145 -0
- package/src/datahike/config.cljc +294 -0
- package/src/datahike/connections.cljc +16 -0
- package/src/datahike/connector.cljc +265 -0
- package/src/datahike/constants.cljc +142 -0
- package/src/datahike/core.cljc +297 -0
- package/src/datahike/datom.cljc +459 -0
- package/src/datahike/db/interface.cljc +119 -0
- package/src/datahike/db/search.cljc +305 -0
- package/src/datahike/db/transaction.cljc +937 -0
- package/src/datahike/db/utils.cljc +338 -0
- package/src/datahike/db.cljc +956 -0
- package/src/datahike/experimental/unstructured.cljc +126 -0
- package/src/datahike/experimental/versioning.cljc +172 -0
- package/src/datahike/externs.js +31 -0
- package/src/datahike/gc.cljc +69 -0
- package/src/datahike/http/client.clj +188 -0
- package/src/datahike/http/writer.clj +79 -0
- package/src/datahike/impl/entity.cljc +218 -0
- package/src/datahike/index/interface.cljc +93 -0
- package/src/datahike/index/persistent_set.cljc +469 -0
- package/src/datahike/index/utils.cljc +44 -0
- package/src/datahike/index.cljc +32 -0
- package/src/datahike/js/api.cljs +172 -0
- package/src/datahike/js/api_macros.clj +22 -0
- package/src/datahike/js.cljs +163 -0
- package/src/datahike/json.cljc +209 -0
- package/src/datahike/lru.cljc +146 -0
- package/src/datahike/migrate.clj +39 -0
- package/src/datahike/norm/norm.clj +245 -0
- package/src/datahike/online_gc.cljc +252 -0
- package/src/datahike/pod.clj +155 -0
- package/src/datahike/pull_api.cljc +325 -0
- package/src/datahike/query.cljc +1945 -0
- package/src/datahike/query_stats.cljc +88 -0
- package/src/datahike/readers.cljc +62 -0
- package/src/datahike/remote.cljc +218 -0
- package/src/datahike/schema.cljc +228 -0
- package/src/datahike/schema_cache.cljc +42 -0
- package/src/datahike/spec.cljc +101 -0
- package/src/datahike/store.cljc +80 -0
- package/src/datahike/tools.cljc +308 -0
- package/src/datahike/transit.cljc +80 -0
- package/src/datahike/writer.cljc +239 -0
- package/src/datahike/writing.cljc +362 -0
- package/src/deps.cljs +1 -0
- package/src-hitchhiker-tree/datahike/index/hitchhiker_tree/insert.cljc +76 -0
- package/src-hitchhiker-tree/datahike/index/hitchhiker_tree/upsert.cljc +128 -0
- package/src-hitchhiker-tree/datahike/index/hitchhiker_tree.cljc +213 -0
- package/test/datahike/backward_compatibility_test/src/backward_test.clj +37 -0
- package/test/datahike/integration_test/config_record_file_test.clj +14 -0
- package/test/datahike/integration_test/config_record_test.clj +14 -0
- package/test/datahike/integration_test/depr_config_uri_test.clj +15 -0
- package/test/datahike/integration_test/return_map_test.clj +62 -0
- package/test/datahike/integration_test.cljc +67 -0
- package/test/datahike/norm/norm_test.clj +124 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/001-a1-example.edn +5 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/002-a2-example.edn +5 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/003-tx-fn-test.edn +1 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/004-tx-data-and-tx-fn-test.edn +5 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/01-transact-basic-characters.edn +2 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/02 add occupation.edn +5 -0
- package/test/datahike/norm/resources/naming-and-sorting-test/checksums.edn +12 -0
- package/test/datahike/norm/resources/simple-test/001-a1-example.edn +5 -0
- package/test/datahike/norm/resources/simple-test/002-a2-example.edn +5 -0
- package/test/datahike/norm/resources/simple-test/checksums.edn +4 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/001-a1-example.edn +5 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/002-a2-example.edn +5 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/003-tx-fn-test.edn +1 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/first/checksums.edn +6 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/second/004-tx-data-and-tx-fn-test.edn +5 -0
- package/test/datahike/norm/resources/tx-data-and-tx-fn-test/second/checksums.edn +2 -0
- package/test/datahike/norm/resources/tx-fn-test/first/001-a1-example.edn +5 -0
- package/test/datahike/norm/resources/tx-fn-test/first/002-a2-example.edn +5 -0
- package/test/datahike/norm/resources/tx-fn-test/first/checksums.edn +4 -0
- package/test/datahike/norm/resources/tx-fn-test/second/003-tx-fn-test.edn +1 -0
- package/test/datahike/norm/resources/tx-fn-test/second/checksums.edn +2 -0
- package/test/datahike/test/api_test.cljc +895 -0
- package/test/datahike/test/array_test.cljc +40 -0
- package/test/datahike/test/attribute_refs/datoms_test.cljc +140 -0
- package/test/datahike/test/attribute_refs/db_test.cljc +42 -0
- package/test/datahike/test/attribute_refs/differences_test.cljc +515 -0
- package/test/datahike/test/attribute_refs/entity_test.cljc +89 -0
- package/test/datahike/test/attribute_refs/pull_api_test.cljc +320 -0
- package/test/datahike/test/attribute_refs/query_find_specs_test.cljc +59 -0
- package/test/datahike/test/attribute_refs/query_fns_test.cljc +130 -0
- package/test/datahike/test/attribute_refs/query_interop_test.cljc +47 -0
- package/test/datahike/test/attribute_refs/query_not_test.cljc +193 -0
- package/test/datahike/test/attribute_refs/query_or_test.cljc +137 -0
- package/test/datahike/test/attribute_refs/query_pull_test.cljc +156 -0
- package/test/datahike/test/attribute_refs/query_rules_test.cljc +176 -0
- package/test/datahike/test/attribute_refs/query_test.cljc +241 -0
- package/test/datahike/test/attribute_refs/temporal_search.cljc +22 -0
- package/test/datahike/test/attribute_refs/transact_test.cljc +220 -0
- package/test/datahike/test/attribute_refs/utils.cljc +128 -0
- package/test/datahike/test/cache_test.cljc +38 -0
- package/test/datahike/test/components_test.cljc +92 -0
- package/test/datahike/test/config_test.cljc +158 -0
- package/test/datahike/test/core_test.cljc +105 -0
- package/test/datahike/test/datom_test.cljc +44 -0
- package/test/datahike/test/db_test.cljc +54 -0
- package/test/datahike/test/entity_spec_test.cljc +159 -0
- package/test/datahike/test/entity_test.cljc +103 -0
- package/test/datahike/test/explode_test.cljc +143 -0
- package/test/datahike/test/filter_test.cljc +75 -0
- package/test/datahike/test/gc_test.cljc +159 -0
- package/test/datahike/test/http/server_test.clj +192 -0
- package/test/datahike/test/http/writer_test.clj +86 -0
- package/test/datahike/test/ident_test.cljc +32 -0
- package/test/datahike/test/index_test.cljc +345 -0
- package/test/datahike/test/insert.cljc +125 -0
- package/test/datahike/test/java_bindings_test.clj +6 -0
- package/test/datahike/test/listen_test.cljc +41 -0
- package/test/datahike/test/lookup_refs_test.cljc +266 -0
- package/test/datahike/test/lru_test.cljc +27 -0
- package/test/datahike/test/migrate_test.clj +297 -0
- package/test/datahike/test/model/core.cljc +376 -0
- package/test/datahike/test/model/invariant.cljc +142 -0
- package/test/datahike/test/model/rng.cljc +82 -0
- package/test/datahike/test/model_test.clj +217 -0
- package/test/datahike/test/nodejs_test.cljs +262 -0
- package/test/datahike/test/online_gc_test.cljc +475 -0
- package/test/datahike/test/pod_test.clj +369 -0
- package/test/datahike/test/pull_api_test.cljc +474 -0
- package/test/datahike/test/purge_test.cljc +144 -0
- package/test/datahike/test/query_aggregates_test.cljc +101 -0
- package/test/datahike/test/query_find_specs_test.cljc +52 -0
- package/test/datahike/test/query_fns_test.cljc +523 -0
- package/test/datahike/test/query_interop_test.cljc +47 -0
- package/test/datahike/test/query_not_test.cljc +189 -0
- package/test/datahike/test/query_or_test.cljc +158 -0
- package/test/datahike/test/query_pull_test.cljc +147 -0
- package/test/datahike/test/query_rules_test.cljc +248 -0
- package/test/datahike/test/query_stats_test.cljc +218 -0
- package/test/datahike/test/query_test.cljc +984 -0
- package/test/datahike/test/schema_test.cljc +424 -0
- package/test/datahike/test/specification_test.cljc +30 -0
- package/test/datahike/test/store_test.cljc +78 -0
- package/test/datahike/test/stress_test.cljc +57 -0
- package/test/datahike/test/time_variance_test.cljc +518 -0
- package/test/datahike/test/tools_test.clj +134 -0
- package/test/datahike/test/transact_test.cljc +518 -0
- package/test/datahike/test/tuples_test.cljc +564 -0
- package/test/datahike/test/unstructured_test.cljc +291 -0
- package/test/datahike/test/upsert_impl_test.cljc +205 -0
- package/test/datahike/test/upsert_test.cljc +363 -0
- package/test/datahike/test/utils.cljc +110 -0
- package/test/datahike/test/validation_test.cljc +48 -0
- package/test/datahike/test/versioning_test.cljc +56 -0
- package/test/datahike/test.cljc +66 -0
- package/tests.edn +24 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
(ns ^:no-doc datahike.index.hitchhiker-tree.upsert
|
|
2
|
+
(:require [datahike.index.utils :as diu]
|
|
3
|
+
[hitchhiker.tree :as tree]
|
|
4
|
+
[hitchhiker.tree.op :as op]))
|
|
5
|
+
|
|
6
|
+
(defn- increase-by-one?
|
|
7
|
+
"Returns true if elements in vector 'indices' form a prefix of the vector indices.
|
|
8
|
+
This is equivalent to check whether the elements increase by one and contains 0.
|
|
9
|
+
E.g., [0 1 2] => true, [0 2 3] => false, [1 2] => false."
|
|
10
|
+
[indices]
|
|
11
|
+
(if (.contains ^clojure.lang.PersistentVector indices 0)
|
|
12
|
+
(let [m (apply max indices)
|
|
13
|
+
s (apply + indices)]
|
|
14
|
+
(= s (/ (* m (+ 1 m)) 2)))
|
|
15
|
+
false))
|
|
16
|
+
|
|
17
|
+
(def prefix? (memoize increase-by-one?))
|
|
18
|
+
|
|
19
|
+
(defn mask [new indices]
|
|
20
|
+
(reduce (fn [mask pos]
|
|
21
|
+
(assoc mask pos (nth new pos)))
|
|
22
|
+
[nil nil nil nil]
|
|
23
|
+
indices))
|
|
24
|
+
|
|
25
|
+
(defn old-key
|
|
26
|
+
"Returns the old version of the given 'new' key if it exists in 'old-keys'.
|
|
27
|
+
'indices' is a vector of integer indicating which positions in keys are significant,
|
|
28
|
+
i.e., [0 2] means that the first and third entry in the key are used for filtering."
|
|
29
|
+
[old-keys new indices]
|
|
30
|
+
(when (seq old-keys)
|
|
31
|
+
(let [mask (mask new indices)]
|
|
32
|
+
(when-let [candidates (subseq old-keys >= mask)]
|
|
33
|
+
(when (or (not (prefix? indices))
|
|
34
|
+
(diu/equals-on-indices? new (-> candidates first first) indices))
|
|
35
|
+
(let [res (->> candidates
|
|
36
|
+
(map first)
|
|
37
|
+
;; Returns the key which has not been retracted.
|
|
38
|
+
;; There will at most be one such key.
|
|
39
|
+
;; Because of the ordering in keys, we know that
|
|
40
|
+
;; when two successive keys have a positive
|
|
41
|
+
;; :t value, then the second key is our answer,
|
|
42
|
+
;; the one that has not been retracted."
|
|
43
|
+
(reduce (fn [prev-pos? k]
|
|
44
|
+
(let [curr-pos? (pos? (nth k 3))]
|
|
45
|
+
(if (and curr-pos?
|
|
46
|
+
prev-pos?
|
|
47
|
+
(diu/equals-on-indices? new k indices))
|
|
48
|
+
(reduced k)
|
|
49
|
+
curr-pos?)))
|
|
50
|
+
true))]
|
|
51
|
+
(if (boolean? res) nil res)))))))
|
|
52
|
+
|
|
53
|
+
(defn remove-old
|
|
54
|
+
"Removes old key from the 'kvs' map using 'remove-fn' function."
|
|
55
|
+
[kvs new remove-fn indices]
|
|
56
|
+
(when-let [old (old-key kvs new indices)]
|
|
57
|
+
(remove-fn old)))
|
|
58
|
+
|
|
59
|
+
(defrecord UpsertOp [key op-count indices version]
|
|
60
|
+
op/IOperation
|
|
61
|
+
(-insertion-ts [_] op-count)
|
|
62
|
+
(-affects-key [_] key)
|
|
63
|
+
(-apply-op-to-coll [_ kvs]
|
|
64
|
+
(-> (or (remove-old kvs key (partial dissoc kvs) indices) kvs)
|
|
65
|
+
(assoc key nil)))
|
|
66
|
+
(-apply-op-to-tree [_ tree]
|
|
67
|
+
(let [children (cond
|
|
68
|
+
(tree/data-node? tree) (:children tree)
|
|
69
|
+
:else (:children (peek (tree/lookup-path tree key))))]
|
|
70
|
+
(-> (or (remove-old children key (partial tree/delete tree) indices) tree)
|
|
71
|
+
(tree/insert key nil)))))
|
|
72
|
+
|
|
73
|
+
(defn old-retracted
|
|
74
|
+
"Returns a new datom to be inserted in the tree to signal the retraction of
|
|
75
|
+
its corresponding 'old' datom."
|
|
76
|
+
[kvs key old indices]
|
|
77
|
+
(let [[a b c _] old
|
|
78
|
+
[_ _ _ nt] key]
|
|
79
|
+
;; '-' means it is retracted and 'nt' is the current transaction time.
|
|
80
|
+
[a b c (- nt)]))
|
|
81
|
+
|
|
82
|
+
(defrecord temporal-UpsertOp [key op-count indices version]
|
|
83
|
+
op/IOperation
|
|
84
|
+
(-insertion-ts [_] op-count)
|
|
85
|
+
(-affects-key [_] key)
|
|
86
|
+
(-apply-op-to-coll [_ kvs]
|
|
87
|
+
(if-let [old (old-key kvs key indices)]
|
|
88
|
+
(if (diu/equals-on-indices? key old [0 1 2])
|
|
89
|
+
kvs
|
|
90
|
+
(let [old-retracted (old-retracted kvs key old indices)]
|
|
91
|
+
(-> (assoc kvs old-retracted nil)
|
|
92
|
+
(assoc key nil))))
|
|
93
|
+
(assoc kvs key nil)))
|
|
94
|
+
(-apply-op-to-tree [_ tree]
|
|
95
|
+
(let [children (cond
|
|
96
|
+
(tree/data-node? tree) (:children tree)
|
|
97
|
+
:else (:children (peek (tree/lookup-path tree key))))
|
|
98
|
+
old (old-key children key indices)]
|
|
99
|
+
(if old
|
|
100
|
+
(if (diu/equals-on-indices? key old [0 1 2])
|
|
101
|
+
tree
|
|
102
|
+
(let [old-retracted (old-retracted children key old indices)]
|
|
103
|
+
(-> (tree/insert tree old-retracted nil)
|
|
104
|
+
(tree/insert key nil))))
|
|
105
|
+
(tree/insert tree key nil)))))
|
|
106
|
+
|
|
107
|
+
(defn new-UpsertOp [key op-count indices]
|
|
108
|
+
(UpsertOp. key op-count indices 0))
|
|
109
|
+
|
|
110
|
+
(defn new-temporal-UpsertOp [key op-count indices]
|
|
111
|
+
(temporal-UpsertOp. key op-count indices 0))
|
|
112
|
+
|
|
113
|
+
(defn add-upsert-handler
|
|
114
|
+
"Tells the store how to deserialize upsert related operations"
|
|
115
|
+
[store]
|
|
116
|
+
(swap! (:read-handlers store)
|
|
117
|
+
merge
|
|
118
|
+
{'datahike.index.hitchhiker_tree.upsert.UpsertOp
|
|
119
|
+
;; TODO Remove ts when Wanderung is available.
|
|
120
|
+
(fn [{:keys [key value op-count ts indices]}]
|
|
121
|
+
(map->UpsertOp {:key key :value value :op-count (or op-count ts) :indices (or indices [0 1])
|
|
122
|
+
:version 0}))
|
|
123
|
+
|
|
124
|
+
'datahike.index.hitchhiker_tree.upsert.temporal_UpsertOp
|
|
125
|
+
(fn [{:keys [key value op-count ts indices]}]
|
|
126
|
+
(map->temporal-UpsertOp {:key key :value value :op-count (or op-count ts) :indices (or indices [0 1])
|
|
127
|
+
:version 0}))})
|
|
128
|
+
store)
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
(ns ^:no-doc datahike.index.hitchhiker-tree
|
|
2
|
+
(:require [datahike.index.hitchhiker-tree.upsert :as ups]
|
|
3
|
+
[datahike.index.hitchhiker-tree.insert :as ins]
|
|
4
|
+
[datahike.index.utils :as diu]
|
|
5
|
+
[hitchhiker.tree.bootstrap.konserve :as hk]
|
|
6
|
+
[hitchhiker.tree.utils.async :as async]
|
|
7
|
+
[hitchhiker.tree.messaging :as hmsg]
|
|
8
|
+
[hitchhiker.tree.key-compare :as kc]
|
|
9
|
+
[hitchhiker.tree :as tree]
|
|
10
|
+
[datahike.array :refer [compare-arrays]]
|
|
11
|
+
[datahike.datom :as dd]
|
|
12
|
+
[datahike.constants :refer [e0 tx0 emax txmax]]
|
|
13
|
+
[clojure.spec.alpha :as s]
|
|
14
|
+
[datahike.index.interface :as di :refer [IIndex]])
|
|
15
|
+
#?(:clj (:import [clojure.lang AMapEntry]
|
|
16
|
+
[hitchhiker.tree DataNode IndexNode]
|
|
17
|
+
[datahike.datom Datom])))
|
|
18
|
+
|
|
19
|
+
(def ^:const default-index-b-factor 17)
|
|
20
|
+
(def ^:const default-index-data-node-size 300)
|
|
21
|
+
(def ^:const default-index-log-size (- 300 17))
|
|
22
|
+
|
|
23
|
+
(extend-protocol kc/IKeyCompare
|
|
24
|
+
clojure.lang.PersistentVector
|
|
25
|
+
(-compare [key1 key2]
|
|
26
|
+
(if-not (= (class key2) clojure.lang.PersistentVector)
|
|
27
|
+
(if (nil? key2)
|
|
28
|
+
+1 ;; Case for tuples. E.g. (compare [100 200] nil)
|
|
29
|
+
-1) ;; HACK for nil
|
|
30
|
+
(let [[a b c d] key1
|
|
31
|
+
[e f g h] key2]
|
|
32
|
+
(dd/combine-cmp
|
|
33
|
+
(kc/-compare a e)
|
|
34
|
+
(kc/-compare b f)
|
|
35
|
+
(kc/-compare c g)
|
|
36
|
+
(kc/-compare d h)))))
|
|
37
|
+
java.lang.String
|
|
38
|
+
(-compare [key1 key2]
|
|
39
|
+
(compare key1 key2))
|
|
40
|
+
clojure.lang.Keyword
|
|
41
|
+
(-compare [key1 key2]
|
|
42
|
+
(compare key1 key2))
|
|
43
|
+
nil
|
|
44
|
+
(-compare [key1 key2]
|
|
45
|
+
(if (nil? key2)
|
|
46
|
+
0 -1)))
|
|
47
|
+
|
|
48
|
+
(extend-protocol kc/IKeyCompare
|
|
49
|
+
(Class/forName "[B")
|
|
50
|
+
(-compare [key1 key2]
|
|
51
|
+
(compare-arrays key1 key2)))
|
|
52
|
+
|
|
53
|
+
(defn- index-type->datom-fn [index-type]
|
|
54
|
+
(case index-type
|
|
55
|
+
:aevt (fn [a e v tx] (dd/datom e a v tx true))
|
|
56
|
+
:avet (fn [a v e tx] (dd/datom e a v tx true))
|
|
57
|
+
(fn [e a v tx] (dd/datom e a v tx true))))
|
|
58
|
+
|
|
59
|
+
(defn slice [tree from to index-type]
|
|
60
|
+
(let [[a b c d] (diu/datom-to-vec from index-type true)
|
|
61
|
+
cmp (diu/prefix-scan kc/-compare (diu/datom-to-vec to index-type false))
|
|
62
|
+
xf (comp
|
|
63
|
+
(take-while (fn [^AMapEntry kv] (cmp (.key kv))))
|
|
64
|
+
(map (fn [kv]
|
|
65
|
+
(let [[a b c d] (.key ^AMapEntry kv)]
|
|
66
|
+
((index-type->datom-fn index-type) a b c d)))))]
|
|
67
|
+
(->> (sequence xf (hmsg/lookup-fwd-iter tree [a b c d]))
|
|
68
|
+
seq)))
|
|
69
|
+
|
|
70
|
+
(defn datom-seq [tree index-type]
|
|
71
|
+
(slice tree (dd/datom e0 nil nil tx0) (dd/datom emax nil nil txmax) index-type))
|
|
72
|
+
|
|
73
|
+
(defn datom-count [tree index-type]
|
|
74
|
+
(count (datom-seq tree index-type)))
|
|
75
|
+
|
|
76
|
+
(defn all-datoms [tree index-type]
|
|
77
|
+
(map
|
|
78
|
+
#(apply
|
|
79
|
+
(index-type->datom-fn index-type)
|
|
80
|
+
(first %))
|
|
81
|
+
(hmsg/lookup-fwd-iter tree [])))
|
|
82
|
+
|
|
83
|
+
(defn- datom->node [^Datom datom index-type]
|
|
84
|
+
(case index-type
|
|
85
|
+
:aevt [(.-a datom) (.-e datom) (.-v datom) (.-tx datom)]
|
|
86
|
+
:avet [(.-a datom) (.-v datom) (.-e datom) (.-tx datom)]
|
|
87
|
+
:eavt [(.-e datom) (.-a datom) (.-v datom) (.-tx datom)]
|
|
88
|
+
(throw (IllegalArgumentException. (str "Unknown index-type: " index-type)))))
|
|
89
|
+
|
|
90
|
+
(defn- index-type->indices [index-type]
|
|
91
|
+
(case index-type
|
|
92
|
+
:eavt [0 1]
|
|
93
|
+
:aevt [0 1]
|
|
94
|
+
:avet [0 2]
|
|
95
|
+
(throw (UnsupportedOperationException. "Unknown index type: " index-type))))
|
|
96
|
+
|
|
97
|
+
(defn insert [tree ^Datom datom index-type op-count]
|
|
98
|
+
(let [datom-as-vec (datom->node datom index-type)]
|
|
99
|
+
(async/<?? (hmsg/enqueue tree [(ins/new-InsertOp datom-as-vec op-count)]))))
|
|
100
|
+
|
|
101
|
+
(defn temporal-insert [tree ^Datom datom index-type op-count]
|
|
102
|
+
(let [datom-as-vec (datom->node datom index-type)]
|
|
103
|
+
(async/<?? (hmsg/enqueue tree [(ins/new-temporal-InsertOp datom-as-vec op-count)]))))
|
|
104
|
+
|
|
105
|
+
(defn upsert [tree ^Datom datom index-type op-count]
|
|
106
|
+
(let [datom-as-vec (datom->node datom index-type)]
|
|
107
|
+
(async/<?? (hmsg/enqueue tree [(ups/new-UpsertOp datom-as-vec op-count (index-type->indices index-type))]))))
|
|
108
|
+
|
|
109
|
+
(defn temporal-upsert [tree ^Datom datom index-type op-count]
|
|
110
|
+
(let [datom-as-vec (datom->node datom index-type)]
|
|
111
|
+
(async/<?? (hmsg/enqueue tree [(ups/new-temporal-UpsertOp datom-as-vec op-count (index-type->indices index-type))]))))
|
|
112
|
+
|
|
113
|
+
(defn remove-datom [tree ^Datom datom index-type op-count]
|
|
114
|
+
(async/<?? (hmsg/delete tree (datom->node datom index-type) op-count)))
|
|
115
|
+
|
|
116
|
+
(defn flush-tree [tree backend]
|
|
117
|
+
(:tree (async/<?? (tree/flush-tree-without-root tree backend))))
|
|
118
|
+
|
|
119
|
+
(defn mark [_tree]
|
|
120
|
+
(throw (ex-info "Mark phase not implemented for hitchhiker-tree."
|
|
121
|
+
{:type :gc-not-implemented})))
|
|
122
|
+
|
|
123
|
+
(extend-type DataNode
|
|
124
|
+
IIndex
|
|
125
|
+
(-all [eavt-tree]
|
|
126
|
+
(all-datoms eavt-tree :eavt))
|
|
127
|
+
(-seq [eavt-tree]
|
|
128
|
+
(datom-seq eavt-tree :eavt))
|
|
129
|
+
(-count [eavt-tree]
|
|
130
|
+
(datom-count eavt-tree :eavt))
|
|
131
|
+
(-insert [tree datom index-type op-count]
|
|
132
|
+
(insert tree datom index-type op-count))
|
|
133
|
+
(-temporal-insert [tree datom index-type op-count]
|
|
134
|
+
(temporal-insert tree datom index-type op-count))
|
|
135
|
+
(-upsert [tree datom index-type op-count _old-datom]
|
|
136
|
+
(upsert tree datom index-type op-count))
|
|
137
|
+
(-temporal-upsert [tree datom index-type op-count _old-datom]
|
|
138
|
+
(temporal-upsert tree datom index-type op-count))
|
|
139
|
+
(-remove [tree datom index-type op-count]
|
|
140
|
+
(remove-datom tree datom index-type op-count))
|
|
141
|
+
(-slice [tree from to index-type]
|
|
142
|
+
(slice tree from to index-type))
|
|
143
|
+
(-flush [tree backend]
|
|
144
|
+
(flush-tree tree backend))
|
|
145
|
+
(-transient [tree]
|
|
146
|
+
(identity tree))
|
|
147
|
+
(-persistent! [tree]
|
|
148
|
+
(identity tree))
|
|
149
|
+
(-mark [tree]
|
|
150
|
+
(mark tree)))
|
|
151
|
+
|
|
152
|
+
(extend-type IndexNode
|
|
153
|
+
IIndex
|
|
154
|
+
(-all [eavt-tree]
|
|
155
|
+
(all-datoms eavt-tree :eavt))
|
|
156
|
+
(-seq [eavt-tree]
|
|
157
|
+
(datom-seq eavt-tree :eavt))
|
|
158
|
+
(-count [eavt-tree]
|
|
159
|
+
(datom-count eavt-tree :eavt))
|
|
160
|
+
(-insert [tree datom index-type op-count]
|
|
161
|
+
(insert tree datom index-type op-count))
|
|
162
|
+
(-temporal-insert [index datom index-type op-count]
|
|
163
|
+
(temporal-insert index datom index-type op-count))
|
|
164
|
+
(-upsert [tree datom index-type op-count _old-datom]
|
|
165
|
+
(upsert tree datom index-type op-count))
|
|
166
|
+
(-temporal-upsert [tree datom index-type op-count _old-datom]
|
|
167
|
+
(temporal-upsert tree datom index-type op-count))
|
|
168
|
+
(-remove [tree datom index-type op-count]
|
|
169
|
+
(remove-datom tree datom index-type op-count))
|
|
170
|
+
(-slice [tree from to index-type]
|
|
171
|
+
(slice tree from to index-type))
|
|
172
|
+
(-flush [tree backend]
|
|
173
|
+
(flush-tree tree backend))
|
|
174
|
+
(-transient [tree]
|
|
175
|
+
(identity tree))
|
|
176
|
+
(-persistent! [tree]
|
|
177
|
+
(identity tree))
|
|
178
|
+
(-mark [tree]
|
|
179
|
+
(mark tree)))
|
|
180
|
+
|
|
181
|
+
(defn empty-tree [b-factor data-node-size log-size]
|
|
182
|
+
(async/<?? (tree/b-tree (tree/->Config b-factor data-node-size log-size))))
|
|
183
|
+
|
|
184
|
+
(defmethod di/empty-index :datahike.index/hitchhiker-tree
|
|
185
|
+
[_index-name _store _index-type {:keys [index-b-factor index-data-node-size index-log-size]}]
|
|
186
|
+
(empty-tree index-b-factor index-data-node-size index-log-size))
|
|
187
|
+
|
|
188
|
+
(defmethod di/init-index :datahike.index/hitchhiker-tree
|
|
189
|
+
[_index-name _store datoms index-type op-count {:keys [index-b-factor index-data-node-size index-log-size]}]
|
|
190
|
+
(async/<??
|
|
191
|
+
(async/reduce<
|
|
192
|
+
(fn [tree [idx datom]]
|
|
193
|
+
(insert tree datom index-type (+ idx op-count)))
|
|
194
|
+
(empty-tree index-b-factor index-data-node-size index-log-size)
|
|
195
|
+
(map-indexed (fn [idx datom] [idx datom]) (seq datoms)))))
|
|
196
|
+
|
|
197
|
+
(defmethod di/add-konserve-handlers :datahike.index/hitchhiker-tree [_config store]
|
|
198
|
+
(ups/add-upsert-handler
|
|
199
|
+
(ins/add-insert-handler
|
|
200
|
+
(hk/add-hitchhiker-tree-handlers
|
|
201
|
+
store))))
|
|
202
|
+
|
|
203
|
+
(defmethod di/konserve-backend :datahike.index/hitchhiker-tree [_index-name store]
|
|
204
|
+
(hk/->KonserveBackend store true))
|
|
205
|
+
|
|
206
|
+
(s/def ::index-b-factor long)
|
|
207
|
+
(s/def ::index-log-size long)
|
|
208
|
+
(s/def ::index-data-node-size long)
|
|
209
|
+
|
|
210
|
+
(defmethod di/default-index-config :datahike.index/hitchhiker-tree [_index-name]
|
|
211
|
+
{:index-b-factor default-index-b-factor
|
|
212
|
+
:index-log-size default-index-log-size
|
|
213
|
+
:index-data-node-size default-index-data-node-size})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
(ns backward-test
|
|
2
|
+
(:require [datahike.api :as d]
|
|
3
|
+
[taoensso.timbre :as t]))
|
|
4
|
+
|
|
5
|
+
(def schema [{:db/ident :age
|
|
6
|
+
:db/cardinality :db.cardinality/one
|
|
7
|
+
:db/valueType :db.type/long}])
|
|
8
|
+
(def cfg {:store {:backend :file
|
|
9
|
+
:path "/tmp/datahike-backward-comp-test"
|
|
10
|
+
:id #uuid "550e8400-e29b-41d4-a716-446655440000"}
|
|
11
|
+
:keep-history? true
|
|
12
|
+
:schema-flexibility :write
|
|
13
|
+
:initial-tx schema})
|
|
14
|
+
|
|
15
|
+
(def size 10000)
|
|
16
|
+
|
|
17
|
+
(defn write [opt]
|
|
18
|
+
(t/info "Writing to db using latest released version of datahike ....")
|
|
19
|
+
(t/set-level! :warn)
|
|
20
|
+
|
|
21
|
+
(d/delete-database cfg)
|
|
22
|
+
(d/create-database cfg)
|
|
23
|
+
(let [conn (d/connect cfg)]
|
|
24
|
+
(d/transact conn
|
|
25
|
+
(vec (for [i (range size)]
|
|
26
|
+
[:db/add (inc i) :age i]))))
|
|
27
|
+
(t/info "Wrote " size " entries."))
|
|
28
|
+
|
|
29
|
+
(defn read [opt]
|
|
30
|
+
(t/info "Reading using latest code ....")
|
|
31
|
+
(let [conn (d/connect cfg)
|
|
32
|
+
res (first (d/q '[:find (count ?a)
|
|
33
|
+
:in $
|
|
34
|
+
:where [?e :age ?a]]
|
|
35
|
+
@conn))]
|
|
36
|
+
(assert (= [size] res))
|
|
37
|
+
(t/info "Read " (first res) " entries.")))
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
(ns datahike.integration-test.config-record-file-test
|
|
2
|
+
(:require [clojure.test :refer :all]
|
|
3
|
+
[datahike.integration-test :as it]))
|
|
4
|
+
|
|
5
|
+
(def config {:store {:backend :file :path "/tmp/file-test-1" :id #uuid "f11e0001-0000-0000-0000-000000000001"}})
|
|
6
|
+
|
|
7
|
+
(defn config-record-file-test-fixture [f]
|
|
8
|
+
(it/integration-test-fixture config)
|
|
9
|
+
(f))
|
|
10
|
+
|
|
11
|
+
(use-fixtures :once config-record-file-test-fixture)
|
|
12
|
+
|
|
13
|
+
(deftest ^:integration config-record-file-test []
|
|
14
|
+
(it/integration-test config))
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
(ns datahike.integration-test.config-record-test
|
|
2
|
+
(:require [clojure.test :refer :all]
|
|
3
|
+
[datahike.integration-test :as it]))
|
|
4
|
+
|
|
5
|
+
(def config {:store {:backend :memory :id #uuid "c0ff1c00-0000-0000-0000-000000000001"}})
|
|
6
|
+
|
|
7
|
+
(defn config-record-test-fixture [f]
|
|
8
|
+
(it/integration-test-fixture config)
|
|
9
|
+
(f))
|
|
10
|
+
|
|
11
|
+
(use-fixtures :once config-record-test-fixture)
|
|
12
|
+
|
|
13
|
+
(deftest ^:integration config-record-test []
|
|
14
|
+
(it/integration-test config))
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
(ns datahike.integration-test.depr-config-uri-test
|
|
2
|
+
(:require [clojure.test :refer :all]
|
|
3
|
+
[datahike.integration-test :as it]))
|
|
4
|
+
|
|
5
|
+
(def config "datahike:file:///tmp/file-test-3?id=5c6e0000-0000-0000-0000-000000000003")
|
|
6
|
+
|
|
7
|
+
(defn depr-config-uri-fixture [f]
|
|
8
|
+
(println "deprecated file uri config: " config)
|
|
9
|
+
(it/integration-test-fixture config)
|
|
10
|
+
(f))
|
|
11
|
+
|
|
12
|
+
(use-fixtures :once depr-config-uri-fixture)
|
|
13
|
+
|
|
14
|
+
(deftest ^:integration depr-config-uri-test []
|
|
15
|
+
(it/integration-test config))
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
(ns datahike.integration-test.return-map-test
|
|
2
|
+
(:require [clojure.test :refer [deftest is use-fixtures]]
|
|
3
|
+
[datahike.api :as d]))
|
|
4
|
+
|
|
5
|
+
(def config {:store {:backend :memory :id #uuid "0e7000a9-0000-0000-0000-000000000001"}})
|
|
6
|
+
|
|
7
|
+
(defn return-map-test-fixture [f]
|
|
8
|
+
(d/delete-database config)
|
|
9
|
+
(d/create-database config)
|
|
10
|
+
(def conn (d/connect config))
|
|
11
|
+
;; the first transaction will be the schema we are using
|
|
12
|
+
(d/transact conn [{:db/ident :name
|
|
13
|
+
:db/valueType :db.type/string
|
|
14
|
+
:db/cardinality :db.cardinality/one}
|
|
15
|
+
{:db/ident :age
|
|
16
|
+
:db/valueType :db.type/long
|
|
17
|
+
:db/cardinality :db.cardinality/one}])
|
|
18
|
+
|
|
19
|
+
;; lets add some data and wait for the transaction
|
|
20
|
+
(d/transact conn [{:name "Alice", :age 20}
|
|
21
|
+
{:name "Bob", :age 30}
|
|
22
|
+
{:name "Charlie", :age 40}])
|
|
23
|
+
|
|
24
|
+
(f))
|
|
25
|
+
|
|
26
|
+
(use-fixtures :once return-map-test-fixture)
|
|
27
|
+
|
|
28
|
+
(deftest return-keys-test
|
|
29
|
+
;; search the data
|
|
30
|
+
(is (= [{:entity 4 :name "Bob" :age 30}
|
|
31
|
+
{:entity 5 :name "Charlie" :age 40}
|
|
32
|
+
{:entity 3 :name "Alice" :age 20}]
|
|
33
|
+
(d/q '[:find ?e ?n ?a
|
|
34
|
+
:keys entity name age
|
|
35
|
+
:where
|
|
36
|
+
[?e :name ?n]
|
|
37
|
+
[?e :age ?a]]
|
|
38
|
+
@conn))))
|
|
39
|
+
|
|
40
|
+
(deftest return-syms-test
|
|
41
|
+
;; search the data
|
|
42
|
+
(is (= [{'entity 4 'name "Bob" 'age 30}
|
|
43
|
+
{'entity 5 'name "Charlie" 'age 40}
|
|
44
|
+
{'entity 3 'name "Alice" 'age 20}]
|
|
45
|
+
(d/q '[:find ?e ?n ?a
|
|
46
|
+
:syms entity name age
|
|
47
|
+
:where
|
|
48
|
+
[?e :name ?n]
|
|
49
|
+
[?e :age ?a]]
|
|
50
|
+
@conn))))
|
|
51
|
+
|
|
52
|
+
(deftest return-strs-test
|
|
53
|
+
;; search the data
|
|
54
|
+
(is (= [{"entity" 4 "name" "Bob" "age" 30}
|
|
55
|
+
{"entity" 5 "name" "Charlie" "age" 40}
|
|
56
|
+
{"entity" 3 "name" "Alice" "age" 20}]
|
|
57
|
+
(d/q '[:find ?e ?n ?a
|
|
58
|
+
:strs entity name age
|
|
59
|
+
:where
|
|
60
|
+
[?e :name ?n]
|
|
61
|
+
[?e :age ?a]]
|
|
62
|
+
@conn))))
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
(ns ^:no-doc datahike.integration-test
|
|
2
|
+
"This namespace is the minimum test a Datahike backend needs to pass for compatibility assessment."
|
|
3
|
+
(:require [clojure.test :refer [is]]
|
|
4
|
+
[datahike.api :as d]
|
|
5
|
+
;; Load hitchhiker-tree for backwards compatibility with existing test databases
|
|
6
|
+
#?(:clj [datahike.index.hitchhiker-tree])))
|
|
7
|
+
|
|
8
|
+
(defn integration-test-fixture [config]
|
|
9
|
+
(d/delete-database config)
|
|
10
|
+
(d/create-database config)
|
|
11
|
+
(let [conn (d/connect config)]
|
|
12
|
+
(d/transact conn [{:db/ident :name
|
|
13
|
+
:db/valueType :db.type/string
|
|
14
|
+
:db/cardinality :db.cardinality/one}
|
|
15
|
+
{:db/ident :age
|
|
16
|
+
:db/valueType :db.type/long
|
|
17
|
+
:db/cardinality :db.cardinality/one}])
|
|
18
|
+
|
|
19
|
+
;; lets add some data and wait for the transaction
|
|
20
|
+
(d/transact conn [{:name "Alice", :age 20}
|
|
21
|
+
{:name "Bob", :age 30}
|
|
22
|
+
{:name "Charlie", :age 40}
|
|
23
|
+
{:age 15}])
|
|
24
|
+
(d/release conn)))
|
|
25
|
+
|
|
26
|
+
(defn integration-test [config]
|
|
27
|
+
(let [conn (d/connect config)]
|
|
28
|
+
;; search the data
|
|
29
|
+
(is (= #{[3 "Alice" 20] [4 "Bob" 30] [5 "Charlie" 40]}
|
|
30
|
+
(d/q '[:find ?e ?n ?a
|
|
31
|
+
:where
|
|
32
|
+
[?e :name ?n]
|
|
33
|
+
[?e :age ?a]]
|
|
34
|
+
@conn)))
|
|
35
|
+
|
|
36
|
+
;; add new entity data using a hash map
|
|
37
|
+
(d/transact conn {:tx-data [{:db/id 3 :age 25}]})
|
|
38
|
+
|
|
39
|
+
;; if you want to work with queries like in
|
|
40
|
+
;; https://grishaev.me/en/datomic-query/,
|
|
41
|
+
;; you may use a hashmap
|
|
42
|
+
(is (= #{[5 "Charlie" 40] [4 "Bob" 30] [3 "Alice" 25]}
|
|
43
|
+
(d/q {:query '{:find [?e ?n ?a]
|
|
44
|
+
:where [[?e :name ?n]
|
|
45
|
+
[?e :age ?a]]}
|
|
46
|
+
:args [@conn]})))
|
|
47
|
+
|
|
48
|
+
;; query the history of the data
|
|
49
|
+
(is (= #{[20] [25]}
|
|
50
|
+
(d/q '[:find ?a
|
|
51
|
+
:where
|
|
52
|
+
[?e :name "Alice"]
|
|
53
|
+
[?e :age ?a]]
|
|
54
|
+
(d/history @conn))))
|
|
55
|
+
|
|
56
|
+
;; you might need to release the connection, e.g. for leveldb
|
|
57
|
+
(is (= nil (d/release conn)))
|
|
58
|
+
|
|
59
|
+
;; database should exist
|
|
60
|
+
(is (d/database-exists? config))
|
|
61
|
+
|
|
62
|
+
;; clean up the database if it is not needed any more
|
|
63
|
+
(d/delete-database config)
|
|
64
|
+
|
|
65
|
+
;; database should not exist
|
|
66
|
+
(is (not (d/database-exists? config)))))
|
|
67
|
+
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
(ns datahike.norm.norm-test
|
|
2
|
+
(:require [clojure.test :refer [deftest is]]
|
|
3
|
+
[clojure.string :as string]
|
|
4
|
+
[clojure.java.io :as io]
|
|
5
|
+
[datahike.api :as d]
|
|
6
|
+
[datahike.norm.norm :as sut :refer [verify-checksums]]
|
|
7
|
+
[datahike.test.utils :as tu]))
|
|
8
|
+
|
|
9
|
+
(def ensure-norms #'sut/ensure-norms)
|
|
10
|
+
|
|
11
|
+
(deftest simple-test
|
|
12
|
+
(let [conn (tu/setup-db {} true)
|
|
13
|
+
_ (verify-checksums (io/file "test/datahike/norm/resources/simple-test"))
|
|
14
|
+
_ (ensure-norms conn (io/file "test/datahike/norm/resources/simple-test"))
|
|
15
|
+
schema (d/schema (d/db conn))]
|
|
16
|
+
(is (= #:db{:valueType :db.type/string, :cardinality :db.cardinality/one, :doc "Place of occupation", :ident :character/place-of-occupation}
|
|
17
|
+
(-> (schema :character/place-of-occupation)
|
|
18
|
+
(dissoc :db/id))))
|
|
19
|
+
(is (= #:db{:valueType :db.type/string, :cardinality :db.cardinality/one, :doc "Simpsons character name", :ident :character/name, :db/unique :db.unique/identity}
|
|
20
|
+
(-> (schema :character/name)
|
|
21
|
+
(dissoc :db/id))))
|
|
22
|
+
(is (= #:db{:ident :tx/norm, :valueType :db.type/keyword, :cardinality :db.cardinality/one}
|
|
23
|
+
(-> (schema :tx/norm)
|
|
24
|
+
(dissoc :db/id))))
|
|
25
|
+
(d/release conn)))
|
|
26
|
+
|
|
27
|
+
(defn tx-fn-test-fn [conn]
|
|
28
|
+
(-> (for [[eid value] (d/q '[:find ?e ?v
|
|
29
|
+
:where
|
|
30
|
+
[?e :character/place-of-occupation ?v]]
|
|
31
|
+
(d/db conn))]
|
|
32
|
+
[:db/add eid
|
|
33
|
+
:character/place-of-occupation (string/lower-case value)])
|
|
34
|
+
vec))
|
|
35
|
+
|
|
36
|
+
(deftest tx-fn-test
|
|
37
|
+
(let [conn (tu/setup-db {} true)
|
|
38
|
+
_ (verify-checksums (io/file "test/datahike/norm/resources/tx-fn-test/first"))
|
|
39
|
+
_ (ensure-norms conn (io/file "test/datahike/norm/resources/tx-fn-test/first"))
|
|
40
|
+
_ (d/transact conn {:tx-data [{:character/place-of-occupation "SPRINGFIELD ELEMENTARY SCHOOL"}
|
|
41
|
+
{:character/place-of-occupation "SPRINGFIELD NUCLEAR POWER PLANT"}]})
|
|
42
|
+
_ (verify-checksums (io/file "test/datahike/norm/resources/tx-fn-test/second"))
|
|
43
|
+
_ (ensure-norms conn (io/file "test/datahike/norm/resources/tx-fn-test/second"))]
|
|
44
|
+
(is (= #{["springfield elementary school"] ["springfield nuclear power plant"]}
|
|
45
|
+
(d/q '[:find ?v
|
|
46
|
+
:where
|
|
47
|
+
[_ :character/place-of-occupation ?v]]
|
|
48
|
+
(d/db conn))))
|
|
49
|
+
(d/release conn)))
|
|
50
|
+
|
|
51
|
+
(defn tx-data-and-tx-fn-test-fn [conn]
|
|
52
|
+
(-> (for [[eid]
|
|
53
|
+
(d/q '[:find ?e
|
|
54
|
+
:where
|
|
55
|
+
[?e :character/name]
|
|
56
|
+
(or-join [?e]
|
|
57
|
+
[?e :character/name "Homer Simpson"]
|
|
58
|
+
[?e :character/name "Marge Simpson"])]
|
|
59
|
+
(d/db conn))]
|
|
60
|
+
{:db/id eid
|
|
61
|
+
:character/children [[:character/name "Bart Simpson"]
|
|
62
|
+
[:character/name "Lisa Simpson"]
|
|
63
|
+
[:character/name "Maggie Simpson"]]})
|
|
64
|
+
vec))
|
|
65
|
+
|
|
66
|
+
(deftest tx-data-and-tx-fn-test
|
|
67
|
+
(let [conn (tu/setup-db {} true)
|
|
68
|
+
_ (verify-checksums (io/file "test/datahike/norm/resources/tx-data-and-tx-fn-test/first"))
|
|
69
|
+
_ (ensure-norms conn (io/file "test/datahike/norm/resources/tx-data-and-tx-fn-test/first"))
|
|
70
|
+
_ (d/transact conn {:tx-data [{:character/name "Homer Simpson"}
|
|
71
|
+
{:character/name "Marge Simpson"}
|
|
72
|
+
{:character/name "Bart Simpson"}
|
|
73
|
+
{:character/name "Lisa Simpson"}
|
|
74
|
+
{:character/name "Maggie Simpson"}]})
|
|
75
|
+
_ (verify-checksums (io/file "test/datahike/norm/resources/tx-data-and-tx-fn-test/second"))
|
|
76
|
+
_ (ensure-norms conn (io/file "test/datahike/norm/resources/tx-data-and-tx-fn-test/second"))
|
|
77
|
+
margehomer (d/q '[:find [?e ...]
|
|
78
|
+
:where
|
|
79
|
+
[?e :character/name]
|
|
80
|
+
(or-join [?e]
|
|
81
|
+
[?e :character/name "Homer Simpson"]
|
|
82
|
+
[?e :character/name "Marge Simpson"])]
|
|
83
|
+
(d/db conn))]
|
|
84
|
+
(is (= [#:character{:name "Homer Simpson",
|
|
85
|
+
:children
|
|
86
|
+
[#:character{:name "Bart Simpson"}
|
|
87
|
+
#:character{:name "Lisa Simpson"}
|
|
88
|
+
#:character{:name "Maggie Simpson"}]}
|
|
89
|
+
#:character{:name "Marge Simpson",
|
|
90
|
+
:children
|
|
91
|
+
[#:character{:name "Bart Simpson"}
|
|
92
|
+
#:character{:name "Lisa Simpson"}
|
|
93
|
+
#:character{:name "Maggie Simpson"}]}]
|
|
94
|
+
(d/pull-many (d/db conn) '[:character/name {:character/children [:character/name]}] margehomer)))
|
|
95
|
+
(d/release conn)))
|
|
96
|
+
|
|
97
|
+
(defn naming-and-sorting-test-fn [conn]
|
|
98
|
+
(-> (for [[eid] (d/q '[:find ?e
|
|
99
|
+
:where
|
|
100
|
+
[?e :character/name]
|
|
101
|
+
(or-join [?e]
|
|
102
|
+
[?e :character/name "Bart Simpson"]
|
|
103
|
+
[?e :character/name "Lisa Simpson"])]
|
|
104
|
+
(d/db conn))]
|
|
105
|
+
{:db/id eid
|
|
106
|
+
:character/occupation :student})
|
|
107
|
+
vec))
|
|
108
|
+
|
|
109
|
+
(deftest naming-and-sorting-test
|
|
110
|
+
(let [conn (tu/setup-db {} true)
|
|
111
|
+
_ (verify-checksums (io/file "test/datahike/norm/resources/naming-and-sorting-test"))
|
|
112
|
+
_ (sut/ensure-norms! conn (io/file "test/datahike/norm/resources/naming-and-sorting-test"))
|
|
113
|
+
lisabart (d/q '[:find [?e ...]
|
|
114
|
+
:where
|
|
115
|
+
[?e :character/occupation :student]]
|
|
116
|
+
(d/db conn))]
|
|
117
|
+
(is (= [{:db/id 10,
|
|
118
|
+
:character/name "Bart Simpson",
|
|
119
|
+
:character/occupation :student}
|
|
120
|
+
{:db/id 11,
|
|
121
|
+
:character/name "Lisa Simpson",
|
|
122
|
+
:character/occupation :student}]
|
|
123
|
+
(d/pull-many (d/db conn) '[*] lisabart)))
|
|
124
|
+
(d/release conn)))
|