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,121 @@
|
|
|
1
|
+
package examples;
|
|
2
|
+
|
|
3
|
+
import datahike.java.Datahike;
|
|
4
|
+
import datahike.java.Database;
|
|
5
|
+
import datahike.java.SchemaFlexibility;
|
|
6
|
+
|
|
7
|
+
import java.time.Instant;
|
|
8
|
+
import java.util.*;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Example demonstrating time-travel queries.
|
|
12
|
+
*
|
|
13
|
+
* Shows:
|
|
14
|
+
* - Querying historical database states
|
|
15
|
+
* - Using asOf for point-in-time queries
|
|
16
|
+
* - Using since for change tracking
|
|
17
|
+
* - Querying full history with all versions
|
|
18
|
+
*/
|
|
19
|
+
public class TimeTravelExample {
|
|
20
|
+
public static void main(String[] args) throws InterruptedException {
|
|
21
|
+
System.out.println("=== Time Travel Example ===\n");
|
|
22
|
+
|
|
23
|
+
// Configure database with history enabled
|
|
24
|
+
Map<String, Object> config = Database.memory(UUID.randomUUID())
|
|
25
|
+
.keepHistory(true)
|
|
26
|
+
.schemaFlexibility(SchemaFlexibility.READ)
|
|
27
|
+
.build();
|
|
28
|
+
|
|
29
|
+
Datahike.createDatabase(config);
|
|
30
|
+
Object conn = Datahike.connect(config);
|
|
31
|
+
|
|
32
|
+
// 1. Initial state - add Alice
|
|
33
|
+
System.out.println("1. Initial state - adding Alice...");
|
|
34
|
+
Datahike.transact(conn, List.of(
|
|
35
|
+
Map.of("name", "Alice", "status", "active")
|
|
36
|
+
));
|
|
37
|
+
|
|
38
|
+
Date t1 = new Date();
|
|
39
|
+
System.out.println("Timestamp T1: " + t1);
|
|
40
|
+
|
|
41
|
+
Thread.sleep(100); // Small delay for distinct timestamps
|
|
42
|
+
|
|
43
|
+
// 2. Add Bob
|
|
44
|
+
System.out.println("\n2. Adding Bob...");
|
|
45
|
+
Datahike.transact(conn, List.of(
|
|
46
|
+
Map.of("name", "Bob", "status", "active")
|
|
47
|
+
));
|
|
48
|
+
|
|
49
|
+
Date t2 = new Date();
|
|
50
|
+
System.out.println("Timestamp T2: " + t2);
|
|
51
|
+
|
|
52
|
+
Thread.sleep(100);
|
|
53
|
+
|
|
54
|
+
// 3. Update Alice's status
|
|
55
|
+
System.out.println("\n3. Updating Alice's status...");
|
|
56
|
+
Set<?> aliceResult = (Set<?>) Datahike.q(
|
|
57
|
+
"[:find ?e :where [?e :name \"Alice\"]]",
|
|
58
|
+
Datahike.deref(conn)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
Object aliceId = ((List<?>) aliceResult.iterator().next()).get(0);
|
|
62
|
+
Datahike.transact(conn, List.of(
|
|
63
|
+
Map.of(":db/id", aliceId, "status", "inactive")
|
|
64
|
+
));
|
|
65
|
+
|
|
66
|
+
Date t3 = new Date();
|
|
67
|
+
System.out.println("Timestamp T3: " + t3);
|
|
68
|
+
|
|
69
|
+
// 4. Query current state
|
|
70
|
+
System.out.println("\n4. Current state:");
|
|
71
|
+
Set<?> currentState = (Set<?>) Datahike.q(
|
|
72
|
+
"[:find ?name ?status :where [?e :name ?name] [?e :status ?status]]",
|
|
73
|
+
Datahike.deref(conn)
|
|
74
|
+
);
|
|
75
|
+
currentState.forEach(System.out::println);
|
|
76
|
+
|
|
77
|
+
// 5. Query as of T1 (only Alice existed)
|
|
78
|
+
System.out.println("\n5. State as of T1 (only Alice):");
|
|
79
|
+
Object dbAtT1 = Datahike.asOf(Datahike.deref(conn), t1);
|
|
80
|
+
Set<?> stateAtT1 = (Set<?>) Datahike.q(
|
|
81
|
+
"[:find ?name ?status :where [?e :name ?name] [?e :status ?status]]",
|
|
82
|
+
dbAtT1
|
|
83
|
+
);
|
|
84
|
+
stateAtT1.forEach(System.out::println);
|
|
85
|
+
|
|
86
|
+
// 6. Query as of T2 (both existed, Alice was active)
|
|
87
|
+
System.out.println("\n6. State as of T2 (both, Alice active):");
|
|
88
|
+
Object dbAtT2 = Datahike.asOf(Datahike.deref(conn), t2);
|
|
89
|
+
Set<?> stateAtT2 = (Set<?>) Datahike.q(
|
|
90
|
+
"[:find ?name ?status :where [?e :name ?name] [?e :status ?status]]",
|
|
91
|
+
dbAtT2
|
|
92
|
+
);
|
|
93
|
+
stateAtT2.forEach(System.out::println);
|
|
94
|
+
|
|
95
|
+
// 7. Query changes since T2
|
|
96
|
+
System.out.println("\n7. Changes since T2:");
|
|
97
|
+
Object dbSinceT2 = Datahike.since(Datahike.deref(conn), t2);
|
|
98
|
+
Set<?> changesSinceT2 = (Set<?>) Datahike.q(
|
|
99
|
+
"[:find ?name ?status :where [?e :name ?name] [?e :status ?status]]",
|
|
100
|
+
dbSinceT2
|
|
101
|
+
);
|
|
102
|
+
System.out.println("Changed entities:");
|
|
103
|
+
changesSinceT2.forEach(System.out::println);
|
|
104
|
+
|
|
105
|
+
// 8. Query full history (includes all versions)
|
|
106
|
+
System.out.println("\n8. Full history of Alice's status:");
|
|
107
|
+
Object historyDb = Datahike.history(Datahike.deref(conn));
|
|
108
|
+
Set<?> aliceHistory = (Set<?>) Datahike.q(
|
|
109
|
+
"[:find ?status :where [?e :name \"Alice\"] [?e :status ?status]]",
|
|
110
|
+
historyDb
|
|
111
|
+
);
|
|
112
|
+
System.out.println("All status values for Alice:");
|
|
113
|
+
aliceHistory.forEach(System.out::println);
|
|
114
|
+
|
|
115
|
+
// Cleanup
|
|
116
|
+
Datahike.deleteDatabase(config);
|
|
117
|
+
|
|
118
|
+
System.out.println("\n=== Example completed successfully! ===");
|
|
119
|
+
System.exit(0);
|
|
120
|
+
}
|
|
121
|
+
}
|
package/flake.lock
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nodes": {
|
|
3
|
+
"nixpkgs": {
|
|
4
|
+
"locked": {
|
|
5
|
+
"lastModified": 1752950548,
|
|
6
|
+
"narHash": "sha256-NS6BLD0lxOrnCiEOcvQCDVPXafX1/ek1dfJHX1nUIzc=",
|
|
7
|
+
"owner": "nixos",
|
|
8
|
+
"repo": "nixpkgs",
|
|
9
|
+
"rev": "c87b95e25065c028d31a94f06a62927d18763fdf",
|
|
10
|
+
"type": "github"
|
|
11
|
+
},
|
|
12
|
+
"original": {
|
|
13
|
+
"owner": "nixos",
|
|
14
|
+
"ref": "nixos-unstable",
|
|
15
|
+
"repo": "nixpkgs",
|
|
16
|
+
"type": "github"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"root": {
|
|
20
|
+
"inputs": {
|
|
21
|
+
"nixpkgs": "nixpkgs"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"root": "root",
|
|
26
|
+
"version": 7
|
|
27
|
+
}
|
package/flake.nix
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
inputs = {
|
|
3
|
+
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
outputs = { self, nixpkgs }:
|
|
7
|
+
let
|
|
8
|
+
lib = nixpkgs.lib;
|
|
9
|
+
allSystems = [
|
|
10
|
+
"aarch64-darwin"
|
|
11
|
+
"aarch64-linux"
|
|
12
|
+
"x86_64-linux"
|
|
13
|
+
];
|
|
14
|
+
pkgsFor = lib.genAttrs allSystems (system: import nixpkgs { inherit system; config.allowUnfree = true; });
|
|
15
|
+
overEachSystem = f: lib.genAttrs allSystems (system: f { inherit system; pkgs = pkgsFor.${system}; });
|
|
16
|
+
in {
|
|
17
|
+
formatter = overEachSystem ({ system, pkgs }: pkgs.nixfmt-rcf-style);
|
|
18
|
+
devShells = overEachSystem ({ system, pkgs }: {
|
|
19
|
+
default = pkgs.mkShellNoCC {
|
|
20
|
+
packages = [
|
|
21
|
+
pkgs.clojure
|
|
22
|
+
pkgs.babashka
|
|
23
|
+
];
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
(ns datahike.http.middleware
|
|
2
|
+
(:require
|
|
3
|
+
[buddy.auth :refer [authenticated?]]
|
|
4
|
+
[buddy.auth.backends :as buddy-auth-backends]
|
|
5
|
+
[buddy.auth.middleware :as buddy-auth-middleware]
|
|
6
|
+
[clojure.edn :as edn]
|
|
7
|
+
[clojure.walk :as cw]
|
|
8
|
+
[datahike.json :as json]
|
|
9
|
+
[datahike.readers :refer [edn-readers]]
|
|
10
|
+
[muuntaja.core :as m]
|
|
11
|
+
[taoensso.timbre :refer [info trace]])
|
|
12
|
+
(:import
|
|
13
|
+
[clojure.lang ExceptionInfo]))
|
|
14
|
+
|
|
15
|
+
(defn auth
|
|
16
|
+
"Middleware used in routes that require authentication. If request is not
|
|
17
|
+
authenticated a 401 not authorized response will be returned.
|
|
18
|
+
Dev mode always authenticates."
|
|
19
|
+
[config handler]
|
|
20
|
+
(fn [request]
|
|
21
|
+
(if (or (:dev-mode config) (authenticated? request))
|
|
22
|
+
(handler request)
|
|
23
|
+
{:status 401 :error "Not authorized"})))
|
|
24
|
+
|
|
25
|
+
(defn token-auth
|
|
26
|
+
"Middleware used on routes requiring token authentication"
|
|
27
|
+
[config handler]
|
|
28
|
+
(buddy-auth-middleware/wrap-authentication
|
|
29
|
+
handler
|
|
30
|
+
(buddy-auth-backends/token {:token-name "token"
|
|
31
|
+
:authfn (fn [_ token]
|
|
32
|
+
(let [valid-token? (not (nil? token))
|
|
33
|
+
correct-auth? (= (:token config) token)]
|
|
34
|
+
(when (and correct-auth? valid-token?)
|
|
35
|
+
"authenticated-user")))})))
|
|
36
|
+
|
|
37
|
+
;; TOOD map more errors
|
|
38
|
+
(defn cause->status-code [cause]
|
|
39
|
+
400)
|
|
40
|
+
|
|
41
|
+
(defn encode-plain-value [muuntaja-with-opts]
|
|
42
|
+
(fn [handler]
|
|
43
|
+
(fn [request]
|
|
44
|
+
(let [format (:content-type request)
|
|
45
|
+
encoder (m/encoder muuntaja-with-opts format)
|
|
46
|
+
response (handler request)
|
|
47
|
+
ret (if (not (instance? java.io.ByteArrayInputStream (:body response)))
|
|
48
|
+
(update response :body #(encoder %))
|
|
49
|
+
response)]
|
|
50
|
+
ret))))
|
|
51
|
+
|
|
52
|
+
(defn patch-swagger-json [handler]
|
|
53
|
+
(fn [request]
|
|
54
|
+
(let [response (handler request)]
|
|
55
|
+
(if (get-in response [:body :swagger])
|
|
56
|
+
(cw/postwalk (fn [n]
|
|
57
|
+
(if (set? n) (vec n) n))
|
|
58
|
+
response)
|
|
59
|
+
response))))
|
|
60
|
+
|
|
61
|
+
(defn support-embedded-edn-in-json [handler]
|
|
62
|
+
(fn [request]
|
|
63
|
+
(let [{:keys [content-type body-params uri]} request]
|
|
64
|
+
(if (= content-type "application/json")
|
|
65
|
+
(if (.endsWith ^String uri "transact")
|
|
66
|
+
(let [[conn tx-data] body-params
|
|
67
|
+
new-body-params [conn (json/xf-data-for-tx tx-data @conn)]]
|
|
68
|
+
(trace "transact transformation" new-body-params)
|
|
69
|
+
(handler (assoc request :body-params new-body-params)))
|
|
70
|
+
(let [[f & r] body-params
|
|
71
|
+
new-body-params (vec (concat [(if (string? f) (edn/read-string {:readers edn-readers} f) f)] r))]
|
|
72
|
+
(trace "old-body-params" body-params)
|
|
73
|
+
(trace "new-body-params" new-body-params)
|
|
74
|
+
(handler (assoc request :body-params new-body-params))))
|
|
75
|
+
(handler request)))))
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
(ns datahike.http.server
|
|
2
|
+
"HTTP server implementation for Datahike."
|
|
3
|
+
(:gen-class)
|
|
4
|
+
(:refer-clojure :exclude [read-string filter])
|
|
5
|
+
(:require
|
|
6
|
+
[clojure.string :as str]
|
|
7
|
+
[clojure.edn :as edn]
|
|
8
|
+
[clojure.core.async :as async]
|
|
9
|
+
[datahike.connections :refer [*connections*]]
|
|
10
|
+
[datahike.api.specification :refer [api-specification ->url]]
|
|
11
|
+
[datahike.api.types :as types]
|
|
12
|
+
[datahike.http.middleware :as middleware]
|
|
13
|
+
[datahike.readers :refer [edn-readers]]
|
|
14
|
+
[datahike.transit :as transit]
|
|
15
|
+
[datahike.json :as json]
|
|
16
|
+
[datahike.api :refer :all :as api]
|
|
17
|
+
[datahike.writing]
|
|
18
|
+
[datahike.writer]
|
|
19
|
+
[reitit.ring :as ring]
|
|
20
|
+
[reitit.coercion.malli]
|
|
21
|
+
[malli.util :as mu]
|
|
22
|
+
[reitit.swagger :as swagger]
|
|
23
|
+
[reitit.swagger-ui :as swagger-ui]
|
|
24
|
+
[reitit.ring.coercion :as coercion]
|
|
25
|
+
[reitit.ring.middleware.muuntaja :as muuntaja]
|
|
26
|
+
[reitit.ring.middleware.exception :as exception]
|
|
27
|
+
[reitit.ring.middleware.multipart :as multipart]
|
|
28
|
+
[reitit.ring.middleware.parameters :as parameters]
|
|
29
|
+
[ring.middleware.cors :refer [wrap-cors]]
|
|
30
|
+
[muuntaja.core :as m]
|
|
31
|
+
[datahike.tools :refer [datahike-version]]
|
|
32
|
+
[datahike.impl.entity :as de]
|
|
33
|
+
[taoensso.timbre :as log]
|
|
34
|
+
[ring.adapter.jetty :refer [run-jetty]])
|
|
35
|
+
(:import [datahike.datom Datom]))
|
|
36
|
+
|
|
37
|
+
(defn generic-handler [config f]
|
|
38
|
+
(fn [request]
|
|
39
|
+
(try
|
|
40
|
+
(let [{{body :body} :parameters
|
|
41
|
+
:keys [headers params method]} request
|
|
42
|
+
_ (log/trace "request body" f body)
|
|
43
|
+
;; TODO move this to client
|
|
44
|
+
ret-body
|
|
45
|
+
(cond (= f #'api/create-database)
|
|
46
|
+
;; remove remote-peer and re-add
|
|
47
|
+
(assoc
|
|
48
|
+
(apply f (dissoc (first body) :remote-peer) (rest body))
|
|
49
|
+
:remote-peer (:remote-peer (first body)))
|
|
50
|
+
|
|
51
|
+
(= f #'api/delete-database)
|
|
52
|
+
(apply f (dissoc (first body) :remote-peer) (rest body))
|
|
53
|
+
|
|
54
|
+
:else
|
|
55
|
+
(apply f body))]
|
|
56
|
+
(log/trace "return body" ret-body)
|
|
57
|
+
(merge
|
|
58
|
+
{:status 200
|
|
59
|
+
:body
|
|
60
|
+
(when-not (headers "no-return-value")
|
|
61
|
+
ret-body)}
|
|
62
|
+
(when (and (= method :get)
|
|
63
|
+
(get params "args-id")
|
|
64
|
+
(get-in config [:cache :get :max-age]))
|
|
65
|
+
{:headers {"Cache-Control" (str (when-not (:token config) "public, ")
|
|
66
|
+
"max-age=" (get-in config [:cache :get :max-age]))}})))
|
|
67
|
+
(catch Exception e
|
|
68
|
+
{:status 500
|
|
69
|
+
:body {:msg (ex-message e)
|
|
70
|
+
:ex-data (ex-data e)}}))))
|
|
71
|
+
|
|
72
|
+
(declare create-routes)
|
|
73
|
+
|
|
74
|
+
(defn extract-first-sentence [doc]
|
|
75
|
+
(str (first (str/split doc #"\.\s")) "."))
|
|
76
|
+
|
|
77
|
+
(defn has-cat-operators?
|
|
78
|
+
"Check if args list contains :cat-specific operators like [:* ...], [:+ ...], [:alt ...], etc.
|
|
79
|
+
These operators are only valid in :cat schemas, not in :tuple schemas."
|
|
80
|
+
[args]
|
|
81
|
+
(some #(and (vector? %) (#{:* :+ :? :alt :altn} (first %))) args))
|
|
82
|
+
|
|
83
|
+
(defn extract-input-schema
|
|
84
|
+
"Extract input schema from malli function schema for HTTP body validation.
|
|
85
|
+
Converts [:=> [:cat Type1 Type2] ret] to [:tuple Type1 Type2]
|
|
86
|
+
or [:function [:=> [:cat T1] ret] [:=> [:cat T1 T2] ret]] to [:or [:tuple T1] [:tuple T1 T2]]
|
|
87
|
+
|
|
88
|
+
The HTTP body is a tuple/vector of arguments that matches the function signature.
|
|
89
|
+
For zero-arity functions, we use [:= []] to match an empty vector.
|
|
90
|
+
For functions with :cat operators ([:* ...], [:alt ...], etc), we use [:sequential :any]
|
|
91
|
+
since tuples can't express these dynamic patterns."
|
|
92
|
+
[schema]
|
|
93
|
+
(cond
|
|
94
|
+
;; Multi-arity: [:function [:=> [:cat ...] ret] ...]
|
|
95
|
+
(and (vector? schema) (= :function (first schema)))
|
|
96
|
+
(let [input-schemas (for [arity-schema (rest schema)
|
|
97
|
+
:when (and (vector? arity-schema)
|
|
98
|
+
(= :=> (first arity-schema)))
|
|
99
|
+
:let [[_ input-schema _] arity-schema
|
|
100
|
+
args (when (and (vector? input-schema)
|
|
101
|
+
(= :cat (first input-schema)))
|
|
102
|
+
(rest input-schema))]]
|
|
103
|
+
(cond
|
|
104
|
+
(not (seq args)) [:= []] ;; Zero-arity
|
|
105
|
+
(has-cat-operators? args) [:sequential :any] ;; Has :cat operators - can't use tuple
|
|
106
|
+
:else (vec (cons :tuple args))))] ;; Fixed arity
|
|
107
|
+
(if (> (count input-schemas) 1)
|
|
108
|
+
(vec (cons :or input-schemas))
|
|
109
|
+
(first input-schemas)))
|
|
110
|
+
|
|
111
|
+
;; Single arity: [:=> [:cat Type1 Type2] ret]
|
|
112
|
+
(and (vector? schema) (= :=> (first schema)))
|
|
113
|
+
(let [[_ input-schema _] schema]
|
|
114
|
+
(if (and (vector? input-schema) (= :cat (first input-schema)))
|
|
115
|
+
(let [args (rest input-schema)]
|
|
116
|
+
(cond
|
|
117
|
+
(not (seq args)) [:= []] ;; Zero-arity
|
|
118
|
+
(has-cat-operators? args) [:sequential :any] ;; Has :cat operators
|
|
119
|
+
:else (vec (cons :tuple args)))) ;; Fixed arity
|
|
120
|
+
[:sequential :any]))
|
|
121
|
+
|
|
122
|
+
;; Fallback
|
|
123
|
+
:else [:sequential :any]))
|
|
124
|
+
|
|
125
|
+
;; This code expands and evals the server route construction given the
|
|
126
|
+
;; API specification.
|
|
127
|
+
(eval
|
|
128
|
+
`(defn ~'create-routes [~'config]
|
|
129
|
+
~(vec
|
|
130
|
+
(for [[n {:keys [args doc supports-remote? referentially-transparent?]}] api-specification
|
|
131
|
+
:when supports-remote?]
|
|
132
|
+
`[~(str "/" (->url n))
|
|
133
|
+
{:swagger {:tags ["API"]}
|
|
134
|
+
~(if referentially-transparent? :get :post)
|
|
135
|
+
{:operationId ~(str n)
|
|
136
|
+
:summary ~(extract-first-sentence doc)
|
|
137
|
+
:description ~doc
|
|
138
|
+
:parameters {:body ~(extract-input-schema args)}
|
|
139
|
+
:handler (generic-handler ~'config ~(resolve n))}}]))))
|
|
140
|
+
|
|
141
|
+
(def muuntaja-with-opts
|
|
142
|
+
(m/create
|
|
143
|
+
(-> m/default-options
|
|
144
|
+
(assoc-in [:formats "application/edn" :decoder-opts]
|
|
145
|
+
{:readers edn-readers})
|
|
146
|
+
(assoc-in [:formats "application/json" :decoder-opts]
|
|
147
|
+
json/mapper-opts)
|
|
148
|
+
(assoc-in [:formats "application/json" :encoder-opts]
|
|
149
|
+
json/mapper-opts)
|
|
150
|
+
(assoc-in [:formats "application/transit+json" :decoder-opts]
|
|
151
|
+
{:handlers transit/read-handlers})
|
|
152
|
+
(assoc-in [:formats "application/transit+json" :encoder-opts]
|
|
153
|
+
{:handlers transit/write-handlers}))))
|
|
154
|
+
|
|
155
|
+
(defn default-route-opts [muuntaja-with-opts]
|
|
156
|
+
{:data {:coercion (reitit.coercion.malli/create
|
|
157
|
+
{:compile mu/closed-schema
|
|
158
|
+
:strip-extra-keys true
|
|
159
|
+
:default-values true
|
|
160
|
+
:options {:registry types/registry}})
|
|
161
|
+
:muuntaja muuntaja-with-opts
|
|
162
|
+
:middleware [swagger/swagger-feature
|
|
163
|
+
parameters/parameters-middleware
|
|
164
|
+
muuntaja/format-negotiate-middleware
|
|
165
|
+
muuntaja/format-response-middleware
|
|
166
|
+
exception/exception-middleware
|
|
167
|
+
muuntaja/format-request-middleware
|
|
168
|
+
(middleware/encode-plain-value muuntaja-with-opts)
|
|
169
|
+
middleware/support-embedded-edn-in-json
|
|
170
|
+
coercion/coerce-response-middleware
|
|
171
|
+
coercion/coerce-request-middleware
|
|
172
|
+
multipart/multipart-middleware
|
|
173
|
+
middleware/patch-swagger-json]}})
|
|
174
|
+
|
|
175
|
+
(defn internal-writer-routes [server-connections]
|
|
176
|
+
[["/delete-database-writer"
|
|
177
|
+
{:post {:parameters {:body [:sequential :any]},
|
|
178
|
+
:summary "Internal endpoint. DO NOT USE!"
|
|
179
|
+
:no-doc true
|
|
180
|
+
:handler (fn [{{:keys [body]} :parameters}]
|
|
181
|
+
(binding [*connections* server-connections]
|
|
182
|
+
(let [cfg (dissoc (first body) :remote-peer :writer)]
|
|
183
|
+
(try
|
|
184
|
+
(try
|
|
185
|
+
(api/release (api/connect cfg) true)
|
|
186
|
+
(catch Exception _))
|
|
187
|
+
{:status 200
|
|
188
|
+
:body (async/<!! (apply datahike.writing/delete-database cfg (rest body)))}
|
|
189
|
+
(catch Exception e
|
|
190
|
+
{:status 500
|
|
191
|
+
:body {:msg (ex-message e)
|
|
192
|
+
:ex-data (ex-data e)}})))))
|
|
193
|
+
:operationId "delete-database"},
|
|
194
|
+
:swagger {:tags ["Internal"]}}]
|
|
195
|
+
["/create-database-writer"
|
|
196
|
+
{:post {:parameters {:body [:sequential :any]},
|
|
197
|
+
:summary "Internal endpoint. DO NOT USE!"
|
|
198
|
+
:no-doc true
|
|
199
|
+
:handler (fn [{{:keys [body]} :parameters}]
|
|
200
|
+
(let [cfg (dissoc (first body) :remote-peer :writer)]
|
|
201
|
+
(try
|
|
202
|
+
{:status 200
|
|
203
|
+
:body (async/<!! (apply datahike.writing/create-database
|
|
204
|
+
cfg
|
|
205
|
+
(rest body)))}
|
|
206
|
+
(catch Exception e
|
|
207
|
+
{:status 500
|
|
208
|
+
:body {:msg (ex-message e)
|
|
209
|
+
:ex-data (ex-data e)}}))))
|
|
210
|
+
:operationId "create-database"},
|
|
211
|
+
:swagger {:tags ["Internal"]}}]
|
|
212
|
+
["/transact!-writer"
|
|
213
|
+
{:post {:parameters {:body [:sequential :any]},
|
|
214
|
+
:summary "Internal endpoint. DO NOT USE!"
|
|
215
|
+
:no-doc true
|
|
216
|
+
:handler (fn [{{:keys [body]} :parameters}]
|
|
217
|
+
(binding [*connections* server-connections]
|
|
218
|
+
(try
|
|
219
|
+
(let [conn (api/connect (dissoc (first body) :remote-peer :writer)) ;; TODO maybe release?
|
|
220
|
+
res @(apply datahike.writer/transact! conn (rest body))]
|
|
221
|
+
{:status 200
|
|
222
|
+
:body res})
|
|
223
|
+
(catch Exception e
|
|
224
|
+
{:status 500
|
|
225
|
+
:body {:msg (ex-message e)
|
|
226
|
+
:ex-data (ex-data e)}}))))
|
|
227
|
+
:operationId "transact"},
|
|
228
|
+
:swagger {:tags ["Internal"]}}]])
|
|
229
|
+
|
|
230
|
+
(defn app [config route-opts server-connections]
|
|
231
|
+
(-> (ring/ring-handler
|
|
232
|
+
(ring/router
|
|
233
|
+
(concat
|
|
234
|
+
[["/swagger.json"
|
|
235
|
+
{:get {:no-doc true
|
|
236
|
+
:swagger {:info {:title "Datahike API"
|
|
237
|
+
:description "Transaction and query functions for Datahike.\n\nThe signatures match those of the Clojure API. All functions take their arguments passed as a vector/list in the POST request body."}}
|
|
238
|
+
:handler (swagger/create-swagger-handler)}}]]
|
|
239
|
+
(map (fn [route]
|
|
240
|
+
(let [method (if (:get (second route)) :get :post)]
|
|
241
|
+
(assoc-in route [1 method :middleware]
|
|
242
|
+
[(partial middleware/token-auth config)
|
|
243
|
+
(partial middleware/auth config)])))
|
|
244
|
+
(concat (create-routes config)
|
|
245
|
+
(internal-writer-routes server-connections)))) route-opts)
|
|
246
|
+
(ring/routes
|
|
247
|
+
(swagger-ui/create-swagger-ui-handler
|
|
248
|
+
{:path "/"
|
|
249
|
+
:config {:validatorUrl nil
|
|
250
|
+
:operationsSorter "alpha"}})
|
|
251
|
+
(ring/create-default-handler)))
|
|
252
|
+
(wrap-cors :access-control-allow-origin (or (:access-control-allow-origin config)
|
|
253
|
+
[#"http://localhost" #"http://localhost:8080"])
|
|
254
|
+
:access-control-allow-methods [:get :put :post :delete])))
|
|
255
|
+
|
|
256
|
+
(defn start-server [config]
|
|
257
|
+
(run-jetty (app config (default-route-opts muuntaja-with-opts) (atom {})) config))
|
|
258
|
+
|
|
259
|
+
(defn stop-server [^org.eclipse.jetty.server.Server server]
|
|
260
|
+
(.stop server))
|
|
261
|
+
|
|
262
|
+
(defn -main [& args]
|
|
263
|
+
(let [{:keys [level token] :as config} (edn/read-string (slurp (first args)))]
|
|
264
|
+
(when level (log/set-level! level))
|
|
265
|
+
(when (#{:trace :debug :info nil} level)
|
|
266
|
+
(println "Datahike HTTP Server" datahike-version "- https://datahike.io"))
|
|
267
|
+
(log/info "Config:" (if token (assoc config :token "REDACTED") config))
|
|
268
|
+
(start-server config)
|
|
269
|
+
(log/info "Server started.")))
|