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,294 @@
|
|
|
1
|
+
(ns ^:no-doc datahike.config
|
|
2
|
+
(:require [clojure.edn :as edn]
|
|
3
|
+
[clojure.walk :refer [postwalk]]
|
|
4
|
+
[clojure.string :as str]
|
|
5
|
+
[clojure.spec.alpha :as s]
|
|
6
|
+
[environ.core :refer [env]]
|
|
7
|
+
[datahike.tools :as dt]
|
|
8
|
+
[datahike.store :as ds]
|
|
9
|
+
[datahike.index :as di]
|
|
10
|
+
[taoensso.timbre :as log])
|
|
11
|
+
(:import #?(:clj [java.net URI]
|
|
12
|
+
:cljs [goog.Uri])))
|
|
13
|
+
|
|
14
|
+
;; global
|
|
15
|
+
(def ^:dynamic *schema-meta-cache-size* (env :schema-meta-cache-size 1024))
|
|
16
|
+
(def ^:dynamic *schema-write-cache-max-db-count* (env :schema-write-cache-size 1024))
|
|
17
|
+
|
|
18
|
+
;; per database
|
|
19
|
+
(def ^:dynamic *default-index* :datahike.index/persistent-set)
|
|
20
|
+
(def ^:dynamic *default-schema-flexibility* :write)
|
|
21
|
+
(def ^:dynamic *default-keep-history?* true)
|
|
22
|
+
(def ^:dynamic *default-attribute-refs?* false)
|
|
23
|
+
(def ^:dynamic *default-search-cache-size* 10000)
|
|
24
|
+
(def ^:dynamic *default-store-cache-size* 1000)
|
|
25
|
+
(def ^:dynamic *default-crypto-hash?* false)
|
|
26
|
+
(def ^:dynamic *default-store* :memory) ;; store-less = in-memory?
|
|
27
|
+
(def ^:dynamic *default-db-name* nil) ;; when nil creates random name
|
|
28
|
+
(def ^:dynamic *default-db-branch* :db) ;; when nil creates random name
|
|
29
|
+
|
|
30
|
+
(s/def ::index #{:datahike.index/hitchhiker-tree :datahike.index/persistent-set})
|
|
31
|
+
(s/def ::keep-history? boolean?)
|
|
32
|
+
(s/def ::schema-flexibility #{:read :write})
|
|
33
|
+
(s/def ::attribute-refs? boolean?)
|
|
34
|
+
(s/def ::search-cache-size nat-int?)
|
|
35
|
+
(s/def ::store-cache-size pos-int?)
|
|
36
|
+
(s/def ::crypto-hash? boolean?)
|
|
37
|
+
(s/def ::writer map?)
|
|
38
|
+
(s/def ::branch keyword?)
|
|
39
|
+
(s/def ::entity (s/or :map associative? :vec vector?))
|
|
40
|
+
(s/def ::initial-tx (s/nilable (s/or :data (s/coll-of ::entity) :path string?
|
|
41
|
+
:was-added? boolean?)))
|
|
42
|
+
(s/def ::name string?)
|
|
43
|
+
|
|
44
|
+
(s/def ::index-config map?)
|
|
45
|
+
|
|
46
|
+
(s/def ::store map?)
|
|
47
|
+
|
|
48
|
+
(s/def :datahike/config (s/keys :opt-un [:datahike/store
|
|
49
|
+
::index
|
|
50
|
+
::index-config
|
|
51
|
+
::keep-history?
|
|
52
|
+
::schema-flexibility
|
|
53
|
+
::attribute-refs?
|
|
54
|
+
::search-cache-size
|
|
55
|
+
::store-cache-size
|
|
56
|
+
::crypto-hash?
|
|
57
|
+
::initial-tx
|
|
58
|
+
::name
|
|
59
|
+
::branch
|
|
60
|
+
::writer]))
|
|
61
|
+
|
|
62
|
+
(s/def :deprecated/schema-on-read boolean?)
|
|
63
|
+
(s/def :deprecated/temporal-index boolean?)
|
|
64
|
+
(s/def :deprecated/config (s/keys :req-un [:datahike/store]
|
|
65
|
+
:opt-un [:deprecated/temporal-index :deprecated/schema-on-read]))
|
|
66
|
+
|
|
67
|
+
(def self-writer {:backend :self})
|
|
68
|
+
|
|
69
|
+
(defn from-deprecated
|
|
70
|
+
[{:keys [backend username password path host port id] :as _backend-cfg}
|
|
71
|
+
& {:keys [schema-on-read temporal-index index initial-tx]
|
|
72
|
+
:as _index-cfg
|
|
73
|
+
:or {schema-on-read false
|
|
74
|
+
index *default-index*
|
|
75
|
+
temporal-index true}}]
|
|
76
|
+
{:store (merge {:backend backend}
|
|
77
|
+
(case backend
|
|
78
|
+
:memory {:id (or id
|
|
79
|
+
(when (or host path)
|
|
80
|
+
#?(:clj (java.util.UUID/nameUUIDFromBytes (.getBytes (str (or host path)) "UTF-8"))
|
|
81
|
+
:cljs (uuid (str (or host path))))))}
|
|
82
|
+
:pg {:username username
|
|
83
|
+
:password password
|
|
84
|
+
:path path
|
|
85
|
+
:host host
|
|
86
|
+
:port port
|
|
87
|
+
:id (or id #?(:clj (java.util.UUID/randomUUID) :cljs (random-uuid)))}
|
|
88
|
+
:level {:path path
|
|
89
|
+
:id (or id
|
|
90
|
+
(when path
|
|
91
|
+
#?(:clj (java.util.UUID/nameUUIDFromBytes (.getBytes path "UTF-8"))
|
|
92
|
+
:cljs (uuid path))))}
|
|
93
|
+
:file {:path path
|
|
94
|
+
:id (or id
|
|
95
|
+
(when path
|
|
96
|
+
#?(:clj (java.util.UUID/nameUUIDFromBytes (.getBytes path "UTF-8"))
|
|
97
|
+
:cljs (uuid path))))}))
|
|
98
|
+
:index index
|
|
99
|
+
:index-config (di/default-index-config index)
|
|
100
|
+
:keep-history? temporal-index
|
|
101
|
+
:attribute-refs? *default-attribute-refs?*
|
|
102
|
+
:initial-tx initial-tx
|
|
103
|
+
:schema-flexibility (if (true? schema-on-read) :read :write)
|
|
104
|
+
:branch *default-db-branch*
|
|
105
|
+
:writer self-writer
|
|
106
|
+
:crypto-hash? *default-crypto-hash?*
|
|
107
|
+
:search-cache-size *default-search-cache-size*
|
|
108
|
+
:store-cache-size *default-store-cache-size*})
|
|
109
|
+
|
|
110
|
+
(defn int-from-env
|
|
111
|
+
[key default]
|
|
112
|
+
(try
|
|
113
|
+
(#?(:clj Integer/parseInt :cljs js/parseInt) (get env key (str default)))
|
|
114
|
+
(catch #?(:clj Exception :cljs js/Error) _ default)))
|
|
115
|
+
|
|
116
|
+
(defn bool-from-env
|
|
117
|
+
[key default]
|
|
118
|
+
(try
|
|
119
|
+
#?(:clj (Boolean/parseBoolean (get env key default))
|
|
120
|
+
:cljs (= "true" (get env key default)))
|
|
121
|
+
(catch #?(:clj Exception :cljs js/Error) _ default)))
|
|
122
|
+
|
|
123
|
+
(defn map-from-env [key default]
|
|
124
|
+
(try
|
|
125
|
+
(edn/read-string (get env key (str default)))
|
|
126
|
+
(catch #?(:clj Exception :cljs js/Error) _ default)))
|
|
127
|
+
|
|
128
|
+
(defn validate-config-attribute [attribute value config]
|
|
129
|
+
(when-not (s/valid? attribute value)
|
|
130
|
+
(throw (ex-info (str "Bad value " value " at " (name attribute)
|
|
131
|
+
", value does not match configuration definition. Must be conform to: "
|
|
132
|
+
(s/describe attribute)) config))))
|
|
133
|
+
|
|
134
|
+
(defn validate-config [{:keys [attribute-refs? schema-flexibility] :as config}]
|
|
135
|
+
(when-not (s/valid? :datahike/config config)
|
|
136
|
+
(throw (ex-info "Invalid Datahike configuration." (s/explain-data :datahike/config config))))
|
|
137
|
+
(when (and attribute-refs? (= :read schema-flexibility))
|
|
138
|
+
(throw (ex-info "Attribute references cannot be used with schema-flexibility ':read'." config))))
|
|
139
|
+
|
|
140
|
+
(defn storeless-config []
|
|
141
|
+
{:store nil
|
|
142
|
+
:keep-history? false
|
|
143
|
+
:schema-flexibility :read
|
|
144
|
+
:attribute-refs? false
|
|
145
|
+
:index *default-index*
|
|
146
|
+
:search-cache-size *default-search-cache-size*
|
|
147
|
+
:store-cache-size *default-store-cache-size*
|
|
148
|
+
:crypto-hash? *default-crypto-hash?*
|
|
149
|
+
:branch *default-db-branch*
|
|
150
|
+
:writer self-writer
|
|
151
|
+
:index-config (di/default-index-config *default-index*)})
|
|
152
|
+
|
|
153
|
+
(defn remove-nils
|
|
154
|
+
"Thanks to https://stackoverflow.com/a/34221816"
|
|
155
|
+
[m]
|
|
156
|
+
(let [f (fn [x]
|
|
157
|
+
(if (map? x)
|
|
158
|
+
(let [kvs (filter (comp not nil? second) x)]
|
|
159
|
+
(if (empty? kvs) nil (into {} kvs)))
|
|
160
|
+
x))]
|
|
161
|
+
(postwalk f m)))
|
|
162
|
+
|
|
163
|
+
(defn- validate-store-backend
|
|
164
|
+
"Validate that the store backend is compatible with Datahike's sync query engine.
|
|
165
|
+
Throws an informative error for async-only backends like IndexedDB."
|
|
166
|
+
[store-config]
|
|
167
|
+
(when (= :indexeddb (:backend store-config))
|
|
168
|
+
(throw (ex-info
|
|
169
|
+
(str "The :indexeddb backend cannot be used directly.\n\n"
|
|
170
|
+
"Datahike's query engine requires synchronous reads, but "
|
|
171
|
+
"IndexedDB is async-only.\n\n"
|
|
172
|
+
"Use a TieredStore with memory frontend instead:\n\n"
|
|
173
|
+
"{:store {:backend :tiered\n"
|
|
174
|
+
" :id <your-uuid>\n"
|
|
175
|
+
" :frontend-config {:backend :memory :id <your-uuid>}\n"
|
|
176
|
+
" :backend-config {:backend :indexeddb :id <your-uuid>}}}\n\n"
|
|
177
|
+
"See: https://github.com/replikativ/datahike/blob/main/doc/cljs-support.md")
|
|
178
|
+
{:type :async-only-backend
|
|
179
|
+
:backend :indexeddb
|
|
180
|
+
:config store-config}))))
|
|
181
|
+
|
|
182
|
+
(defn load-config
|
|
183
|
+
"Load and validate configuration with defaults from the store."
|
|
184
|
+
([]
|
|
185
|
+
(load-config nil nil))
|
|
186
|
+
([config-as-arg]
|
|
187
|
+
(load-config config-as-arg nil))
|
|
188
|
+
([config-as-arg opts]
|
|
189
|
+
(let [config-as-arg (if (s/valid? :datahike/config-depr config-as-arg)
|
|
190
|
+
(apply from-deprecated config-as-arg (first opts))
|
|
191
|
+
config-as-arg)
|
|
192
|
+
;; Store config now provided by user - konserve validates :id requirement
|
|
193
|
+
raw-store-config (merge
|
|
194
|
+
{:backend (keyword (:datahike-store-backend env *default-store*))}
|
|
195
|
+
(:store config-as-arg))
|
|
196
|
+
;; Normalize :mem to :memory for backward compatibility
|
|
197
|
+
store-config (if (= (:backend raw-store-config) :mem)
|
|
198
|
+
(do
|
|
199
|
+
(log/warn "DEPRECATION: :mem backend is deprecated, use :memory instead. Support for :mem will be removed in a future version.")
|
|
200
|
+
(assoc raw-store-config :backend :memory))
|
|
201
|
+
raw-store-config)
|
|
202
|
+
_ (validate-store-backend store-config)
|
|
203
|
+
index (if (:datahike-index env)
|
|
204
|
+
(keyword "datahike.index" (:datahike-index env))
|
|
205
|
+
*default-index*)
|
|
206
|
+
config {:store store-config
|
|
207
|
+
:initial-tx (:datahike-initial-tx env)
|
|
208
|
+
:keep-history? (bool-from-env :datahike-keep-history *default-keep-history?*)
|
|
209
|
+
:attribute-refs? (bool-from-env :datahike-attribute-refs *default-attribute-refs?*)
|
|
210
|
+
:schema-flexibility (keyword (:datahike-schema-flexibility env *default-schema-flexibility*))
|
|
211
|
+
:index index
|
|
212
|
+
:branch *default-db-branch*
|
|
213
|
+
:crypto-hash? *default-crypto-hash?*
|
|
214
|
+
:writer self-writer
|
|
215
|
+
:search-cache-size (int-from-env :datahike-search-cache-size *default-search-cache-size*)
|
|
216
|
+
:store-cache-size (int-from-env :datahike-store-cache-size *default-store-cache-size*)
|
|
217
|
+
:index-config (if-let [index-config (map-from-env :datahike-index-config nil)]
|
|
218
|
+
index-config
|
|
219
|
+
(di/default-index-config index))}
|
|
220
|
+
merged-config ((comp remove-nils dt/deep-merge) config config-as-arg)
|
|
221
|
+
{:keys [schema-flexibility initial-tx store attribute-refs?]} merged-config]
|
|
222
|
+
;; konserve now handles store config validation at runtime
|
|
223
|
+
(when-not (s/valid? :datahike/config merged-config)
|
|
224
|
+
(throw (ex-info "Invalid Datahike configuration." (s/explain-data :datahike/config merged-config))))
|
|
225
|
+
(when (and attribute-refs? (= :read schema-flexibility))
|
|
226
|
+
(throw (ex-info "Attribute references cannot be used with schema-flexibility ':read'." config)))
|
|
227
|
+
(if (string? initial-tx)
|
|
228
|
+
#?(:clj (update merged-config :initial-tx (fn [path] (-> path slurp read-string)))
|
|
229
|
+
:cljs (throw (ex-info ":initial-tx from path is not supported in cljs at this time" merged-config)))
|
|
230
|
+
merged-config))))
|
|
231
|
+
|
|
232
|
+
;; deprecation begin
|
|
233
|
+
(s/def ::backend-depr keyword?)
|
|
234
|
+
(s/def ::username-depr string?)
|
|
235
|
+
(s/def ::password-depr string?)
|
|
236
|
+
(s/def ::path-depr string?)
|
|
237
|
+
(s/def ::host-depr string?)
|
|
238
|
+
(s/def ::port-depr int?)
|
|
239
|
+
(s/def ::uri-depr string?)
|
|
240
|
+
|
|
241
|
+
(s/def :datahike/config-depr (s/keys :req-un [::backend]
|
|
242
|
+
:opt-un [::username ::password ::path ::host ::port]))
|
|
243
|
+
|
|
244
|
+
(defn uri->config [uri]
|
|
245
|
+
(log/warn "DEPRECATION WARNING: URI string format for Datahike configuration is deprecated and may be removed in a future version. Please migrate to the map-based configuration format. See documentation for details.")
|
|
246
|
+
(let [base-uri (#?(:clj URI. :cljs goog.Uri.) uri)
|
|
247
|
+
_ (when-not (= (.getScheme base-uri) "datahike")
|
|
248
|
+
(throw (ex-info "URI scheme is not datahike conform." {:uri uri})))
|
|
249
|
+
sub-uri #?(:clj (URI. (.getSchemeSpecificPart base-uri))
|
|
250
|
+
:cljs (goog.Uri. (.getScheme base-uri)))
|
|
251
|
+
backend-raw (keyword (.getScheme sub-uri))
|
|
252
|
+
;; Normalize :mem to :memory for backward compatibility
|
|
253
|
+
backend (if (= backend-raw :mem) :memory backend-raw)
|
|
254
|
+
[username password] (when-let [user-info (.getUserInfo sub-uri)]
|
|
255
|
+
(str/split user-info #":"))
|
|
256
|
+
credentials (when-not (and (nil? username) (nil? password))
|
|
257
|
+
{:username username
|
|
258
|
+
:password password})
|
|
259
|
+
port (.getPort sub-uri)
|
|
260
|
+
path (.getPath sub-uri)
|
|
261
|
+
host (.getHost sub-uri)
|
|
262
|
+
;; Parse query parameters to extract id if present
|
|
263
|
+
query-string #?(:clj (.getQuery sub-uri)
|
|
264
|
+
:cljs (when-let [qd (.getQueryData sub-uri)]
|
|
265
|
+
(when (.containsKey qd "id")
|
|
266
|
+
(str "id=" (.get qd "id")))))
|
|
267
|
+
parsed-id (when query-string
|
|
268
|
+
(when-let [[_ id-str] (re-find #"id=([0-9a-fA-F-]+)" query-string)]
|
|
269
|
+
#?(:clj (try (java.util.UUID/fromString id-str)
|
|
270
|
+
(catch Exception e
|
|
271
|
+
(throw (ex-info "Invalid UUID format in ?id= query parameter"
|
|
272
|
+
{:uri uri :id-str id-str :error (.getMessage e)}))))
|
|
273
|
+
:cljs (try (uuid id-str)
|
|
274
|
+
(catch js/Error e
|
|
275
|
+
(throw (ex-info "Invalid UUID format in ?id= query parameter"
|
|
276
|
+
{:uri uri :id-str id-str :error (.-message e)})))))))
|
|
277
|
+
config (merge
|
|
278
|
+
{:backend backend
|
|
279
|
+
:uri uri}
|
|
280
|
+
credentials
|
|
281
|
+
(when host
|
|
282
|
+
{:host host})
|
|
283
|
+
(when-not (empty? path)
|
|
284
|
+
{:path path})
|
|
285
|
+
(when (<= 0 port)
|
|
286
|
+
{:port port})
|
|
287
|
+
(when parsed-id
|
|
288
|
+
{:id parsed-id}))]
|
|
289
|
+
config))
|
|
290
|
+
|
|
291
|
+
(defn validate-config-depr [config]
|
|
292
|
+
(when-not (s/valid? :datahike/config-depr config)
|
|
293
|
+
(throw (ex-info "Invalid datahike configuration." config))))
|
|
294
|
+
;; deprecation end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
(ns ^:no-doc datahike.connections)
|
|
2
|
+
|
|
3
|
+
(def ^:dynamic *connections* (atom {}))
|
|
4
|
+
|
|
5
|
+
(defn get-connection [conn-id]
|
|
6
|
+
(when-let [conn (get-in @*connections* [conn-id :conn])]
|
|
7
|
+
(swap! *connections* update-in [conn-id :count] inc)
|
|
8
|
+
conn))
|
|
9
|
+
|
|
10
|
+
(defn add-connection! [conn-id conn]
|
|
11
|
+
(swap! *connections* assoc conn-id {:conn conn :count 1}))
|
|
12
|
+
|
|
13
|
+
(defn delete-connection! [conn-id]
|
|
14
|
+
(when-let [conn (get-connection conn-id)]
|
|
15
|
+
(reset! conn :released)
|
|
16
|
+
(swap! *connections* dissoc conn-id)))
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
(ns ^:no-doc datahike.connector
|
|
2
|
+
(:require [datahike.connections :refer [get-connection add-connection! delete-connection!
|
|
3
|
+
*connections*]]
|
|
4
|
+
[datahike.readers]
|
|
5
|
+
[datahike.store :as ds]
|
|
6
|
+
[datahike.writing :as dsi]
|
|
7
|
+
[datahike.config :as dc]
|
|
8
|
+
[datahike.tools :as dt #?(:clj :refer :cljs :refer-macros) [meta-data]]
|
|
9
|
+
[datahike.writer :as w]
|
|
10
|
+
[konserve.core :as k]
|
|
11
|
+
[konserve.store :as ks]
|
|
12
|
+
[taoensso.timbre :as log]
|
|
13
|
+
[clojure.spec.alpha :as s]
|
|
14
|
+
[clojure.data :refer [diff]]
|
|
15
|
+
[konserve.utils :refer [#?(:clj async+sync) *default-sync-translation*]
|
|
16
|
+
#?@(:cljs [:refer-macros [async+sync]])]
|
|
17
|
+
[superv.async :refer [go-try- <?-]]
|
|
18
|
+
[clojure.core.async :refer [go] :as async])
|
|
19
|
+
#?(:clj (:import [clojure.lang IDeref IAtom IMeta ILookup IRef])))
|
|
20
|
+
|
|
21
|
+
;; connection
|
|
22
|
+
|
|
23
|
+
(declare deref-conn)
|
|
24
|
+
|
|
25
|
+
(deftype Connection [wrapped-atom]
|
|
26
|
+
IDeref
|
|
27
|
+
(#?(:clj deref :cljs -deref) [conn] (deref-conn conn))
|
|
28
|
+
;; These interfaces should not be used from the outside, they are here to keep
|
|
29
|
+
;; the internal interfaces lean and working.
|
|
30
|
+
ILookup
|
|
31
|
+
(#?(:clj valAt :cljs -lookup) [c k] (if (= k :wrapped-atom) wrapped-atom nil))
|
|
32
|
+
IMeta
|
|
33
|
+
(#?(:clj meta :cljs -meta) [_] (meta wrapped-atom))
|
|
34
|
+
#?@(:cljs
|
|
35
|
+
[IAtom
|
|
36
|
+
ISwap
|
|
37
|
+
(-swap! [_ f] (swap! wrapped-atom f))
|
|
38
|
+
(-swap! [_ f arg] (swap! wrapped-atom f arg))
|
|
39
|
+
(-swap! [_ f arg1 arg2] (swap! wrapped-atom f arg1 arg2))
|
|
40
|
+
(-swap! [_ f arg1 arg2 args] (apply swap! wrapped-atom f arg1 arg2 args))
|
|
41
|
+
IReset
|
|
42
|
+
(-reset! [_ newval] (reset! wrapped-atom newval))
|
|
43
|
+
IWatchable ;; TODO This is unofficially supported, it triggers watches on each update, not on commits. For proper listeners use the API.
|
|
44
|
+
(-add-watch [_ key f] (add-watch wrapped-atom key f))
|
|
45
|
+
(-remove-watch [_ key] (remove-watch wrapped-atom key))
|
|
46
|
+
(-notify-watches [_ old new] (-notify-watches wrapped-atom old new))])
|
|
47
|
+
#?@(:clj
|
|
48
|
+
[IAtom
|
|
49
|
+
(swap [_ f] (swap! wrapped-atom f))
|
|
50
|
+
(swap [_ f arg] (swap! wrapped-atom f arg))
|
|
51
|
+
(swap [_ f arg1 arg2] (swap! wrapped-atom f arg1 arg2))
|
|
52
|
+
(swap [_ f arg1 arg2 args] (apply swap! wrapped-atom f arg1 arg2 args))
|
|
53
|
+
(compareAndSet [_ oldv newv] (compare-and-set! wrapped-atom oldv newv))
|
|
54
|
+
(reset [_ newval] (reset! wrapped-atom newval))
|
|
55
|
+
IRef ;; TODO This is unofficially supported, it triggers watches on each update, not on commits. For proper listeners use the API.
|
|
56
|
+
(addWatch [_ key f] (add-watch wrapped-atom key f))
|
|
57
|
+
(removeWatch [_ key] (remove-watch wrapped-atom key))]))
|
|
58
|
+
|
|
59
|
+
(defn connection? [x]
|
|
60
|
+
(instance? Connection x))
|
|
61
|
+
|
|
62
|
+
#?(:clj
|
|
63
|
+
(defmethod print-method Connection
|
|
64
|
+
[^Connection conn ^java.io.Writer w]
|
|
65
|
+
(let [config (:config @(:wrapped-atom conn))]
|
|
66
|
+
(.write w "#datahike/Connection")
|
|
67
|
+
(.write w (pr-str [(ds/store-identity (:store config)) (:branch config)])))))
|
|
68
|
+
|
|
69
|
+
(defn deref-conn [^Connection conn]
|
|
70
|
+
(let [wrapped-atom (.-wrapped-atom conn)]
|
|
71
|
+
(when (= @wrapped-atom :released)
|
|
72
|
+
(throw (ex-info "Connection has been released."
|
|
73
|
+
{:type :connection-has-been-released})))
|
|
74
|
+
(if (not (w/streaming? (get @wrapped-atom :writer)))
|
|
75
|
+
(let [store (:store @wrapped-atom)
|
|
76
|
+
stored (k/get store (:branch (:config @wrapped-atom)) nil {:sync? true})]
|
|
77
|
+
(log/trace "Fetched db for deref: " (:config stored))
|
|
78
|
+
(dsi/stored->db stored store))
|
|
79
|
+
@wrapped-atom)))
|
|
80
|
+
|
|
81
|
+
(defn conn-from-db
|
|
82
|
+
"Creates a mutable reference to a given immutable database. See [[create-conn]]."
|
|
83
|
+
[db]
|
|
84
|
+
(Connection. (atom db :meta {:listeners (atom {})})))
|
|
85
|
+
|
|
86
|
+
(s/def ::connection #(and (instance? Connection %)
|
|
87
|
+
(not= @(:wrapped-atom %) :released)))
|
|
88
|
+
|
|
89
|
+
(defn version-check [{:keys [meta config] :as db}]
|
|
90
|
+
(let [{dh-stored :datahike/version
|
|
91
|
+
hh-stored :hitchhiker.tree/version
|
|
92
|
+
pss-stored :persistent.set/version
|
|
93
|
+
ksv-stored :konserve/version} meta
|
|
94
|
+
{dh-now :datahike/version
|
|
95
|
+
hh-now :hitchhiker.tree/version
|
|
96
|
+
pss-now :persistent.set/version
|
|
97
|
+
ksv-now :konserve/version} (meta-data)]
|
|
98
|
+
(when-not (or (= dh-now "DEVELOPMENT")
|
|
99
|
+
(= dh-stored "DEVELOPMENT")
|
|
100
|
+
(>= (compare dh-now dh-stored) 0))
|
|
101
|
+
(dt/raise "Database was written with newer Datahike version."
|
|
102
|
+
{:type :db-was-written-with-newer-datahike-version
|
|
103
|
+
:stored dh-stored
|
|
104
|
+
:now dh-now
|
|
105
|
+
:config config}))
|
|
106
|
+
(when (and hh-stored hh-now
|
|
107
|
+
(not (>= (compare hh-now hh-stored) 0)))
|
|
108
|
+
(dt/raise "Database was written with newer hitchhiker-tree version."
|
|
109
|
+
{:type :db-was-written-with-newer-hht-version
|
|
110
|
+
:stored hh-stored
|
|
111
|
+
:now hh-now
|
|
112
|
+
:config config}))
|
|
113
|
+
(when-not (>= (compare pss-now pss-stored) 0)
|
|
114
|
+
(dt/raise "Database was written with newer persistent-sorted-set version."
|
|
115
|
+
{:type :db-was-written-with-newer-pss-version
|
|
116
|
+
:stored pss-stored
|
|
117
|
+
:now pss-now
|
|
118
|
+
:config config}))
|
|
119
|
+
(when-not (>= (compare ksv-now ksv-stored) 0)
|
|
120
|
+
(dt/raise "Database was written with newer konserve version."
|
|
121
|
+
{:type :db-was-written-with-newer-konserve-version
|
|
122
|
+
:stored ksv-stored
|
|
123
|
+
:now ksv-now
|
|
124
|
+
:config config}))))
|
|
125
|
+
|
|
126
|
+
(defn ensure-stored-config-consistency [config stored-config]
|
|
127
|
+
(let [;; Remove runtime parameters and creation-time parameters
|
|
128
|
+
config (dissoc config :name :search-cache-size :store-cache-size)
|
|
129
|
+
stored-config (dissoc stored-config :initial-tx :name :search-cache-size :store-cache-size)
|
|
130
|
+
stored-config (merge {:writer dc/self-writer} stored-config)
|
|
131
|
+
stored-config (if (empty? (:index-config stored-config))
|
|
132
|
+
(dissoc stored-config :index-config)
|
|
133
|
+
stored-config)
|
|
134
|
+
;; if we connect to remote allow writer to be different
|
|
135
|
+
[config stored-config] (if-not (= dc/self-writer config)
|
|
136
|
+
[(dissoc config :writer)
|
|
137
|
+
(dissoc stored-config :writer)]
|
|
138
|
+
[config stored-config])
|
|
139
|
+
|
|
140
|
+
;; Validate store identities match (prevents connecting to wrong database)
|
|
141
|
+
;; Store configuration details (backend, path, credentials) can differ
|
|
142
|
+
stored-store-id (get-in stored-config [:store :id])
|
|
143
|
+
connect-store-id (get-in config [:store :id])
|
|
144
|
+
_ (when (and stored-store-id connect-store-id
|
|
145
|
+
(not= stored-store-id connect-store-id))
|
|
146
|
+
(dt/raise "Store identity mismatch: connecting to wrong database."
|
|
147
|
+
{:type :store-identity-mismatch
|
|
148
|
+
:stored-id stored-store-id
|
|
149
|
+
:connect-id connect-store-id
|
|
150
|
+
:config config
|
|
151
|
+
:stored-config stored-config}))
|
|
152
|
+
|
|
153
|
+
;; Remove entire :store from comparison (backend, path, credentials can change)
|
|
154
|
+
;; Only the :id needs to match (checked above)
|
|
155
|
+
config (dissoc config :store)
|
|
156
|
+
stored-config (dissoc stored-config :store)]
|
|
157
|
+
|
|
158
|
+
(when-not (= config stored-config)
|
|
159
|
+
(dt/raise "Configuration does not match stored configuration. In some cases this check is too restrictive. If you are sure you are loading the right database with the right configuration then you can disable this check by setting :allow-unsafe-config to true in your config."
|
|
160
|
+
{:type :config-does-not-match-stored-db
|
|
161
|
+
:config config
|
|
162
|
+
:stored-config stored-config
|
|
163
|
+
:diff (diff config stored-config)}))))
|
|
164
|
+
|
|
165
|
+
(defn- normalize-config [cfg]
|
|
166
|
+
(-> cfg
|
|
167
|
+
(dissoc :writer :store :store-cache-size :search-cache-size)))
|
|
168
|
+
|
|
169
|
+
(defn -connect-impl* [config opts]
|
|
170
|
+
(async+sync (:sync? opts) *default-sync-translation*
|
|
171
|
+
(go-try-
|
|
172
|
+
(let [_ (log/debug "Using config " (update-in config [:store] dissoc :password))
|
|
173
|
+
store-config (:store config)
|
|
174
|
+
store-id (ds/store-identity store-config)
|
|
175
|
+
conn-id [store-id (:branch config)]]
|
|
176
|
+
(if-let [conn (get-connection conn-id)]
|
|
177
|
+
(let [conn-config (:config @(:wrapped-atom conn))
|
|
178
|
+
;; replace store config with its identity
|
|
179
|
+
cfg (normalize-config config)
|
|
180
|
+
conn-cfg (normalize-config conn-config)]
|
|
181
|
+
(when-not (= cfg conn-cfg)
|
|
182
|
+
(dt/raise "Configuration does not match existing connections."
|
|
183
|
+
{:type :config-does-not-match-existing-connections
|
|
184
|
+
:config cfg
|
|
185
|
+
:existing-connections-config conn-cfg
|
|
186
|
+
:diff (diff cfg conn-cfg)}))
|
|
187
|
+
conn)
|
|
188
|
+
(let [raw-store (<?- (ks/connect-store store-config opts))
|
|
189
|
+
_ (when-not raw-store
|
|
190
|
+
(dt/raise "Backend does not exist." {:type :backend-does-not-exist
|
|
191
|
+
:config store-config}))
|
|
192
|
+
store (ds/add-cache-and-handlers raw-store config)
|
|
193
|
+
_ (<?- (ds/ready-store (assoc store-config :opts opts) store))
|
|
194
|
+
stored-db (<?- (k/get store (:branch config) nil opts))
|
|
195
|
+
_ (when-not stored-db
|
|
196
|
+
(ks/release-store store-config store opts)
|
|
197
|
+
(dt/raise "Database does not exist." {:type :db-does-not-exist
|
|
198
|
+
:config config}))
|
|
199
|
+
[config store stored-db]
|
|
200
|
+
(let [intended-index (:index config)
|
|
201
|
+
stored-index (get-in stored-db [:config :index])]
|
|
202
|
+
(if-not (= intended-index stored-index)
|
|
203
|
+
(do
|
|
204
|
+
(log/warn (str "Stored index does not match configuration. Please set :index explicitly to " stored-index " in config. The default index is now :datahike/persistent-set. Using stored index setting now, but this might throw an error in the future."))
|
|
205
|
+
(let [config (assoc config :index stored-index)
|
|
206
|
+
store (ds/add-cache-and-handlers raw-store config)
|
|
207
|
+
_ (<?- (ds/ready-store (assoc store-config :opts opts) store))
|
|
208
|
+
stored-db (<?- (k/get store (:branch config) nil opts))]
|
|
209
|
+
[config store stored-db]))
|
|
210
|
+
[config store stored-db]))
|
|
211
|
+
_ (version-check stored-db)
|
|
212
|
+
_ (when-not (:allow-unsafe-config config)
|
|
213
|
+
(ensure-stored-config-consistency config (:config stored-db)))
|
|
214
|
+
conn (conn-from-db (dsi/stored->db (assoc stored-db :config config) store))]
|
|
215
|
+
(swap! (:wrapped-atom conn) assoc :writer
|
|
216
|
+
(w/create-writer (:writer config) conn))
|
|
217
|
+
(add-connection! conn-id conn)
|
|
218
|
+
conn))))))
|
|
219
|
+
|
|
220
|
+
;; Multimethod dispatch for different writer backends
|
|
221
|
+
|
|
222
|
+
(defn backend-dispatch [config & _]
|
|
223
|
+
(get-in config [:writer :backend] :self))
|
|
224
|
+
|
|
225
|
+
(defmulti -connect* #'backend-dispatch)
|
|
226
|
+
|
|
227
|
+
(defmethod -connect* :self [config opts]
|
|
228
|
+
(-connect-impl* config opts))
|
|
229
|
+
|
|
230
|
+
;; public API
|
|
231
|
+
|
|
232
|
+
(defn connect
|
|
233
|
+
"Connect to a Datahike database.
|
|
234
|
+
|
|
235
|
+
Config can be a map or URI string. Opts map supports:
|
|
236
|
+
- :sync? (default true) - Block and return connection, or return channel for async"
|
|
237
|
+
([] (connect {} {}))
|
|
238
|
+
([config] (connect config {}))
|
|
239
|
+
([config opts]
|
|
240
|
+
(let [opts (merge {:sync? true} opts)
|
|
241
|
+
normalized (cond
|
|
242
|
+
(string? config) (dc/uri->config config)
|
|
243
|
+
(map? config) config
|
|
244
|
+
:else config)
|
|
245
|
+
loaded (dissoc (dc/load-config normalized) :initial-tx :remote-peer :name)]
|
|
246
|
+
(-connect* loaded opts))))
|
|
247
|
+
|
|
248
|
+
(defn release
|
|
249
|
+
([connection] (release connection false))
|
|
250
|
+
([connection release-all?]
|
|
251
|
+
(when-not (= @(:wrapped-atom connection) :released)
|
|
252
|
+
(let [db @(:wrapped-atom connection)
|
|
253
|
+
_ (log/info "Releasing connection, config store backend:"
|
|
254
|
+
(get-in db [:config :store :backend]))
|
|
255
|
+
conn-id [(ds/store-identity (get-in db [:config :store]))
|
|
256
|
+
(get-in db [:config :branch])]]
|
|
257
|
+
(if-not (get @*connections* conn-id)
|
|
258
|
+
(log/info "Connection already released." conn-id)
|
|
259
|
+
(let [new-conns (swap! *connections* update-in [conn-id :count] dec)]
|
|
260
|
+
(when (or release-all? (zero? (get-in new-conns [conn-id :count])))
|
|
261
|
+
(delete-connection! conn-id)
|
|
262
|
+
(w/shutdown (:writer db))
|
|
263
|
+
;; Release the underlying store to clean up resources (memory registry, etc.)
|
|
264
|
+
(ks/release-store (get-in db [:config :store]) (:store db))
|
|
265
|
+
nil)))))))
|