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,469 @@
|
|
|
1
|
+
(ns ^:no-doc datahike.index.persistent-set
|
|
2
|
+
(:require [clojure.string]
|
|
3
|
+
[org.replikativ.persistent-sorted-set :as psset]
|
|
4
|
+
#?(:cljs [org.replikativ.persistent-sorted-set.btset :refer [BTSet]])
|
|
5
|
+
#?(:cljs [org.replikativ.persistent-sorted-set.branch :refer [Branch]])
|
|
6
|
+
#?(:cljs [org.replikativ.persistent-sorted-set.leaf :refer [Leaf]])
|
|
7
|
+
#?(:cljs [org.replikativ.persistent-sorted-set.impl.storage :refer [IStorage]])
|
|
8
|
+
[org.replikativ.persistent-sorted-set.arrays :as arrays]
|
|
9
|
+
#?@(:clj [[clojure.core.cache :as cache]
|
|
10
|
+
[clojure.core.cache.wrapped :as wrapped]]
|
|
11
|
+
:cljs [[cljs.cache :as cache]
|
|
12
|
+
[cljs.cache.wrapped :as wrapped]])
|
|
13
|
+
[datahike.datom :as dd :refer [index-type->cmp-quick]]
|
|
14
|
+
[datahike.constants :refer [tx0 txmax]]
|
|
15
|
+
[datahike.index.interface :as di :refer [IIndex]]
|
|
16
|
+
[datahike.tools :as dt]
|
|
17
|
+
[konserve.core :as k]
|
|
18
|
+
[konserve.serializers :refer [fressian-serializer]]
|
|
19
|
+
#?(:cljs [fress.api :as fress])
|
|
20
|
+
[hasch.core :refer [uuid squuid]]
|
|
21
|
+
[taoensso.timbre :refer [trace]])
|
|
22
|
+
#?(:cljs (:require-macros [datahike.index.persistent-set :refer [generate-slice-comparator-constructor]]))
|
|
23
|
+
#?(:clj (:import [datahike.datom Datom]
|
|
24
|
+
[org.fressian.handlers WriteHandler ReadHandler]
|
|
25
|
+
[org.replikativ.persistent_sorted_set PersistentSortedSet IStorage Leaf Branch ANode Settings]
|
|
26
|
+
[java.util List])))
|
|
27
|
+
|
|
28
|
+
(def index-type->kwseq
|
|
29
|
+
{:eavt [:e :a :v :tx :added]
|
|
30
|
+
:aevt [:a :e :v :tx :added]
|
|
31
|
+
:avet [:a :v :e :tx :added]})
|
|
32
|
+
|
|
33
|
+
(defn slice-from-to-tree
|
|
34
|
+
"This function generates code for deciding which datom elements that need to be compared based on which elements in the slice bounds are nil, as well as the index. Once all datom elements have been considered, `leaf-fn` is called with a vector containing the keywords of the actual elements to compare."
|
|
35
|
+
[from-sym to-sym index-spec acc leaf-fn]
|
|
36
|
+
(if (empty? index-spec)
|
|
37
|
+
|
|
38
|
+
;; When there is nothing left to compare,
|
|
39
|
+
;; return the correct comparator.
|
|
40
|
+
(leaf-fn acc)
|
|
41
|
+
|
|
42
|
+
(let [[findex & index-spec] index-spec]
|
|
43
|
+
`(if (and (nil? (~findex ~from-sym))
|
|
44
|
+
(nil? (~findex ~to-sym)))
|
|
45
|
+
|
|
46
|
+
;; Whenever both slice bounds are nil, there is nothing more to compare
|
|
47
|
+
;; and we know what comparator to return.
|
|
48
|
+
~(leaf-fn acc)
|
|
49
|
+
|
|
50
|
+
;; Otherwise, if at least one slie bound is non-nil, we need a comparator for
|
|
51
|
+
;; the remaining datom elements.
|
|
52
|
+
~(slice-from-to-tree from-sym to-sym index-spec (conj acc findex) leaf-fn)))))
|
|
53
|
+
|
|
54
|
+
(defn cmp-for-kwseq-sub
|
|
55
|
+
"This function generates the actual body of the comparator"
|
|
56
|
+
[datom0 datom1 kwseq]
|
|
57
|
+
(let [result (gensym)]
|
|
58
|
+
(if (empty? kwseq)
|
|
59
|
+
0
|
|
60
|
+
(let [[k & kwseq] kwseq]
|
|
61
|
+
`(let [;; Compare the datoms at the element with key `k`
|
|
62
|
+
~result ~(dd/cmp-val-expr k datom0 datom1)]
|
|
63
|
+
(cond
|
|
64
|
+
;; If it is nil, typically return 0
|
|
65
|
+
(nil? ~result) 0
|
|
66
|
+
|
|
67
|
+
;; If it is zero, we need to proceed with the next datom element to compare.
|
|
68
|
+
(zero? ~result) ~(cmp-for-kwseq-sub datom0 datom1 kwseq)
|
|
69
|
+
|
|
70
|
+
;; If it is non-zero, it means that this is the result of the comparison.
|
|
71
|
+
:else ~result))))))
|
|
72
|
+
|
|
73
|
+
(defn cmp-for-kwseq
|
|
74
|
+
"Given a sequence of keywords for datom elements to compare, generate the code for a function that performs the comparison."
|
|
75
|
+
[kwseq]
|
|
76
|
+
(let [datom0 (dd/type-hint-datom (gensym))
|
|
77
|
+
datom1 (dd/type-hint-datom (gensym))]
|
|
78
|
+
`(fn [~datom0 ~datom1] ~(cmp-for-kwseq-sub datom0 datom1 kwseq))))
|
|
79
|
+
|
|
80
|
+
(defmacro generate-slice-comparator-constructor []
|
|
81
|
+
(let [index-sym (gensym)
|
|
82
|
+
from-sym (gensym)
|
|
83
|
+
to-sym (gensym)
|
|
84
|
+
|
|
85
|
+
;; List keyword sequences referring to datom elements for
|
|
86
|
+
;; all combinations of indexes and leftmost slices of the
|
|
87
|
+
;; corresponding datom elements.
|
|
88
|
+
all-kwseqs (set (for [[_ kwseq] index-type->kwseq
|
|
89
|
+
limit (range 6)]
|
|
90
|
+
(vec (take limit kwseq))))
|
|
91
|
+
kwseq-sym-map (zipmap all-kwseqs (repeatedly gensym))]
|
|
92
|
+
`(let [;; Pre-build comparators for every sequence
|
|
93
|
+
;; of keywords referring to datom elements.
|
|
94
|
+
;; A comparator is a function taking two datoms
|
|
95
|
+
;; as arguments.
|
|
96
|
+
~@(mapcat (fn [[kwseq sym]]
|
|
97
|
+
[sym (cmp-for-kwseq kwseq)])
|
|
98
|
+
kwseq-sym-map)]
|
|
99
|
+
|
|
100
|
+
;; This is the function generated by this macro
|
|
101
|
+
;; and it is called by the `-slice` method.
|
|
102
|
+
(fn [~index-sym ~from-sym ~to-sym]
|
|
103
|
+
|
|
104
|
+
;; First branch based on which index to use ...
|
|
105
|
+
(case ~index-sym
|
|
106
|
+
~@(mapcat
|
|
107
|
+
(fn [[index-key index-spec]]
|
|
108
|
+
[index-key
|
|
109
|
+
|
|
110
|
+
;; ... then branch based on what elements
|
|
111
|
+
;; are non-nil in the slice bound datoms ...
|
|
112
|
+
(slice-from-to-tree
|
|
113
|
+
from-sym to-sym
|
|
114
|
+
index-spec
|
|
115
|
+
[]
|
|
116
|
+
|
|
117
|
+
(fn [acc]
|
|
118
|
+
{:post [(symbol? %)]}
|
|
119
|
+
|
|
120
|
+
;; ... and eventually return a precomputed comparator
|
|
121
|
+
;; that will be used by `psset/slice`. The generated
|
|
122
|
+
;; code is the symbol that is bound to a comparator.
|
|
123
|
+
(get kwseq-sym-map acc)))])
|
|
124
|
+
index-type->kwseq))))))
|
|
125
|
+
|
|
126
|
+
(def slice-comparator-constructor (generate-slice-comparator-constructor))
|
|
127
|
+
|
|
128
|
+
(defn remove-datom [pset ^Datom datom index-type]
|
|
129
|
+
(psset/disj pset datom (index-type->cmp-quick index-type false)))
|
|
130
|
+
|
|
131
|
+
(defn insert [pset ^Datom datom index-type]
|
|
132
|
+
;; Use lookup with prefix comparator - O(log n) with zero allocations
|
|
133
|
+
;; Prefix comparator checks only (e,a,v) to find if ANY datom exists with same triple
|
|
134
|
+
(if #?(:clj (.lookup ^PersistentSortedSet pset datom (dd/index-type->cmp-prefix index-type))
|
|
135
|
+
:cljs (psset/lookup pset datom (dd/index-type->cmp-prefix index-type)))
|
|
136
|
+
pset
|
|
137
|
+
(psset/conj pset datom (index-type->cmp-quick index-type))))
|
|
138
|
+
|
|
139
|
+
(defn temporal-insert [pset ^Datom datom index-type]
|
|
140
|
+
(psset/conj pset datom (index-type->cmp-quick index-type false)))
|
|
141
|
+
|
|
142
|
+
(defn upsert [pset ^Datom datom index-type old-datom]
|
|
143
|
+
(if old-datom
|
|
144
|
+
(if (= index-type :avet)
|
|
145
|
+
(-> pset
|
|
146
|
+
(psset/disj old-datom (index-type->cmp-quick index-type))
|
|
147
|
+
(psset/conj datom (index-type->cmp-quick index-type)))
|
|
148
|
+
#?(:clj (.replace ^PersistentSortedSet pset old-datom datom (dd/index-type->cmp-replace index-type))
|
|
149
|
+
:cljs (psset/replace pset old-datom datom (dd/index-type->cmp-replace index-type))))
|
|
150
|
+
(psset/conj pset datom (index-type->cmp-quick index-type))))
|
|
151
|
+
|
|
152
|
+
(defn temporal-upsert [pset ^Datom datom index-type {old-val :v}]
|
|
153
|
+
(let [{:keys [e a v tx added]} datom]
|
|
154
|
+
(if added
|
|
155
|
+
(if old-val
|
|
156
|
+
(if (= v old-val)
|
|
157
|
+
pset
|
|
158
|
+
(-> pset
|
|
159
|
+
(psset/conj (dd/datom e a old-val tx false)
|
|
160
|
+
(index-type->cmp-quick index-type false))
|
|
161
|
+
(psset/conj datom
|
|
162
|
+
(index-type->cmp-quick index-type false))))
|
|
163
|
+
(psset/conj pset datom (index-type->cmp-quick index-type false)))
|
|
164
|
+
(if old-val
|
|
165
|
+
(psset/conj pset
|
|
166
|
+
(dd/datom e a old-val tx false)
|
|
167
|
+
(index-type->cmp-quick index-type false))
|
|
168
|
+
pset))))
|
|
169
|
+
|
|
170
|
+
(defn mark [^PersistentSortedSet pset]
|
|
171
|
+
(when-not (.-_address pset)
|
|
172
|
+
(throw (ex-info "Index needs to be properly flushed before marking."
|
|
173
|
+
{:type :flush-before-marking})))
|
|
174
|
+
(let [addresses (atom #{})]
|
|
175
|
+
(psset/walk-addresses pset (fn [address] (swap! addresses conj address)))
|
|
176
|
+
@addresses))
|
|
177
|
+
|
|
178
|
+
(extend-type #?(:clj PersistentSortedSet :cljs BTSet)
|
|
179
|
+
IIndex
|
|
180
|
+
(-slice [^PersistentSortedSet pset from to index-type]
|
|
181
|
+
(psset/slice pset from to (slice-comparator-constructor index-type from to)))
|
|
182
|
+
(-all [pset]
|
|
183
|
+
(identity pset))
|
|
184
|
+
(-seq [^PersistentSortedSet pset]
|
|
185
|
+
(seq pset))
|
|
186
|
+
(-count [^PersistentSortedSet pset]
|
|
187
|
+
(count pset))
|
|
188
|
+
(-insert [^PersistentSortedSet pset datom index-type _op-count]
|
|
189
|
+
(insert pset datom index-type))
|
|
190
|
+
(-temporal-insert [^PersistentSortedSet pset datom index-type _op-count]
|
|
191
|
+
(psset/conj pset datom (index-type->cmp-quick index-type)))
|
|
192
|
+
(-upsert [^PersistentSortedSet pset datom index-type _op-count old-datom]
|
|
193
|
+
(upsert pset datom index-type old-datom))
|
|
194
|
+
(-temporal-upsert [^PersistentSortedSet pset datom index-type _op-count old-val]
|
|
195
|
+
(temporal-upsert pset datom index-type old-val))
|
|
196
|
+
(-remove [^PersistentSortedSet pset datom index-type _op-count]
|
|
197
|
+
(remove-datom pset datom index-type))
|
|
198
|
+
(-flush [^PersistentSortedSet pset _]
|
|
199
|
+
(psset/store pset)
|
|
200
|
+
pset)
|
|
201
|
+
(-transient [^PersistentSortedSet pset]
|
|
202
|
+
(transient pset))
|
|
203
|
+
(-persistent! [^PersistentSortedSet pset]
|
|
204
|
+
(persistent! pset))
|
|
205
|
+
(-mark [^PersistentSortedSet pset]
|
|
206
|
+
(mark pset)))
|
|
207
|
+
|
|
208
|
+
(defn- gen-address [^ANode node crypto-hash?]
|
|
209
|
+
(if crypto-hash?
|
|
210
|
+
(if (instance? Branch node)
|
|
211
|
+
(uuid (vec (.addresses ^Branch node)))
|
|
212
|
+
(uuid (mapv (comp vec seq) (.keys node))))
|
|
213
|
+
(squuid))) ;; Sequential UUID for better index locality
|
|
214
|
+
|
|
215
|
+
(defn- freelist-pop!
|
|
216
|
+
"Atomically pop an address from the freelist. Returns nil if empty."
|
|
217
|
+
[freelist-atom]
|
|
218
|
+
(loop []
|
|
219
|
+
(let [current @freelist-atom]
|
|
220
|
+
(if (empty? current)
|
|
221
|
+
nil
|
|
222
|
+
(let [addr (peek current)
|
|
223
|
+
new-list (pop current)]
|
|
224
|
+
(if (compare-and-set! freelist-atom current new-list)
|
|
225
|
+
addr
|
|
226
|
+
(recur)))))))
|
|
227
|
+
|
|
228
|
+
(defrecord CachedStorage [store config cache stats pending-writes freed-addresses freed-set freelist cost-center-fn]
|
|
229
|
+
IStorage
|
|
230
|
+
(store [_ node #?(:cljs opts)]
|
|
231
|
+
(@cost-center-fn :store)
|
|
232
|
+
(swap! stats update :writes inc)
|
|
233
|
+
(let [;; Only reuse addresses when not using crypto-hash (content-addressed storage
|
|
234
|
+
;; requires the address to match the content)
|
|
235
|
+
reused (when-not (:crypto-hash? config)
|
|
236
|
+
(freelist-pop! freelist))
|
|
237
|
+
address (or reused (gen-address node (:crypto-hash? config)))
|
|
238
|
+
_ (trace "writing storage: " address " reused: " (boolean reused) " crypto: " (:crypto-hash? config))]
|
|
239
|
+
;; Evict old cached value when reusing an address
|
|
240
|
+
(when reused
|
|
241
|
+
(wrapped/evict cache address))
|
|
242
|
+
(swap! pending-writes conj [address node])
|
|
243
|
+
(wrapped/miss cache address node)
|
|
244
|
+
address))
|
|
245
|
+
(accessed [_ address]
|
|
246
|
+
(@cost-center-fn :accessed)
|
|
247
|
+
(trace "accessing storage: " address)
|
|
248
|
+
(swap! stats update :accessed inc)
|
|
249
|
+
(wrapped/hit cache address)
|
|
250
|
+
nil)
|
|
251
|
+
(restore [_ address #?(:cljs opts)]
|
|
252
|
+
(@cost-center-fn :restore)
|
|
253
|
+
(trace "reading: " address)
|
|
254
|
+
(if-let [cached (wrapped/lookup cache address)]
|
|
255
|
+
cached
|
|
256
|
+
(let [node (k/get store address nil {:sync? true})]
|
|
257
|
+
(when (nil? node)
|
|
258
|
+
(dt/raise "Node not found in storage." {:type :node-not-found
|
|
259
|
+
:address address
|
|
260
|
+
:store store}))
|
|
261
|
+
(swap! stats update :reads inc)
|
|
262
|
+
(wrapped/miss cache address node)
|
|
263
|
+
node)))
|
|
264
|
+
(markFreed [_ address]
|
|
265
|
+
(when address
|
|
266
|
+
(let [now #?(:clj (java.util.Date.) :cljs (js/Date.))]
|
|
267
|
+
(trace "marking address as freed: " address)
|
|
268
|
+
(swap! freed-set conj address)
|
|
269
|
+
(swap! freed-addresses conj [address now]))))
|
|
270
|
+
(isFreed [_ address]
|
|
271
|
+
(contains? @freed-set address))
|
|
272
|
+
(freedInfo [_ address]
|
|
273
|
+
(when (contains? @freed-set address)
|
|
274
|
+
"Address has been marked as freed")))
|
|
275
|
+
|
|
276
|
+
(def init-stats {:writes 0
|
|
277
|
+
:reads 0
|
|
278
|
+
:accessed 0})
|
|
279
|
+
|
|
280
|
+
(defn create-storage [store config]
|
|
281
|
+
(CachedStorage. store config
|
|
282
|
+
(atom (cache/lru-cache-factory {} :threshold (:store-cache-size config)))
|
|
283
|
+
(atom init-stats)
|
|
284
|
+
(atom [])
|
|
285
|
+
(atom []) ;; freed-addresses: vector of [address timestamp] pairs
|
|
286
|
+
(atom #{}) ;; freed-set: HashSet for O(1) isFreed lookups
|
|
287
|
+
(atom []) ;; freelist: vector of reusable addresses (used as stack via peek/pop)
|
|
288
|
+
(atom (fn [_] nil))))
|
|
289
|
+
|
|
290
|
+
(def ^:const DEFAULT_BRANCHING_FACTOR 512)
|
|
291
|
+
|
|
292
|
+
(defmethod di/empty-index :datahike.index/persistent-set [_index-name store index-type _]
|
|
293
|
+
(let [^PersistentSortedSet pset (psset/sorted-set* {:cmp (index-type->cmp-quick index-type false)
|
|
294
|
+
:storage (:storage store)
|
|
295
|
+
:branching-factor DEFAULT_BRANCHING_FACTOR})]
|
|
296
|
+
(with-meta pset
|
|
297
|
+
{:index-type index-type})))
|
|
298
|
+
|
|
299
|
+
(defmethod di/init-index :datahike.index/persistent-set [_index-name store datoms index-type _ {:keys [indexed]}]
|
|
300
|
+
(let [arr (if (= index-type :avet)
|
|
301
|
+
(->> datoms
|
|
302
|
+
(filter #(contains? indexed (.-a ^Datom %)))
|
|
303
|
+
to-array)
|
|
304
|
+
(cond-> datoms
|
|
305
|
+
(not (arrays/array? datoms))
|
|
306
|
+
(arrays/into-array)))
|
|
307
|
+
_ (arrays/asort arr (index-type->cmp-quick index-type false))
|
|
308
|
+
^PersistentSortedSet pset (psset/from-sorted-array (index-type->cmp-quick index-type false)
|
|
309
|
+
arr
|
|
310
|
+
(arrays/alength arr)
|
|
311
|
+
{:branching-factor DEFAULT_BRANCHING_FACTOR})]
|
|
312
|
+
(set! (.-_storage pset) (:storage store))
|
|
313
|
+
(with-meta pset
|
|
314
|
+
{:index-type index-type})))
|
|
315
|
+
|
|
316
|
+
;; temporary import from psset until public
|
|
317
|
+
(defn- map->settings ^Settings [m]
|
|
318
|
+
#?(:cljs m
|
|
319
|
+
:clj (Settings.
|
|
320
|
+
(int (or (:branching-factor m) 0))
|
|
321
|
+
nil ;; weak ref default
|
|
322
|
+
)))
|
|
323
|
+
|
|
324
|
+
(defmethod di/add-konserve-handlers :datahike.index/persistent-set [config store]
|
|
325
|
+
;; Check if store has pre-configured handlers (e.g., LMDB with buffer encoder).
|
|
326
|
+
;; If so, the store will have :storage-atom that handlers close over.
|
|
327
|
+
(if-let [storage-atom (:storage-atom store)]
|
|
328
|
+
;; Non-fressian store - handlers already configured, just create storage
|
|
329
|
+
(let [storage (or (:storage store)
|
|
330
|
+
(create-storage store config))]
|
|
331
|
+
(reset! storage-atom storage)
|
|
332
|
+
(assoc store :storage storage))
|
|
333
|
+
|
|
334
|
+
;; Standard fressian store - set up serializers
|
|
335
|
+
;; deal with circular reference between storage and store
|
|
336
|
+
(let [settings (map->settings {:branching-factor DEFAULT_BRANCHING_FACTOR})
|
|
337
|
+
storage (atom nil)
|
|
338
|
+
store
|
|
339
|
+
(k/assoc-serializers
|
|
340
|
+
store
|
|
341
|
+
{:FressianSerializer (fressian-serializer
|
|
342
|
+
|
|
343
|
+
;; read handlers
|
|
344
|
+
{"datahike.index.PersistentSortedSet"
|
|
345
|
+
#?(:clj
|
|
346
|
+
(reify ReadHandler
|
|
347
|
+
(read [_ reader _tag _component-count]
|
|
348
|
+
(let [{:keys [meta address count]} (.readObject reader)
|
|
349
|
+
cmp (index-type->cmp-quick (:index-type meta) false)]
|
|
350
|
+
;; The following fields are reset as they cannot be accessed from outside:
|
|
351
|
+
;; - 'edit' is set to false, i.e. the set is assumed to be persistent, not transient
|
|
352
|
+
;; - 'version' is set back to 0
|
|
353
|
+
(PersistentSortedSet. meta cmp address @storage nil count settings 0))))
|
|
354
|
+
:cljs
|
|
355
|
+
(fn [reader _tag _component-count]
|
|
356
|
+
(let [{:keys [meta address count]} (fress/read-object reader)
|
|
357
|
+
cmp (index-type->cmp-quick (:index-type meta) false)]
|
|
358
|
+
;; CLJS BTSet deftype: [root cnt comparator meta _hash storage address settings]
|
|
359
|
+
(BTSet. nil count cmp meta nil @storage address settings))))
|
|
360
|
+
"datahike.index.PersistentSortedSet.Leaf"
|
|
361
|
+
#?(:clj
|
|
362
|
+
(reify ReadHandler
|
|
363
|
+
(read [_ reader _tag _component-count]
|
|
364
|
+
(let [{:keys [keys _level]} (.readObject reader)]
|
|
365
|
+
(Leaf. ^List keys settings))))
|
|
366
|
+
:cljs
|
|
367
|
+
(fn [reader _tag _component-count]
|
|
368
|
+
(let [{:keys [keys _level]} (fress/read-object reader)]
|
|
369
|
+
;; CLJS Leaf deftype: [keys settings _measure]
|
|
370
|
+
(Leaf. (clj->js keys) settings nil))))
|
|
371
|
+
"datahike.index.PersistentSortedSet.Branch"
|
|
372
|
+
#?(:clj
|
|
373
|
+
(reify ReadHandler
|
|
374
|
+
(read [_ reader _tag _component-count]
|
|
375
|
+
(let [{:keys [keys level addresses subtree-count]} (.readObject reader)]
|
|
376
|
+
(Branch. (int level) (count keys) (into-array Object keys) (into-array Object (seq addresses)) nil (long (or subtree-count -1)) settings))))
|
|
377
|
+
:cljs
|
|
378
|
+
(fn [reader _tag _component-count]
|
|
379
|
+
(let [{:keys [keys level addresses subtree-count]} (fress/read-object reader)]
|
|
380
|
+
;; CLJS Branch deftype: [level keys children addresses subtree-count _measure settings]
|
|
381
|
+
(Branch. (int level) (clj->js keys) nil (clj->js addresses) (or subtree-count -1) nil settings))))
|
|
382
|
+
"datahike.datom.Datom"
|
|
383
|
+
#?(:clj
|
|
384
|
+
(reify ReadHandler
|
|
385
|
+
(read [_ reader _tag _component-count]
|
|
386
|
+
(dd/datom-from-reader (.readObject reader))))
|
|
387
|
+
:cljs
|
|
388
|
+
(fn [reader _tag _component-count]
|
|
389
|
+
(dd/datom-from-reader (fress/read-object reader))))}
|
|
390
|
+
|
|
391
|
+
;; write handlers
|
|
392
|
+
;; CLJ format: nested {Type {"tag" handler}} for clojure.data.fressian
|
|
393
|
+
;; CLJS format: flat {Type handler-fn} for fress library
|
|
394
|
+
#?(:clj
|
|
395
|
+
{org.replikativ.persistent_sorted_set.PersistentSortedSet
|
|
396
|
+
{"datahike.index.PersistentSortedSet"
|
|
397
|
+
(reify WriteHandler
|
|
398
|
+
(write [_ writer pset]
|
|
399
|
+
(when (nil? (.-_address ^PersistentSortedSet pset))
|
|
400
|
+
(dt/raise "Must be flushed." {:type :must-be-flushed
|
|
401
|
+
:pset pset}))
|
|
402
|
+
(.writeTag writer "datahike.index.PersistentSortedSet" 1)
|
|
403
|
+
(.writeObject writer {:meta (meta pset)
|
|
404
|
+
:address (.-_address ^PersistentSortedSet pset)
|
|
405
|
+
:count (count pset)})))}
|
|
406
|
+
|
|
407
|
+
org.replikativ.persistent_sorted_set.Leaf
|
|
408
|
+
{"datahike.index.PersistentSortedSet.Leaf"
|
|
409
|
+
(reify WriteHandler
|
|
410
|
+
(write [_ writer leaf]
|
|
411
|
+
(.writeTag writer "datahike.index.PersistentSortedSet.Leaf" 1)
|
|
412
|
+
(.writeObject writer {:level (.level ^Leaf leaf)
|
|
413
|
+
:keys (.keys ^Leaf leaf)})))}
|
|
414
|
+
|
|
415
|
+
org.replikativ.persistent_sorted_set.Branch
|
|
416
|
+
{"datahike.index.PersistentSortedSet.Branch"
|
|
417
|
+
(reify WriteHandler
|
|
418
|
+
(write [_ writer node]
|
|
419
|
+
(.writeTag writer "datahike.index.PersistentSortedSet.Branch" 1)
|
|
420
|
+
(.writeObject writer {:level (.level ^Branch node)
|
|
421
|
+
:keys (.keys ^Branch node)
|
|
422
|
+
:addresses (.addresses ^Branch node)
|
|
423
|
+
:subtree-count (.subtreeCount ^Branch node)})))}
|
|
424
|
+
|
|
425
|
+
datahike.datom.Datom
|
|
426
|
+
{"datahike.datom.Datom"
|
|
427
|
+
(reify WriteHandler
|
|
428
|
+
(write [_ writer datom]
|
|
429
|
+
(.writeTag writer "datahike.datom.Datom" 1)
|
|
430
|
+
(.writeObject writer (vec (seq ^Datom datom)))))}}
|
|
431
|
+
|
|
432
|
+
:cljs
|
|
433
|
+
{BTSet
|
|
434
|
+
(fn [writer pset]
|
|
435
|
+
(when (nil? (.-address ^BTSet pset))
|
|
436
|
+
(dt/raise "Must be flushed." {:type :must-be-flushed
|
|
437
|
+
:pset pset}))
|
|
438
|
+
(fress/write-tag writer "datahike.index.PersistentSortedSet" 1)
|
|
439
|
+
(fress/write-object writer {:meta (meta pset)
|
|
440
|
+
:address (.-address ^BTSet pset)
|
|
441
|
+
:count (count pset)}))
|
|
442
|
+
|
|
443
|
+
Leaf
|
|
444
|
+
(fn [writer leaf]
|
|
445
|
+
(fress/write-tag writer "datahike.index.PersistentSortedSet.Leaf" 1)
|
|
446
|
+
(fress/write-object writer {:level 0 ;; not supported in cljs
|
|
447
|
+
:keys (vec (.-keys ^Leaf leaf))}))
|
|
448
|
+
|
|
449
|
+
Branch
|
|
450
|
+
(fn [writer node]
|
|
451
|
+
(fress/write-tag writer "datahike.index.PersistentSortedSet.Branch" 1)
|
|
452
|
+
(fress/write-object writer {:level (.-level ^Branch node)
|
|
453
|
+
:keys (vec (.-keys ^Branch node))
|
|
454
|
+
:addresses (vec (.-addresses ^Branch node))
|
|
455
|
+
:subtree-count (.-subtree-count ^Branch node)}))
|
|
456
|
+
|
|
457
|
+
datahike.datom.Datom
|
|
458
|
+
(fn [writer datom]
|
|
459
|
+
(fress/write-tag writer "datahike.datom.Datom" 1)
|
|
460
|
+
(fress/write-object writer (vec (seq ^Datom datom))))}))})]
|
|
461
|
+
(reset! storage (or (:storage store)
|
|
462
|
+
(create-storage store config)))
|
|
463
|
+
(assoc store :storage @storage))))
|
|
464
|
+
|
|
465
|
+
(defmethod di/konserve-backend :datahike.index/persistent-set [_index-name store]
|
|
466
|
+
store)
|
|
467
|
+
|
|
468
|
+
(defmethod di/default-index-config :datahike.index/persistent-set [_index-name]
|
|
469
|
+
{})
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
(ns datahike.index.utils
|
|
2
|
+
(:require [datahike.constants :refer [e0 tx0 emax txmax]]
|
|
3
|
+
[datahike.datom :as dd])
|
|
4
|
+
#?(:clj (:import [datahike.datom Datom])))
|
|
5
|
+
|
|
6
|
+
(defn datom-to-vec [^Datom datom index-type start?]
|
|
7
|
+
(let [e (fn [^Datom datom] (when-not (or (and start? (= e0 (.-e datom)))
|
|
8
|
+
(and (not start?) (= emax (.-e datom))))
|
|
9
|
+
(.-e datom)))
|
|
10
|
+
tx (fn [^Datom datom] (when-not (or (and start? (= tx0 (.-tx datom)))
|
|
11
|
+
(and (not start?) (= txmax (.-tx datom))))
|
|
12
|
+
(.-tx datom)))
|
|
13
|
+
datom-seq (case index-type
|
|
14
|
+
:aevt (list (.-a datom) (e datom) (.-v datom) (tx datom))
|
|
15
|
+
:avet (list (.-a datom) (.-v datom) (e datom) (tx datom))
|
|
16
|
+
(list (e datom) (.-a datom) (.-v datom) (tx datom)))]
|
|
17
|
+
(->> datom-seq
|
|
18
|
+
(take-while some?)
|
|
19
|
+
vec)))
|
|
20
|
+
|
|
21
|
+
(defn- slice-datom-compare [cmp]
|
|
22
|
+
(fn [v1 v2] (-> (filter #(not (= % 0)) (map cmp v1 v2))
|
|
23
|
+
first
|
|
24
|
+
(or 0))))
|
|
25
|
+
|
|
26
|
+
(defn prefix-scan [cmp [e f g h]]
|
|
27
|
+
(let [datom-vec-compare (slice-datom-compare cmp)]
|
|
28
|
+
(fn [[i j k l]]
|
|
29
|
+
(< (cond (and e f g h) (datom-vec-compare [i j k l] [e f g h])
|
|
30
|
+
(and e f g) (datom-vec-compare [i j k] [e f g])
|
|
31
|
+
(and e f) (datom-vec-compare [i j] [e f])
|
|
32
|
+
e (cmp i e)
|
|
33
|
+
:else 0)
|
|
34
|
+
1))))
|
|
35
|
+
|
|
36
|
+
(defn equals-on-indices?
|
|
37
|
+
"Returns true if 'k1' and 'k2' have the same value at positions indicated by 'indices'"
|
|
38
|
+
[k1, k2, indices]
|
|
39
|
+
(reduce (fn [_ i]
|
|
40
|
+
(if (= (nth k1 i) (nth k2 i))
|
|
41
|
+
true
|
|
42
|
+
(reduced false)))
|
|
43
|
+
true
|
|
44
|
+
indices))
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
(ns ^:no-doc datahike.index
|
|
2
|
+
(:refer-clojure :exclude [-persistent! -flush -count -seq])
|
|
3
|
+
(:require [datahike.index.interface :as di]
|
|
4
|
+
[datahike.index.persistent-set]))
|
|
5
|
+
|
|
6
|
+
;; Aliases for protocol functions
|
|
7
|
+
|
|
8
|
+
(def -all di/-all)
|
|
9
|
+
(def -seq di/-seq)
|
|
10
|
+
(def -count di/-count)
|
|
11
|
+
(def -insert di/-insert)
|
|
12
|
+
(def -temporal-insert di/-temporal-insert)
|
|
13
|
+
(def -upsert di/-upsert)
|
|
14
|
+
(def -temporal-upsert di/-temporal-upsert)
|
|
15
|
+
(def -remove di/-remove)
|
|
16
|
+
(def -slice di/-slice)
|
|
17
|
+
(def -flush di/-flush)
|
|
18
|
+
(def -transient di/-transient)
|
|
19
|
+
(def -persistent! di/-persistent!)
|
|
20
|
+
(def -mark di/-mark)
|
|
21
|
+
|
|
22
|
+
;; Aliases for multimethods
|
|
23
|
+
|
|
24
|
+
(def empty-index di/empty-index)
|
|
25
|
+
(def init-index di/init-index)
|
|
26
|
+
(def add-konserve-handlers di/add-konserve-handlers)
|
|
27
|
+
(def konserve-backend di/konserve-backend)
|
|
28
|
+
(def default-index-config di/default-index-config)
|
|
29
|
+
|
|
30
|
+
;; Other functions
|
|
31
|
+
|
|
32
|
+
(def index-types (keys (methods empty-index)))
|