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,88 @@
|
|
|
1
|
+
(ns datahike.query-stats
|
|
2
|
+
(:require [clojure.set :as set]
|
|
3
|
+
[datahike.tools :as dt]))
|
|
4
|
+
|
|
5
|
+
(defn round [precision x]
|
|
6
|
+
#?(:clj (with-precision ^long precision ^java.math.BigDecimal x)
|
|
7
|
+
:cljs (let [y (Math/pow 10 precision)]
|
|
8
|
+
(/ (.round js/Math (* y x)) y))))
|
|
9
|
+
|
|
10
|
+
(defn compatible-abs [^long n]
|
|
11
|
+
#?(:clj (Math/abs n)
|
|
12
|
+
:cljs (js/Math.abs n)))
|
|
13
|
+
|
|
14
|
+
(defn get-stats [context]
|
|
15
|
+
{:rels (mapv (fn [rel] {:rows (count (:tuples rel))
|
|
16
|
+
:bound (set (keys (:attrs rel)))})
|
|
17
|
+
(:rels context))})
|
|
18
|
+
|
|
19
|
+
(defn update-ctx-with-stats
|
|
20
|
+
"update-fn must expect [context] as argument"
|
|
21
|
+
[context clause update-fn]
|
|
22
|
+
(if (:stats context)
|
|
23
|
+
(let [{:keys [res t]} (dt/timed #(update-fn context))
|
|
24
|
+
clause-stats (merge (get-stats res)
|
|
25
|
+
{:clause clause
|
|
26
|
+
:t t}
|
|
27
|
+
(:tmp-stats res))]
|
|
28
|
+
(-> res
|
|
29
|
+
(update :stats conj clause-stats)
|
|
30
|
+
(dissoc :tmp-stats)))
|
|
31
|
+
(update-fn context)))
|
|
32
|
+
|
|
33
|
+
(defn extend-stat
|
|
34
|
+
"Adds summarized row counts, bindings and clause time for convenience"
|
|
35
|
+
[{:keys [branches rels] :as stat}]
|
|
36
|
+
(assoc stat
|
|
37
|
+
:id (subs (str (compatible-abs (hash stat))) 0 6)
|
|
38
|
+
:t-branches (reduce #(+ %1 (:t %2)) 0.0 branches)
|
|
39
|
+
:rel-count (count rels)
|
|
40
|
+
:rows (reduce #(+ %1 (:rows %2)) 0 rels)
|
|
41
|
+
:bound (reduce #(set/union %1 (:bound %2)) #{} rels)
|
|
42
|
+
:branches (mapv extend-stat branches)))
|
|
43
|
+
|
|
44
|
+
(defn get-stat-diffs [parent-node prev-node {:keys [t t-branches rows bound] :as node}]
|
|
45
|
+
(let [extend-and-branches (fn [branches]
|
|
46
|
+
(mapv (partial get-stat-diffs node)
|
|
47
|
+
(cons prev-node branches)
|
|
48
|
+
branches))
|
|
49
|
+
extend-or-branches (fn [branches]
|
|
50
|
+
(mapv (partial get-stat-diffs node prev-node) branches))]
|
|
51
|
+
(-> node
|
|
52
|
+
(dissoc :rows :bound)
|
|
53
|
+
(assoc :prev (:id prev-node)
|
|
54
|
+
:parent (:id parent-node)
|
|
55
|
+
:t-diff (round 6 (- t t-branches))
|
|
56
|
+
:rows-in (:rows prev-node)
|
|
57
|
+
:rows-out rows
|
|
58
|
+
:rows-diff (- rows (:rows prev-node))
|
|
59
|
+
:bound-in (:bound prev-node)
|
|
60
|
+
:bound-out bound
|
|
61
|
+
:bound-diff (set/difference bound (:bound prev-node)))
|
|
62
|
+
(update :branches (case (:type node)
|
|
63
|
+
:and extend-and-branches
|
|
64
|
+
:or extend-or-branches
|
|
65
|
+
:or-join extend-or-branches
|
|
66
|
+
:rule extend-or-branches
|
|
67
|
+
:solve extend-and-branches
|
|
68
|
+
identity)))))
|
|
69
|
+
|
|
70
|
+
(defn extend-stats [stats]
|
|
71
|
+
(let [extended (map extend-stat stats)
|
|
72
|
+
root {:rows 0 :bound (set []) :id "_root_"}]
|
|
73
|
+
(mapv (partial get-stat-diffs root)
|
|
74
|
+
(cons root extended)
|
|
75
|
+
extended)))
|
|
76
|
+
|
|
77
|
+
(defn stats-table
|
|
78
|
+
([stats]
|
|
79
|
+
(stats-table stats [:id :prev :parent :clause :type
|
|
80
|
+
:rows-in :rows-diff :bound-in :bound-diff
|
|
81
|
+
:t :t-diff :clauses]))
|
|
82
|
+
([stats cols]
|
|
83
|
+
(->> stats
|
|
84
|
+
extend-stats
|
|
85
|
+
(hash-map :branches)
|
|
86
|
+
(tree-seq map? :branches)
|
|
87
|
+
rest
|
|
88
|
+
(map (apply juxt cols)))))
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
(ns datahike.readers
|
|
2
|
+
(:require [datahike.connections :refer [get-connection *connections*]]
|
|
3
|
+
[datahike.writing :as dw]
|
|
4
|
+
[datahike.datom :refer [datom] :as dd]
|
|
5
|
+
#?(:cljs [datahike.db :refer [HistoricalDB AsOfDB SinceDB]])
|
|
6
|
+
[datahike.impl.entity :as de]
|
|
7
|
+
[datahike.core :refer [init-db] :as dc]
|
|
8
|
+
[datahike.tools :refer [raise]]
|
|
9
|
+
[konserve.core :as k])
|
|
10
|
+
#?(:clj
|
|
11
|
+
(:import [datahike.datom Datom]
|
|
12
|
+
[datahike.db HistoricalDB AsOfDB SinceDB])))
|
|
13
|
+
|
|
14
|
+
(def tempid dc/tempid)
|
|
15
|
+
|
|
16
|
+
(def datom-from-reader dd/datom-from-reader)
|
|
17
|
+
|
|
18
|
+
(defn db-from-reader [{:keys [schema datoms store-id commit-id] :as raw-db}]
|
|
19
|
+
(if (and store-id commit-id)
|
|
20
|
+
#?(:cljs (throw (ex-info "Reader not supported." {:type :reader-not-supported
|
|
21
|
+
:raw-db raw-db}))
|
|
22
|
+
:clj
|
|
23
|
+
(if-let [conn (get-connection store-id)]
|
|
24
|
+
(let [store (:store @conn)]
|
|
25
|
+
(when-let [raw-db (k/get store commit-id nil {:sync? true})]
|
|
26
|
+
(dw/stored->db raw-db store)))
|
|
27
|
+
(raise (ex-info "Could not find active connection. Did you connect already?"
|
|
28
|
+
{:type :no-connection-for-db
|
|
29
|
+
:raw-db raw-db}))))
|
|
30
|
+
(init-db (map (fn [[e a v tx]] (datom e a v tx)) datoms) schema)))
|
|
31
|
+
|
|
32
|
+
(defn history-from-reader [{:keys [origin]}]
|
|
33
|
+
(HistoricalDB. origin))
|
|
34
|
+
|
|
35
|
+
(defn since-from-reader [{:keys [origin time-point]}]
|
|
36
|
+
(AsOfDB. origin time-point))
|
|
37
|
+
|
|
38
|
+
(defn as-of-from-reader [{:keys [origin time-point]}]
|
|
39
|
+
(SinceDB. origin time-point))
|
|
40
|
+
|
|
41
|
+
(defn connection-from-reader [conn-id]
|
|
42
|
+
(:conn (@*connections* conn-id)))
|
|
43
|
+
|
|
44
|
+
(defn entity-from-reader [{:keys [db eid]}]
|
|
45
|
+
(de/entity db eid))
|
|
46
|
+
|
|
47
|
+
(def ^{:doc "Data readers for EDN readers. In CLJS they’re registered automatically. In CLJ, if `data_readers.clj` do not work, you can always do
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
(clojure.edn/read-string {:readers data-readers} \"...\")
|
|
51
|
+
```"}
|
|
52
|
+
edn-readers
|
|
53
|
+
{'datahike/Datom datahike.readers/datom-from-reader
|
|
54
|
+
'datahike/DB datahike.readers/db-from-reader
|
|
55
|
+
'datahike/HistoricalDB datahike.readers/history-from-reader
|
|
56
|
+
'datahike/SinceDB datahike.readers/since-from-reader
|
|
57
|
+
'datahike/AsOfDB datahike.readers/as-of-from-reader
|
|
58
|
+
'datahike/Connection datahike.readers/connection-from-reader
|
|
59
|
+
'db/id datahike.readers/tempid})
|
|
60
|
+
|
|
61
|
+
#?(:cljs
|
|
62
|
+
(doseq [[tag cb] edn-readers] (cljs.reader/register-tag-parser! tag cb)))
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
(ns datahike.remote
|
|
2
|
+
"Literals that can function as lightweight remote pointers to connections and
|
|
3
|
+
dbs."
|
|
4
|
+
(:require [cognitect.transit :as transit]
|
|
5
|
+
[jsonista.core :as j]
|
|
6
|
+
[jsonista.tagged :as jt]
|
|
7
|
+
[clojure.edn :as edn]
|
|
8
|
+
[datahike.json :refer [json-base-handlers]]
|
|
9
|
+
[datahike.datom :as dd])
|
|
10
|
+
#?(:clj
|
|
11
|
+
(:import [clojure.lang IDeref]
|
|
12
|
+
[datahike.datom Datom]
|
|
13
|
+
[com.fasterxml.jackson.core JsonGenerator])))
|
|
14
|
+
|
|
15
|
+
;; https://github.com/thi-ng/color/issues/10
|
|
16
|
+
;; fixes lein repl / Cloure 1.10.0
|
|
17
|
+
(prefer-method print-method java.util.Map clojure.lang.IDeref)
|
|
18
|
+
|
|
19
|
+
;; fixes lein repl / Clojure 1.10.1
|
|
20
|
+
(prefer-method print-method clojure.lang.IPersistentMap clojure.lang.IDeref)
|
|
21
|
+
|
|
22
|
+
;; fixes CIDER / Clojure 1.9.0 / 1.10.0 / 1.10.1
|
|
23
|
+
(prefer-method clojure.pprint/simple-dispatch clojure.lang.IPersistentMap clojure.lang.IDeref)
|
|
24
|
+
|
|
25
|
+
;; Remote peer currently operated on. This is used to allow the tagged literal
|
|
26
|
+
;; readers to attach the remote again.
|
|
27
|
+
(def ^:dynamic *remote-peer* nil)
|
|
28
|
+
|
|
29
|
+
(defmulti remote-deref (fn [{:keys [remote-peer]}] (:backend remote-peer)))
|
|
30
|
+
|
|
31
|
+
(defprotocol PRemotePeer
|
|
32
|
+
(-remote-peer [_] "Retrieve remote peer."))
|
|
33
|
+
|
|
34
|
+
(extend-protocol PRemotePeer
|
|
35
|
+
Object
|
|
36
|
+
(-remote-peer [_] nil))
|
|
37
|
+
|
|
38
|
+
(defn remote-peer [obj] (-remote-peer obj))
|
|
39
|
+
|
|
40
|
+
(defrecord RemoteConnection [store-id remote-peer]
|
|
41
|
+
#?@(:clj
|
|
42
|
+
[IDeref
|
|
43
|
+
(deref [conn] (remote-deref conn))
|
|
44
|
+
PRemotePeer
|
|
45
|
+
(-remote-peer [_] remote-peer)]))
|
|
46
|
+
|
|
47
|
+
(defn remote-connection [store-id]
|
|
48
|
+
(RemoteConnection. store-id *remote-peer*))
|
|
49
|
+
|
|
50
|
+
#?(:clj
|
|
51
|
+
(defmethod print-method RemoteConnection
|
|
52
|
+
[^RemoteConnection conn ^java.io.Writer w]
|
|
53
|
+
(.write w "#datahike/RemoteConnection")
|
|
54
|
+
(.write w (pr-str (:store-id conn)))))
|
|
55
|
+
|
|
56
|
+
(defrecord RemoteDB [store-id max-tx max-eid commit-id remote-peer]
|
|
57
|
+
PRemotePeer
|
|
58
|
+
(-remote-peer [_] remote-peer))
|
|
59
|
+
|
|
60
|
+
(defn remote-db [m]
|
|
61
|
+
(assoc (map->RemoteDB m) :remote-peer *remote-peer*))
|
|
62
|
+
|
|
63
|
+
#?(:clj
|
|
64
|
+
(defmethod print-method RemoteDB
|
|
65
|
+
[^RemoteDB db ^java.io.Writer w]
|
|
66
|
+
(.write w "#datahike/RemoteDB")
|
|
67
|
+
(.write w (pr-str (into {} (dissoc db :remote-peer))))))
|
|
68
|
+
|
|
69
|
+
(defrecord RemoteHistoricalDB [origin remote-peer]
|
|
70
|
+
PRemotePeer
|
|
71
|
+
(-remote-peer [_] remote-peer))
|
|
72
|
+
|
|
73
|
+
(defn remote-historical-db [m]
|
|
74
|
+
(assoc (map->RemoteHistoricalDB m) :remote-peer *remote-peer*))
|
|
75
|
+
|
|
76
|
+
#?(:clj
|
|
77
|
+
(defmethod print-method RemoteHistoricalDB
|
|
78
|
+
[^RemoteDB db ^java.io.Writer w]
|
|
79
|
+
(.write w "#datahike/RemoteHistoricalDB")
|
|
80
|
+
(.write w (pr-str (into {} (dissoc db :remote-peer))))))
|
|
81
|
+
|
|
82
|
+
(defrecord RemoteSinceDB [origin time-point remote-peer]
|
|
83
|
+
PRemotePeer
|
|
84
|
+
(-remote-peer [_] remote-peer))
|
|
85
|
+
|
|
86
|
+
(defn remote-since-db [m]
|
|
87
|
+
(assoc (map->RemoteSinceDB m) :remote-peer *remote-peer*))
|
|
88
|
+
|
|
89
|
+
#?(:clj
|
|
90
|
+
(defmethod print-method RemoteSinceDB
|
|
91
|
+
[^RemoteDB db ^java.io.Writer w]
|
|
92
|
+
(.write w "#datahike/RemoteSinceDB")
|
|
93
|
+
(.write w (pr-str (into {} (dissoc db :remote-peer))))))
|
|
94
|
+
|
|
95
|
+
(defrecord RemoteAsOfDB [origin time-point remote-peer]
|
|
96
|
+
PRemotePeer
|
|
97
|
+
(-remote-peer [_] remote-peer))
|
|
98
|
+
|
|
99
|
+
(defn remote-as-of-db [m]
|
|
100
|
+
(assoc (map->RemoteAsOfDB m) :remote-peer *remote-peer*))
|
|
101
|
+
|
|
102
|
+
#?(:clj
|
|
103
|
+
(defmethod print-method RemoteAsOfDB
|
|
104
|
+
[^RemoteDB db ^java.io.Writer w]
|
|
105
|
+
(.write w "#datahike/RemoteAsOfDB")
|
|
106
|
+
(.write w (pr-str (into {} (dissoc db :remote-peer))))))
|
|
107
|
+
|
|
108
|
+
(defrecord RemoteEntity [db eid remote-peer]
|
|
109
|
+
PRemotePeer
|
|
110
|
+
(-remote-peer [_] remote-peer))
|
|
111
|
+
|
|
112
|
+
(defn remote-entity [m]
|
|
113
|
+
(assoc (map->RemoteEntity m) :remote-peer *remote-peer*))
|
|
114
|
+
|
|
115
|
+
#?(:clj
|
|
116
|
+
(defmethod print-method RemoteEntity
|
|
117
|
+
[^RemoteEntity e ^java.io.Writer w]
|
|
118
|
+
(.write w "#datahike/RemoteEntity")
|
|
119
|
+
(.write w (pr-str (dissoc (into {} e) :remote-peer)))))
|
|
120
|
+
|
|
121
|
+
(defn edn-replace-remote-literals [s]
|
|
122
|
+
(reduce (fn [^String s [^String from ^String to]]
|
|
123
|
+
(.replace s from to))
|
|
124
|
+
s
|
|
125
|
+
[["#datahike/RemoteConnection" "#datahike/Connection"]
|
|
126
|
+
["#datahike/RemoteDB" "#datahike/DB"]
|
|
127
|
+
["#datahike/RemoteHistoricalDB" "#datahike/HistoricalDB"]
|
|
128
|
+
["#datahike/RemoteSinceDB" "#datahike/SinceDB"]
|
|
129
|
+
["#datahike/RemoteAsOfDB" "#datahike/AsOfDB"]]))
|
|
130
|
+
|
|
131
|
+
(def edn-readers {'datahike/Connection remote-connection
|
|
132
|
+
'datahike/DB remote-db
|
|
133
|
+
'datahike/HistoricalDB remote-historical-db
|
|
134
|
+
'datahike/AsOfDB remote-as-of-db
|
|
135
|
+
'datahike/SinceDB remote-since-db
|
|
136
|
+
'datahike/Datom datahike.datom/datom-from-reader
|
|
137
|
+
'datahike.db.TxReport datahike.db/map->TxReport})
|
|
138
|
+
|
|
139
|
+
(defn map-without-remote [r]
|
|
140
|
+
(dissoc (into {} r) :remote-peer))
|
|
141
|
+
|
|
142
|
+
(defn datom-as-vec [^Datom d]
|
|
143
|
+
[(.-e d) (.-a d) (.-v d) (dd/datom-tx d) (dd/datom-added d)])
|
|
144
|
+
|
|
145
|
+
(defn datom-from-vec [v] (apply dd/datom v))
|
|
146
|
+
|
|
147
|
+
(def transit-write-handlers {datahike.remote.RemoteConnection (transit/write-handler "datahike/Connection" #(:store-id %))
|
|
148
|
+
datahike.datom.Datom (transit/write-handler "datahike/Datom" datom-as-vec)
|
|
149
|
+
datahike.remote.RemoteDB (transit/write-handler "datahike/DB" map-without-remote)
|
|
150
|
+
datahike.remote.RemoteHistoricalDB (transit/write-handler "datahike/HistoricalDB" map-without-remote)
|
|
151
|
+
datahike.remote.RemoteSinceDB (transit/write-handler "datahike/SinceDB" map-without-remote)
|
|
152
|
+
datahike.remote.RemoteAsOfDB (transit/write-handler "datahike/AsOfDB" map-without-remote)
|
|
153
|
+
datahike.remote.RemoteEntity (transit/write-handler "datahike/Entity" #(into {} %))})
|
|
154
|
+
|
|
155
|
+
(def transit-read-handlers {"datahike/Connection" (transit/read-handler remote-connection)
|
|
156
|
+
"datahike/Datom" (transit/read-handler datom-from-vec)
|
|
157
|
+
"datahike/TxReport" (transit/read-handler datahike.db/map->TxReport)
|
|
158
|
+
"datahike/DB" (transit/read-handler remote-db)
|
|
159
|
+
"datahike/HistoricalDB" (transit/read-handler remote-historical-db)
|
|
160
|
+
"datahike/SinceDB" (transit/read-handler remote-since-db)
|
|
161
|
+
"datahike/AsOfDB" (transit/read-handler remote-as-of-db)
|
|
162
|
+
"datahike/Entity" (transit/read-handler remote-entity)})
|
|
163
|
+
|
|
164
|
+
(declare json-mapper)
|
|
165
|
+
|
|
166
|
+
(defn write-to-generator [f]
|
|
167
|
+
(fn [x ^JsonGenerator gen]
|
|
168
|
+
(let [json-out (j/write-value-as-string (f x) json-mapper)]
|
|
169
|
+
(.writeRawValue gen json-out))))
|
|
170
|
+
|
|
171
|
+
(def json-mapper-opts
|
|
172
|
+
{:encode-key-fn true
|
|
173
|
+
:decode-key-fn true
|
|
174
|
+
:modules [(jt/module
|
|
175
|
+
{:handlers
|
|
176
|
+
(merge
|
|
177
|
+
json-base-handlers
|
|
178
|
+
{datahike.remote.RemoteConnection
|
|
179
|
+
{:tag "!datahike/Connection"
|
|
180
|
+
:encode (write-to-generator :store-id)
|
|
181
|
+
:decode remote-connection}
|
|
182
|
+
|
|
183
|
+
datahike.datom.Datom
|
|
184
|
+
{:tag "!datahike/Datom"
|
|
185
|
+
:encode (write-to-generator datom-as-vec)
|
|
186
|
+
:decode datom-from-vec}
|
|
187
|
+
|
|
188
|
+
datahike.db.TxReport
|
|
189
|
+
{:tag "!datahike/TxReport"
|
|
190
|
+
:encode (write-to-generator #(into {} %))
|
|
191
|
+
:decode datahike.db/map->TxReport}
|
|
192
|
+
|
|
193
|
+
datahike.remote.RemoteDB
|
|
194
|
+
{:tag "!datahike/DB"
|
|
195
|
+
:encode (write-to-generator map-without-remote)
|
|
196
|
+
:decode remote-db}
|
|
197
|
+
|
|
198
|
+
datahike.remote.RemoteHistoricalDB
|
|
199
|
+
{:tag "!datahike/HistoricalDB"
|
|
200
|
+
:encode (write-to-generator map-without-remote)
|
|
201
|
+
:decode remote-historical-db}
|
|
202
|
+
|
|
203
|
+
datahike.remote.RemoteSinceDB
|
|
204
|
+
{:tag "!datahike/SinceDB"
|
|
205
|
+
:encode (write-to-generator map-without-remote)
|
|
206
|
+
:decode remote-since-db}
|
|
207
|
+
|
|
208
|
+
datahike.remote.RemoteAsOfDB
|
|
209
|
+
{:tag "!datahike/AsOfDB"
|
|
210
|
+
:encode (write-to-generator map-without-remote)
|
|
211
|
+
:decode remote-as-of-db}
|
|
212
|
+
|
|
213
|
+
datahike.remote.RemoteEntity
|
|
214
|
+
{:tag "!datahike/Entity"
|
|
215
|
+
:encode (write-to-generator #(into {} %))
|
|
216
|
+
:decode remote-entity}})})]})
|
|
217
|
+
|
|
218
|
+
(def json-mapper (j/object-mapper json-mapper-opts))
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
(ns ^:no-doc datahike.schema
|
|
2
|
+
(:require [clojure.spec.alpha :as s]
|
|
3
|
+
[datahike.datom])
|
|
4
|
+
#?(:clj (:import [datahike.datom Datom])))
|
|
5
|
+
|
|
6
|
+
(s/def :db.type/id #?(:clj #(or (= (class %) java.lang.Long) string?)
|
|
7
|
+
:cljs #(or (and (number? %)
|
|
8
|
+
(js/Number.isSafeInteger %))
|
|
9
|
+
string?)))
|
|
10
|
+
|
|
11
|
+
;; db types
|
|
12
|
+
(s/def :db.type/bigdec #?(:cljs (complement any?) ; feels more appropriate than hiding key -pat
|
|
13
|
+
:clj decimal?))
|
|
14
|
+
(s/def :db.type/bigint #?(:clj integer?
|
|
15
|
+
:cljs #(or (integer? %)
|
|
16
|
+
(= js/BigInt (type %)))))
|
|
17
|
+
(s/def :db.type/boolean boolean?)
|
|
18
|
+
(s/def :db.type/bytes #?(:clj bytes?
|
|
19
|
+
:cljs #(and (some->> (.-buffer %) (instance? js/ArrayBuffer))
|
|
20
|
+
(some->> (.-byteLength %) (number?)))))
|
|
21
|
+
(s/def :db.type/double double?)
|
|
22
|
+
(s/def :db.type/float float?)
|
|
23
|
+
(s/def :db.type/number number?)
|
|
24
|
+
(s/def :db.type/instant #?(:clj #(= (class %) java.util.Date)
|
|
25
|
+
:cljs inst?))
|
|
26
|
+
(s/def :db.type/keyword keyword?)
|
|
27
|
+
(s/def :db.type/long #?(:clj #(= (class %) java.lang.Long)
|
|
28
|
+
:cljs #(js/Number.isSafeInteger %)))
|
|
29
|
+
(s/def :db.type/ref :db.type/id)
|
|
30
|
+
(s/def :db.type/string string?)
|
|
31
|
+
(s/def :db.type/symbol symbol?)
|
|
32
|
+
(s/def :db.type/uuid uuid?)
|
|
33
|
+
(s/def :db.type/tuple vector?)
|
|
34
|
+
|
|
35
|
+
(s/def :db.type/value
|
|
36
|
+
#{:db.type/bigdec
|
|
37
|
+
:db.type/bigint
|
|
38
|
+
:db.type/boolean
|
|
39
|
+
:db.type/bytes
|
|
40
|
+
:db.type/double
|
|
41
|
+
:db.type/float
|
|
42
|
+
:db.type/number
|
|
43
|
+
:db.type/instant
|
|
44
|
+
:db.type/keyword
|
|
45
|
+
:db.type/long
|
|
46
|
+
:db.type/ref
|
|
47
|
+
:db.type/string
|
|
48
|
+
:db.type/symbol
|
|
49
|
+
:db.type/uuid
|
|
50
|
+
:db.type/value
|
|
51
|
+
:db.type/tuple
|
|
52
|
+
:db.type/cardinality
|
|
53
|
+
:db.type.install/attribute
|
|
54
|
+
:db.type/valueType
|
|
55
|
+
:db.type/unique})
|
|
56
|
+
|
|
57
|
+
;; TODO: add bytes
|
|
58
|
+
|
|
59
|
+
(s/def :db.type/cardinality #{:db.cardinality/one :db.cardinality/many})
|
|
60
|
+
(s/def :db.type/unique #{:db.unique/identity :db.unique/value})
|
|
61
|
+
|
|
62
|
+
;; only for old datomic compliance, will be part of partioning in the future
|
|
63
|
+
(s/def :db.type.install/_attribute #{:db.part/tx :db.part/db :db.part/user})
|
|
64
|
+
|
|
65
|
+
(s/def ::schema-attribute #{:db/id :db/ident :db/isComponent :db/noHistory :db/valueType :db/cardinality :db/unique :db/index :db.install/_attribute :db/doc :db/tupleAttrs :db/tupleType :db/tupleTypes})
|
|
66
|
+
|
|
67
|
+
(s/def ::entity-spec-attribute #{:db/ensure :db.entity/attrs :db.entity/preds})
|
|
68
|
+
(s/def ::meta-attribute #{:db/txInstant :db/retracted :db/noCommit})
|
|
69
|
+
|
|
70
|
+
(s/def ::schema (s/keys :req [:db/ident :db/valueType :db/cardinality]
|
|
71
|
+
:opt [:db/id :db/unique :db/index :db.install/_attribute :db/doc :db/noHistory :db/tupleType :db/tupleTypes]))
|
|
72
|
+
|
|
73
|
+
(s/def ::entity-spec (s/keys :opt [:db.entity/attrs :db.entity/preds]))
|
|
74
|
+
|
|
75
|
+
(s/def ::enum (s/keys :req [:db/ident]))
|
|
76
|
+
|
|
77
|
+
(def required-keys #{:db/ident :db/valueType :db/cardinality})
|
|
78
|
+
|
|
79
|
+
(def ^:const implicit-schema-spec {:db/ident {:db/valueType :db.type/keyword
|
|
80
|
+
:db/unique :db.unique/identity
|
|
81
|
+
:db/cardinality :db.cardinality/one}
|
|
82
|
+
:db/valueType {:db/valueType :db.type/value
|
|
83
|
+
:db/unique :db.unique/identity
|
|
84
|
+
:db/cardinality :db.cardinality/one}
|
|
85
|
+
:db/id {:db/valueType :db.type/id
|
|
86
|
+
:db/unique :db.unique/identity
|
|
87
|
+
:db/cardinality :db.cardinality/one}
|
|
88
|
+
:db/cardinality {:db/valueType :db.type/cardinality
|
|
89
|
+
:db/unique :db.unique/identity
|
|
90
|
+
:db/cardinality :db.cardinality/one}
|
|
91
|
+
:db/index {:db/valueType :db.type/boolean
|
|
92
|
+
:db/unique :db.unique/identity
|
|
93
|
+
:db/cardinality :db.cardinality/one}
|
|
94
|
+
:db/unique {:db/valueType :db.type/unique
|
|
95
|
+
:db/unique :db.unique/identity
|
|
96
|
+
:db/cardinality :db.cardinality/one}
|
|
97
|
+
:db/isComponent {:db/valueType :db.type/boolean
|
|
98
|
+
:db/unique :db.unique/identity
|
|
99
|
+
:db/cardinality :db.cardinality/one}
|
|
100
|
+
:db/noHistory {:db/valueType :db.type/boolean
|
|
101
|
+
:db/unique :db.unique/identity
|
|
102
|
+
:db/cardinality :db.cardinality/one}
|
|
103
|
+
:db/txInstant {:db/valueType :db.type/instant
|
|
104
|
+
:db/unique :db.unique/identity
|
|
105
|
+
:db/index true
|
|
106
|
+
:db/cardinality :db.cardinality/one}
|
|
107
|
+
:db/noCommit {:db/valueType :db.type/boolean
|
|
108
|
+
:db/unique :db.unique/identity
|
|
109
|
+
:db/cardinality :db.cardinality/one}
|
|
110
|
+
:db/retracted {:db/valueType :db.type/long
|
|
111
|
+
:db/unique :db.unique/identity
|
|
112
|
+
:db/cardinality :db.cardinality/many}
|
|
113
|
+
:db/ensure {:db/valueType :db.type/keyword
|
|
114
|
+
:db/cardinality :db.cardinality/one}
|
|
115
|
+
:db.entity/attrs {:db/valueType :db.type/keyword
|
|
116
|
+
:db/cardinality :db.cardinality/many}
|
|
117
|
+
:db.entity/preds {:db/valueType :db.type/symbol
|
|
118
|
+
:db/cardinality :db.cardinality/many}
|
|
119
|
+
:db/doc {:db/valueType :db.type/string
|
|
120
|
+
:db/index true
|
|
121
|
+
:db/cardinality :db.cardinality/one}
|
|
122
|
+
:db.install/_attribute {:db/valueType :db.type.install/_attribute
|
|
123
|
+
:db/unique :db.unique/identity
|
|
124
|
+
:db/cardinality :db.cardinality/one}
|
|
125
|
+
:db/tupleType {:db/valueType :db.type/value
|
|
126
|
+
:db/cardinality :db.cardinality/one}
|
|
127
|
+
:db/tupleTypes {:db/valueType :db.type/tuple
|
|
128
|
+
:db/cardinality :db.cardinality/one}
|
|
129
|
+
:db/tupleAttrs {:db/valueType :db.type/tuple
|
|
130
|
+
:db/cardinality :db.cardinality/one}})
|
|
131
|
+
(s/def :db/helpers #{:db.install/attribute :db})
|
|
132
|
+
(s/def :db.part/types #{:db.part/tx :db.part/sys :db.part/user})
|
|
133
|
+
|
|
134
|
+
(s/def :db.meta/attributes #{:db/txInstant})
|
|
135
|
+
|
|
136
|
+
(s/def ::sys-idents (s/or :value :db.type/value
|
|
137
|
+
:cardinality :db.type/cardinality
|
|
138
|
+
:parts :db.part/types
|
|
139
|
+
:helpers :db/helpers
|
|
140
|
+
:meta :db.meta/attributes
|
|
141
|
+
:unique :db.type/unique))
|
|
142
|
+
|
|
143
|
+
(def schema-keys #{:db/ident :db/isComponent :db/noHistory :db/valueType :db/cardinality :db/unique :db/index :db.install/_attribute :db/doc :db/tupleType :db/tupleTypes :db/tupleAttrs})
|
|
144
|
+
|
|
145
|
+
(s/def ::old-schema-val (s/keys :req [:db/valueType :db/cardinality]
|
|
146
|
+
:opt [:db/ident :db/unique :db/index :db.install/_attribute :db/doc :db/noHistory]))
|
|
147
|
+
|
|
148
|
+
(s/def ::old-schema-key keyword?)
|
|
149
|
+
|
|
150
|
+
(s/def ::old-schema (s/nilable (s/map-of ::old-schema-key ::old-schema-val)))
|
|
151
|
+
|
|
152
|
+
(defn old-schema-valid? [schema]
|
|
153
|
+
(s/valid? ::old-schema schema))
|
|
154
|
+
|
|
155
|
+
(defn explain-old-schema [schema]
|
|
156
|
+
(s/explain-data ::old-schema schema))
|
|
157
|
+
|
|
158
|
+
(defn meta-attr? [a-ident]
|
|
159
|
+
(s/valid? ::meta-attribute a-ident))
|
|
160
|
+
|
|
161
|
+
(defn schema-attr? [a-ident]
|
|
162
|
+
(s/valid? ::schema-attribute a-ident))
|
|
163
|
+
|
|
164
|
+
(defn sys-ident? [a-ident]
|
|
165
|
+
(s/valid? ::sys-idents a-ident))
|
|
166
|
+
|
|
167
|
+
(defn entity-spec-attr? [a-ident]
|
|
168
|
+
(s/valid? ::entity-spec-attribute a-ident))
|
|
169
|
+
|
|
170
|
+
(defn value-valid? [a-ident v-ident schema]
|
|
171
|
+
(let [schema (if (or (meta-attr? a-ident) (schema-attr? a-ident) (entity-spec-attr? a-ident))
|
|
172
|
+
implicit-schema-spec
|
|
173
|
+
schema)
|
|
174
|
+
value-type (get-in schema [a-ident :db/valueType])]
|
|
175
|
+
(s/valid? value-type v-ident)))
|
|
176
|
+
|
|
177
|
+
(defn instant? [db ^Datom datom schema]
|
|
178
|
+
(let [a-ident (if (:attribute-refs? (:config db))
|
|
179
|
+
((:ref-ident-map db) (.-a datom))
|
|
180
|
+
(.-a datom))
|
|
181
|
+
schema (if (or (meta-attr? a-ident) (schema-attr? a-ident))
|
|
182
|
+
implicit-schema-spec
|
|
183
|
+
schema)]
|
|
184
|
+
(= (get-in schema [a-ident :db/valueType]) :db.type/instant)))
|
|
185
|
+
|
|
186
|
+
(defn schema-entity? [entity]
|
|
187
|
+
(some #(contains? entity %) schema-keys))
|
|
188
|
+
|
|
189
|
+
(defn schema? [schema]
|
|
190
|
+
(s/valid? ::schema schema))
|
|
191
|
+
|
|
192
|
+
(defn describe-type [schema-type]
|
|
193
|
+
(s/describe schema-type))
|
|
194
|
+
|
|
195
|
+
(defn find-invalid-schema-updates [entity attr-schema]
|
|
196
|
+
(reduce-kv
|
|
197
|
+
(fn [m attr-def new-value]
|
|
198
|
+
(let [old-value (get-in attr-schema [attr-def])]
|
|
199
|
+
(when (not= old-value new-value)
|
|
200
|
+
(case attr-def
|
|
201
|
+
:db/cardinality
|
|
202
|
+
;; Prohibit update from :db.cardinality/one to :db.cardinality/many, if there is a :db/unique constraint.
|
|
203
|
+
(when (and (= new-value :db.cardinality/many)
|
|
204
|
+
(#{:db.unique/value :db.unique/identity} (:db/unique attr-schema)))
|
|
205
|
+
(assoc m attr-def [old-value new-value]))
|
|
206
|
+
|
|
207
|
+
:db/unique
|
|
208
|
+
(when (or (not (:db/unique attr-schema))
|
|
209
|
+
(not= :db.cardinality/one (:db/cardinality attr-schema)))
|
|
210
|
+
(assoc m attr-def [old-value new-value]))
|
|
211
|
+
|
|
212
|
+
;; Always allow these attributes to be updated.
|
|
213
|
+
:db/doc nil
|
|
214
|
+
:db/noHistory nil
|
|
215
|
+
:db/isComponent nil
|
|
216
|
+
|
|
217
|
+
(assoc m attr-def [old-value new-value])))))
|
|
218
|
+
{}
|
|
219
|
+
(dissoc entity :db/id)))
|
|
220
|
+
|
|
221
|
+
(defn is-system-keyword? [value]
|
|
222
|
+
(and (or (keyword? value) (string? value))
|
|
223
|
+
(if-let [ns (namespace (keyword value))]
|
|
224
|
+
(= "db" (first (clojure.string/split ns #"\.")))
|
|
225
|
+
false)))
|
|
226
|
+
|
|
227
|
+
(defn get-user-schema [{:keys [schema] :as db}]
|
|
228
|
+
(into {} (filter #(not (is-system-keyword? (key %))) schema)))
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
(ns datahike.schema-cache
|
|
2
|
+
(:require #?(:clj [clojure.core.cache.wrapped :as cw]
|
|
3
|
+
:cljs [cljs.cache.wrapped :as cw])
|
|
4
|
+
[datahike.config :as dc]
|
|
5
|
+
[datahike.store :as ds]))
|
|
6
|
+
|
|
7
|
+
;; Shared schema read cache across all stores
|
|
8
|
+
(def schema-meta-cache (cw/lru-cache-factory {} :threshold dc/*schema-meta-cache-size*))
|
|
9
|
+
|
|
10
|
+
;; LRU cache of LRU caches for write operations, one per store
|
|
11
|
+
(def schema-write-caches
|
|
12
|
+
(cw/lru-cache-factory {} :threshold dc/*schema-write-cache-max-db-count*))
|
|
13
|
+
|
|
14
|
+
(defn- get-or-create-write-cache [store-config]
|
|
15
|
+
(let [store-id (ds/store-identity store-config)]
|
|
16
|
+
(if (cw/has? schema-write-caches store-id)
|
|
17
|
+
(cw/lookup schema-write-caches store-id)
|
|
18
|
+
(let [new-cache (cw/lru-cache-factory {} :threshold dc/*schema-meta-cache-size*)]
|
|
19
|
+
(cw/miss schema-write-caches store-id new-cache)
|
|
20
|
+
new-cache))))
|
|
21
|
+
|
|
22
|
+
(defn cache-has? [schema-meta-key]
|
|
23
|
+
(cw/has? schema-meta-cache schema-meta-key))
|
|
24
|
+
|
|
25
|
+
(defn cache-lookup [schema-meta-key]
|
|
26
|
+
(cw/lookup schema-meta-cache schema-meta-key))
|
|
27
|
+
|
|
28
|
+
(defn cache-miss [schema-meta-key schema-meta]
|
|
29
|
+
(cw/miss schema-meta-cache schema-meta-key schema-meta))
|
|
30
|
+
|
|
31
|
+
(defn write-cache-has? [store-config schema-meta-key]
|
|
32
|
+
(let [write-cache (get-or-create-write-cache store-config)]
|
|
33
|
+
(cw/has? write-cache schema-meta-key)))
|
|
34
|
+
|
|
35
|
+
(defn add-to-write-cache [store-config schema-meta-key]
|
|
36
|
+
(let [write-cache (get-or-create-write-cache store-config)]
|
|
37
|
+
(cw/miss write-cache schema-meta-key true)))
|
|
38
|
+
|
|
39
|
+
(defn clear-write-cache [store-config]
|
|
40
|
+
(let [store-id (ds/store-identity store-config)]
|
|
41
|
+
(cw/evict schema-write-caches store-id)))
|
|
42
|
+
|