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
package/doc/java-api.md
ADDED
|
@@ -0,0 +1,808 @@
|
|
|
1
|
+
# Datahike Java API
|
|
2
|
+
|
|
3
|
+
**Status: Beta** - The Java API is functional and tested, but may receive breaking changes as we gather feedback from production use.
|
|
4
|
+
|
|
5
|
+
Datahike provides a comprehensive Java API that enables you to use the full power of Datalog databases from Java applications without writing Clojure code. The API offers both high-level convenience methods and low-level access for advanced use cases.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Type-Safe Configuration** - Fluent builder pattern with compile-time checks
|
|
10
|
+
- **Modern Java API** - Works with Java Maps, UUIDs, and standard collections
|
|
11
|
+
- **Full Datalog Support** - Expressive declarative queries with joins, aggregates, and rules
|
|
12
|
+
- **Time Travel** - Query database history and point-in-time snapshots
|
|
13
|
+
- **Pull API** - Recursive pattern-based entity retrieval
|
|
14
|
+
- **Schema Support** - Optional strict or flexible schema enforcement
|
|
15
|
+
- **Multiple Backends** - Memory, file system, and extensible to custom stores
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
### Maven
|
|
20
|
+
|
|
21
|
+
Add the Clojars repository and Datahike dependency to your `pom.xml`:
|
|
22
|
+
|
|
23
|
+
```xml
|
|
24
|
+
<repositories>
|
|
25
|
+
<repository>
|
|
26
|
+
<id>clojars</id>
|
|
27
|
+
<name>Clojars</name>
|
|
28
|
+
<url>https://repo.clojars.org/</url>
|
|
29
|
+
</repository>
|
|
30
|
+
</repositories>
|
|
31
|
+
|
|
32
|
+
<dependencies>
|
|
33
|
+
<dependency>
|
|
34
|
+
<groupId>org.replikativ</groupId>
|
|
35
|
+
<artifactId>datahike</artifactId>
|
|
36
|
+
<version>CURRENT</version> <!-- Check https://clojars.org/org.replikativ/datahike for latest -->
|
|
37
|
+
</dependency>
|
|
38
|
+
</dependencies>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Gradle
|
|
42
|
+
|
|
43
|
+
Add to your `build.gradle`:
|
|
44
|
+
|
|
45
|
+
```gradle
|
|
46
|
+
repositories {
|
|
47
|
+
maven { url "https://repo.clojars.org/" }
|
|
48
|
+
mavenCentral()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
dependencies {
|
|
52
|
+
implementation 'org.replikativ:datahike:CURRENT' // Check https://clojars.org/org.replikativ/datahike for latest
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```java
|
|
59
|
+
import datahike.java.Datahike;
|
|
60
|
+
import datahike.java.Database;
|
|
61
|
+
import datahike.java.SchemaFlexibility;
|
|
62
|
+
import java.util.*;
|
|
63
|
+
|
|
64
|
+
// Create and connect to database
|
|
65
|
+
Map<String, Object> config = Database.memory(UUID.randomUUID())
|
|
66
|
+
.schemaFlexibility(SchemaFlexibility.READ)
|
|
67
|
+
.build();
|
|
68
|
+
|
|
69
|
+
Datahike.createDatabase(config);
|
|
70
|
+
Object conn = Datahike.connect(config);
|
|
71
|
+
|
|
72
|
+
// Transact data using Java Maps
|
|
73
|
+
Datahike.transact(conn, List.of(
|
|
74
|
+
Map.of("name", "Alice", "age", 30),
|
|
75
|
+
Map.of("name", "Bob", "age", 25)
|
|
76
|
+
));
|
|
77
|
+
|
|
78
|
+
// Query with Datalog
|
|
79
|
+
Set<?> results = (Set<?>) Datahike.q(
|
|
80
|
+
"[:find ?name ?age :where [?e :name ?name] [?e :age ?age]]",
|
|
81
|
+
Datahike.deref(conn)
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
System.out.println(results);
|
|
85
|
+
// => #{["Alice" 30] ["Bob" 25]}
|
|
86
|
+
|
|
87
|
+
// Cleanup
|
|
88
|
+
Datahike.deleteDatabase(config);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Configuration
|
|
92
|
+
|
|
93
|
+
Datahike offers three approaches to configuration, each suited for different needs.
|
|
94
|
+
|
|
95
|
+
### Approach 1: Database Builder (Recommended)
|
|
96
|
+
|
|
97
|
+
The fluent builder pattern provides type safety and IDE autocompletion:
|
|
98
|
+
|
|
99
|
+
```java
|
|
100
|
+
import datahike.java.Database;
|
|
101
|
+
import datahike.java.SchemaFlexibility;
|
|
102
|
+
import java.util.UUID;
|
|
103
|
+
|
|
104
|
+
// In-memory database (requires UUID)
|
|
105
|
+
Map<String, Object> config = Database.memory(UUID.randomUUID())
|
|
106
|
+
.keepHistory(true)
|
|
107
|
+
.schemaFlexibility(SchemaFlexibility.READ)
|
|
108
|
+
.build();
|
|
109
|
+
|
|
110
|
+
// File-based database
|
|
111
|
+
Map<String, Object> config = Database.file("/var/lib/mydb")
|
|
112
|
+
.keepHistory(true)
|
|
113
|
+
.name("production-db")
|
|
114
|
+
.build();
|
|
115
|
+
|
|
116
|
+
// With initial schema
|
|
117
|
+
import static datahike.java.Keywords.*;
|
|
118
|
+
import static datahike.java.Util.*;
|
|
119
|
+
|
|
120
|
+
Object schema = vec(
|
|
121
|
+
map(DB_IDENT, kwd(":person/name"),
|
|
122
|
+
DB_VALUE_TYPE, STRING,
|
|
123
|
+
DB_CARDINALITY, ONE)
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
Map<String, Object> config = Database.memory(UUID.randomUUID())
|
|
127
|
+
.initialTx(schema)
|
|
128
|
+
.build();
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**When to use:** New projects, when you want type safety and clear code.
|
|
132
|
+
|
|
133
|
+
### Approach 2: Java Maps
|
|
134
|
+
|
|
135
|
+
Use standard Java collections with string keys (automatically converted to Clojure keywords):
|
|
136
|
+
|
|
137
|
+
```java
|
|
138
|
+
import java.util.*;
|
|
139
|
+
|
|
140
|
+
// Configuration with nested maps
|
|
141
|
+
Map<String, Object> config = Map.of(
|
|
142
|
+
"store", Map.of(
|
|
143
|
+
"backend", ":memory", // : prefix makes it a keyword
|
|
144
|
+
"id", UUID.randomUUID()
|
|
145
|
+
),
|
|
146
|
+
"schema-flexibility", ":read",
|
|
147
|
+
"keep-history?", true
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// Custom backends
|
|
151
|
+
Map<String, Object> config = Map.of(
|
|
152
|
+
"store", Map.of(
|
|
153
|
+
"backend", ":pg",
|
|
154
|
+
"host", "localhost",
|
|
155
|
+
"port", 5432,
|
|
156
|
+
"username", "user",
|
|
157
|
+
"password", "secret"
|
|
158
|
+
)
|
|
159
|
+
);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**When to use:** Dynamic configuration, config files (JSON/YAML → Map), custom backends.
|
|
163
|
+
|
|
164
|
+
### Approach 3: EDN Strings (Advanced)
|
|
165
|
+
|
|
166
|
+
For advanced use cases, work directly with Clojure's Extensible Data Notation:
|
|
167
|
+
|
|
168
|
+
```java
|
|
169
|
+
import static datahike.java.Util.*;
|
|
170
|
+
|
|
171
|
+
// Parse EDN string
|
|
172
|
+
Object config = ednFromString(
|
|
173
|
+
"{:store {:backend :memory :id #uuid \"550e8400-e29b-41d4-a716-446655440000\"}}"
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// Build EDN programmatically
|
|
177
|
+
Object config = map(
|
|
178
|
+
kwd(":store"), map(
|
|
179
|
+
kwd(":backend"), kwd(":memory"),
|
|
180
|
+
kwd(":id"), UUID.randomUUID()
|
|
181
|
+
)
|
|
182
|
+
);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**When to use:** Interop with Clojure code, advanced EDN features, maximum control.
|
|
186
|
+
|
|
187
|
+
## Database Lifecycle
|
|
188
|
+
|
|
189
|
+
### Creating and Connecting
|
|
190
|
+
|
|
191
|
+
```java
|
|
192
|
+
import datahike.java.Datahike;
|
|
193
|
+
|
|
194
|
+
// Create database (idempotent - safe to call multiple times)
|
|
195
|
+
Datahike.createDatabase(config);
|
|
196
|
+
|
|
197
|
+
// Check if database exists
|
|
198
|
+
boolean exists = Datahike.databaseExists(config);
|
|
199
|
+
|
|
200
|
+
// Connect to database (returns connection object)
|
|
201
|
+
Object conn = Datahike.connect(config);
|
|
202
|
+
|
|
203
|
+
// Get current database value
|
|
204
|
+
Object db = Datahike.deref(conn);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Deleting Databases
|
|
208
|
+
|
|
209
|
+
```java
|
|
210
|
+
// Delete all database files/data
|
|
211
|
+
Datahike.deleteDatabase(config);
|
|
212
|
+
|
|
213
|
+
// Release connection (required for some backends like LevelDB)
|
|
214
|
+
Datahike.release(conn);
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Transactions
|
|
218
|
+
|
|
219
|
+
Transactions are atomic and consistent. Add, update, or retract data.
|
|
220
|
+
|
|
221
|
+
### Simple Transactions
|
|
222
|
+
|
|
223
|
+
```java
|
|
224
|
+
import java.util.*;
|
|
225
|
+
|
|
226
|
+
// Add entities with auto-generated IDs
|
|
227
|
+
Datahike.transact(conn, List.of(
|
|
228
|
+
Map.of("name", "Alice", "age", 30),
|
|
229
|
+
Map.of("name", "Bob", "age", 25)
|
|
230
|
+
));
|
|
231
|
+
|
|
232
|
+
// Update existing entity (requires :db/id)
|
|
233
|
+
Datahike.transact(conn, List.of(
|
|
234
|
+
Map.of(":db/id", 1, "age", 31)
|
|
235
|
+
));
|
|
236
|
+
|
|
237
|
+
// Retract attribute
|
|
238
|
+
import static datahike.java.Util.*;
|
|
239
|
+
|
|
240
|
+
Datahike.transact(conn, vec(
|
|
241
|
+
vec(kwd(":db/retract"), 1, kwd(":age"), 30)
|
|
242
|
+
));
|
|
243
|
+
|
|
244
|
+
// Retract entire entity
|
|
245
|
+
Datahike.transact(conn, vec(
|
|
246
|
+
vec(kwd(":db.fn/retractEntity"), 1)
|
|
247
|
+
));
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### EDN Conversion Rules
|
|
251
|
+
|
|
252
|
+
Datahike automatically converts between Java and Clojure data:
|
|
253
|
+
|
|
254
|
+
| Java Type | EDN Type | Example |
|
|
255
|
+
|-----------|----------|---------|
|
|
256
|
+
| `String` starting with `:` | Keyword | `":memory"` → `:memory` |
|
|
257
|
+
| Other `String` | String | `"Alice"` → `"Alice"` |
|
|
258
|
+
| `Integer`, `Long` | Long | `42` → `42` |
|
|
259
|
+
| `Boolean` | Boolean | `true` → `true` |
|
|
260
|
+
| `Map<String, ?>` | Map | `{"a": 1}` → `{:a 1}` |
|
|
261
|
+
| `List<?>`, `Object[]` | Vector | `[1, 2]` → `[1 2]` |
|
|
262
|
+
| `UUID` | UUID | `UUID` → `#uuid "..."` |
|
|
263
|
+
|
|
264
|
+
**Important:** Map keys are always converted to keywords. Use `:` prefix in string values to create keyword values.
|
|
265
|
+
|
|
266
|
+
See [EDN Conversion Documentation](bindings/edn-conversion.md) for complete rules and edge cases.
|
|
267
|
+
|
|
268
|
+
## Queries
|
|
269
|
+
|
|
270
|
+
Datahike uses Datalog, a declarative query language similar to SQL but more expressive.
|
|
271
|
+
|
|
272
|
+
### Basic Queries
|
|
273
|
+
|
|
274
|
+
```java
|
|
275
|
+
// Find all names
|
|
276
|
+
Set<?> results = (Set<?>) Datahike.q(
|
|
277
|
+
"[:find ?name :where [?e :name ?name]]",
|
|
278
|
+
Datahike.deref(conn)
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
// Find with conditions
|
|
282
|
+
Set<?> results = (Set<?>) Datahike.q(
|
|
283
|
+
"[:find ?name ?age :where [?e :name ?name] [?e :age ?age] [(>= ?age 25)]]",
|
|
284
|
+
Datahike.deref(conn)
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
// Joins across entities
|
|
288
|
+
Set<?> results = (Set<?>) Datahike.q(
|
|
289
|
+
"""
|
|
290
|
+
[:find ?person-name ?friend-name
|
|
291
|
+
:where
|
|
292
|
+
[?p :person/name ?person-name]
|
|
293
|
+
[?p :person/friends ?f]
|
|
294
|
+
[?f :person/name ?friend-name]]
|
|
295
|
+
""",
|
|
296
|
+
Datahike.deref(conn)
|
|
297
|
+
);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Parameterized Queries
|
|
301
|
+
|
|
302
|
+
```java
|
|
303
|
+
// Query with input parameters
|
|
304
|
+
Set<?> results = (Set<?>) Datahike.q(
|
|
305
|
+
"[:find ?e :in $ ?name :where [?e :name ?name]]",
|
|
306
|
+
Datahike.deref(conn),
|
|
307
|
+
"Alice"
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
// Multiple databases
|
|
311
|
+
Object conn2 = Datahike.connect(otherConfig);
|
|
312
|
+
Set<?> results = (Set<?>) Datahike.q(
|
|
313
|
+
"[:find ?name :in $ $2 :where [$ ?e :name ?name] [$2 ?e :active true]]",
|
|
314
|
+
Datahike.deref(conn),
|
|
315
|
+
Datahike.deref(conn2)
|
|
316
|
+
);
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Aggregates
|
|
320
|
+
|
|
321
|
+
```java
|
|
322
|
+
// Count, sum, min, max, avg
|
|
323
|
+
Set<?> results = (Set<?>) Datahike.q(
|
|
324
|
+
"[:find (count ?e) (avg ?age) :where [?e :age ?age]]",
|
|
325
|
+
Datahike.deref(conn)
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
// Group by
|
|
329
|
+
Set<?> results = (Set<?>) Datahike.q(
|
|
330
|
+
"""
|
|
331
|
+
[:find ?department (avg ?salary)
|
|
332
|
+
:where
|
|
333
|
+
[?e :employee/department ?department]
|
|
334
|
+
[?e :employee/salary ?salary]]
|
|
335
|
+
""",
|
|
336
|
+
Datahike.deref(conn)
|
|
337
|
+
);
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Pull API
|
|
341
|
+
|
|
342
|
+
The Pull API retrieves entities with nested relationships using pattern-based selectors.
|
|
343
|
+
|
|
344
|
+
### Basic Pull
|
|
345
|
+
|
|
346
|
+
```java
|
|
347
|
+
// Pull single entity by ID
|
|
348
|
+
Map<?, ?> entity = (Map<?, ?>) Datahike.pull(
|
|
349
|
+
Datahike.deref(conn),
|
|
350
|
+
"[:name :age]",
|
|
351
|
+
1
|
|
352
|
+
);
|
|
353
|
+
// => {:name "Alice" :age 30}
|
|
354
|
+
|
|
355
|
+
// Pull all attributes
|
|
356
|
+
Map<?, ?> entity = (Map<?, ?>) Datahike.pull(
|
|
357
|
+
Datahike.deref(conn),
|
|
358
|
+
"[*]",
|
|
359
|
+
1
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
// Pull multiple entities
|
|
363
|
+
List<?> entities = (List<?>) Datahike.pullMany(
|
|
364
|
+
Datahike.deref(conn),
|
|
365
|
+
"[:name :age]",
|
|
366
|
+
List.of(1, 2, 3)
|
|
367
|
+
);
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Nested Pull
|
|
371
|
+
|
|
372
|
+
```java
|
|
373
|
+
// Pull with nested relationships
|
|
374
|
+
Map<?, ?> person = (Map<?, ?>) Datahike.pull(
|
|
375
|
+
Datahike.deref(conn),
|
|
376
|
+
"""
|
|
377
|
+
[:person/name
|
|
378
|
+
{:person/friends [:person/name :person/email]}]
|
|
379
|
+
""",
|
|
380
|
+
1
|
|
381
|
+
);
|
|
382
|
+
// => {:person/name "Alice"
|
|
383
|
+
// :person/friends [{:person/name "Bob" :person/email "bob@example.com"}]}
|
|
384
|
+
|
|
385
|
+
// Recursive pull (follow references up to 3 levels)
|
|
386
|
+
Map<?, ?> org = (Map<?, ?>) Datahike.pull(
|
|
387
|
+
Datahike.deref(conn),
|
|
388
|
+
"[:org/name {:org/parent 3}]", // 3 = recursion depth
|
|
389
|
+
orgId
|
|
390
|
+
);
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Time Travel
|
|
394
|
+
|
|
395
|
+
Query database state at any point in history.
|
|
396
|
+
|
|
397
|
+
### Historical Queries
|
|
398
|
+
|
|
399
|
+
```java
|
|
400
|
+
import java.time.Instant;
|
|
401
|
+
import java.util.Date;
|
|
402
|
+
|
|
403
|
+
// Query as of specific time
|
|
404
|
+
Date timestamp = Date.from(Instant.parse("2024-01-01T00:00:00Z"));
|
|
405
|
+
Object pastDb = Datahike.asOf(Datahike.deref(conn), timestamp);
|
|
406
|
+
Set<?> results = (Set<?>) Datahike.q(
|
|
407
|
+
"[:find ?name :where [?e :name ?name]]",
|
|
408
|
+
pastDb
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
// Query changes since timestamp
|
|
412
|
+
Object recentDb = Datahike.since(Datahike.deref(conn), timestamp);
|
|
413
|
+
Set<?> changes = (Set<?>) Datahike.q(
|
|
414
|
+
"[:find ?name :where [?e :name ?name]]",
|
|
415
|
+
recentDb
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
// Query full history (includes all assertions and retractions)
|
|
419
|
+
Object historyDb = Datahike.history(Datahike.deref(conn));
|
|
420
|
+
Set<?> allValues = (Set<?>) Datahike.q(
|
|
421
|
+
"[:find ?name :where [?e :name ?name]]",
|
|
422
|
+
historyDb
|
|
423
|
+
);
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Transaction Metadata
|
|
427
|
+
|
|
428
|
+
```java
|
|
429
|
+
import static datahike.java.Util.*;
|
|
430
|
+
|
|
431
|
+
// Add metadata to transaction
|
|
432
|
+
Datahike.transact(conn, Map.of(
|
|
433
|
+
":tx-data", List.of(Map.of("name", "Alice")),
|
|
434
|
+
":tx-meta", Map.of("author", "user@example.com", "reason", "user signup")
|
|
435
|
+
));
|
|
436
|
+
|
|
437
|
+
// Query transaction metadata
|
|
438
|
+
Set<?> txData = (Set<?>) Datahike.q(
|
|
439
|
+
"""
|
|
440
|
+
[:find ?tx ?author ?time
|
|
441
|
+
:where
|
|
442
|
+
[?tx :author ?author]
|
|
443
|
+
[?tx :db/txInstant ?time]]
|
|
444
|
+
""",
|
|
445
|
+
Datahike.deref(conn)
|
|
446
|
+
);
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
## Schema Definition
|
|
450
|
+
|
|
451
|
+
Schemas define attributes and their properties, enabling validation and optimizations.
|
|
452
|
+
|
|
453
|
+
### Defining Schema
|
|
454
|
+
|
|
455
|
+
```java
|
|
456
|
+
import static datahike.java.Keywords.*;
|
|
457
|
+
import static datahike.java.Util.*;
|
|
458
|
+
|
|
459
|
+
// Define schema attributes
|
|
460
|
+
Object schema = vec(
|
|
461
|
+
map(
|
|
462
|
+
DB_IDENT, kwd(":person/name"),
|
|
463
|
+
DB_VALUE_TYPE, STRING,
|
|
464
|
+
DB_CARDINALITY, ONE,
|
|
465
|
+
DB_DOC, "Person's full name",
|
|
466
|
+
DB_UNIQUE, UNIQUE_IDENTITY
|
|
467
|
+
),
|
|
468
|
+
map(
|
|
469
|
+
DB_IDENT, kwd(":person/age"),
|
|
470
|
+
DB_VALUE_TYPE, LONG,
|
|
471
|
+
DB_CARDINALITY, ONE
|
|
472
|
+
),
|
|
473
|
+
map(
|
|
474
|
+
DB_IDENT, kwd(":person/friends"),
|
|
475
|
+
DB_VALUE_TYPE, REF,
|
|
476
|
+
DB_CARDINALITY, MANY,
|
|
477
|
+
DB_DOC, "Person's friends (entity references)"
|
|
478
|
+
)
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
// Option 1: Set schema at database creation
|
|
482
|
+
Map<String, Object> config = Database.memory(UUID.randomUUID())
|
|
483
|
+
.initialTx(schema)
|
|
484
|
+
.build();
|
|
485
|
+
|
|
486
|
+
Datahike.createDatabase(config);
|
|
487
|
+
|
|
488
|
+
// Option 2: Transact schema after creation
|
|
489
|
+
Datahike.createDatabase(config);
|
|
490
|
+
Object conn = Datahike.connect(config);
|
|
491
|
+
Datahike.transact(conn, schema);
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Schema Flexibility
|
|
495
|
+
|
|
496
|
+
```java
|
|
497
|
+
import datahike.java.SchemaFlexibility;
|
|
498
|
+
|
|
499
|
+
// Strict: Only defined attributes allowed
|
|
500
|
+
Map<String, Object> config = Database.memory(UUID.randomUUID())
|
|
501
|
+
.build(); // Default: strict schema enforcement
|
|
502
|
+
|
|
503
|
+
// Flexible read: Allow reading undefined attributes, reject writes
|
|
504
|
+
Map<String, Object> config = Database.memory(UUID.randomUUID())
|
|
505
|
+
.schemaFlexibility(SchemaFlexibility.READ)
|
|
506
|
+
.build();
|
|
507
|
+
|
|
508
|
+
// Flexible write: Allow both reading and writing undefined attributes
|
|
509
|
+
Map<String, Object> config = Database.memory(UUID.randomUUID())
|
|
510
|
+
.schemaFlexibility(SchemaFlexibility.WRITE)
|
|
511
|
+
.build();
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### Schema Constants
|
|
515
|
+
|
|
516
|
+
Use the `Keywords` class for type-safe schema definitions:
|
|
517
|
+
|
|
518
|
+
```java
|
|
519
|
+
import static datahike.java.Keywords.*;
|
|
520
|
+
|
|
521
|
+
// Entity attributes
|
|
522
|
+
DB_ID, DB_IDENT
|
|
523
|
+
|
|
524
|
+
// Schema definition
|
|
525
|
+
DB_VALUE_TYPE, DB_CARDINALITY, DB_DOC, DB_UNIQUE, DB_INDEX
|
|
526
|
+
|
|
527
|
+
// Value types
|
|
528
|
+
STRING, BOOLEAN, LONG, BIGINT, FLOAT, DOUBLE, BIGDEC,
|
|
529
|
+
INSTANT, UUID_TYPE, KEYWORD_TYPE, SYMBOL_TYPE, REF, BYTES
|
|
530
|
+
|
|
531
|
+
// Cardinality
|
|
532
|
+
ONE, MANY
|
|
533
|
+
|
|
534
|
+
// Uniqueness
|
|
535
|
+
UNIQUE_VALUE, UNIQUE_IDENTITY
|
|
536
|
+
|
|
537
|
+
// Schema flexibility
|
|
538
|
+
SCHEMA_READ, SCHEMA_WRITE
|
|
539
|
+
|
|
540
|
+
// Storage backends
|
|
541
|
+
BACKEND_MEMORY, BACKEND_FILE
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
## Advanced Features
|
|
545
|
+
|
|
546
|
+
### Index Access
|
|
547
|
+
|
|
548
|
+
```java
|
|
549
|
+
// Get datoms from index (EAVT, AEVT, AVET)
|
|
550
|
+
Iterable<?> datoms = Datahike.datoms(
|
|
551
|
+
Datahike.deref(conn),
|
|
552
|
+
":eavt"
|
|
553
|
+
);
|
|
554
|
+
|
|
555
|
+
// Seek to position in index
|
|
556
|
+
import static datahike.java.Util.*;
|
|
557
|
+
|
|
558
|
+
Iterable<?> datoms = Datahike.seekDatoms(
|
|
559
|
+
Datahike.deref(conn),
|
|
560
|
+
":avet",
|
|
561
|
+
kwd(":name"), "Alice"
|
|
562
|
+
);
|
|
563
|
+
|
|
564
|
+
// Get index range
|
|
565
|
+
Iterable<?> range = Datahike.indexRange(
|
|
566
|
+
Datahike.deref(conn),
|
|
567
|
+
":name",
|
|
568
|
+
"A", "M" // Lexicographic range
|
|
569
|
+
);
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### Entity API
|
|
573
|
+
|
|
574
|
+
```java
|
|
575
|
+
import datahike.java.IEntity;
|
|
576
|
+
import static datahike.java.Util.*;
|
|
577
|
+
|
|
578
|
+
// Get entity by ID
|
|
579
|
+
IEntity entity = (IEntity) Datahike.entity(Datahike.deref(conn), 1);
|
|
580
|
+
|
|
581
|
+
// Access attributes
|
|
582
|
+
String name = (String) entity.valAt(kwd(":name"));
|
|
583
|
+
Long age = (Long) entity.valAt(kwd(":age"));
|
|
584
|
+
|
|
585
|
+
// Touch entity (load all attributes)
|
|
586
|
+
Object touchedEntity = Datahike.touch(entity);
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
### Database Metrics
|
|
590
|
+
|
|
591
|
+
```java
|
|
592
|
+
// Get database statistics
|
|
593
|
+
Map<?, ?> metrics = (Map<?, ?>) Datahike.metrics(
|
|
594
|
+
Datahike.deref(conn)
|
|
595
|
+
);
|
|
596
|
+
|
|
597
|
+
System.out.println(metrics);
|
|
598
|
+
// => {:datoms 1000 :indexed-datoms 1000 ...}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### Schema Introspection
|
|
602
|
+
|
|
603
|
+
```java
|
|
604
|
+
// Get current schema
|
|
605
|
+
Map<?, ?> schema = (Map<?, ?>) Datahike.schema(
|
|
606
|
+
Datahike.deref(conn)
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
// Get reverse schema (ident -> attribute map)
|
|
610
|
+
Map<?, ?> reverseSchema = (Map<?, ?>) Datahike.reverseSchema(
|
|
611
|
+
Datahike.deref(conn)
|
|
612
|
+
);
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
## Storage Backends
|
|
616
|
+
|
|
617
|
+
### Memory Backend
|
|
618
|
+
|
|
619
|
+
Fast in-memory storage, requires UUID identifier:
|
|
620
|
+
|
|
621
|
+
```java
|
|
622
|
+
Map<String, Object> config = Database.memory(UUID.randomUUID())
|
|
623
|
+
.build();
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
**Use cases:** Testing, caching, temporary data, development.
|
|
627
|
+
|
|
628
|
+
### File Backend
|
|
629
|
+
|
|
630
|
+
Persistent file-based storage:
|
|
631
|
+
|
|
632
|
+
```java
|
|
633
|
+
Map<String, Object> config = Database.file("/var/lib/myapp/db")
|
|
634
|
+
.build();
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
**Use cases:** Local applications, single-server deployments, development persistence.
|
|
638
|
+
|
|
639
|
+
### Custom Backends
|
|
640
|
+
|
|
641
|
+
Extend Datahike with custom storage implementations:
|
|
642
|
+
|
|
643
|
+
```java
|
|
644
|
+
Map<String, Object> config = Database.custom(Map.of(
|
|
645
|
+
"backend", ":my-backend",
|
|
646
|
+
"custom-option-1", "value1",
|
|
647
|
+
"custom-option-2", "value2"
|
|
648
|
+
)).build();
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
Available via plugins: PostgreSQL, S3, Redis, and more.
|
|
652
|
+
|
|
653
|
+
## Examples
|
|
654
|
+
|
|
655
|
+
### Complete Application
|
|
656
|
+
|
|
657
|
+
```java
|
|
658
|
+
import datahike.java.*;
|
|
659
|
+
import static datahike.java.Keywords.*;
|
|
660
|
+
import static datahike.java.Util.*;
|
|
661
|
+
import java.util.*;
|
|
662
|
+
|
|
663
|
+
public class DatahikeExample {
|
|
664
|
+
public static void main(String[] args) {
|
|
665
|
+
// 1. Configure database
|
|
666
|
+
Object schema = vec(
|
|
667
|
+
map(DB_IDENT, kwd(":user/email"),
|
|
668
|
+
DB_VALUE_TYPE, STRING,
|
|
669
|
+
DB_CARDINALITY, ONE,
|
|
670
|
+
DB_UNIQUE, UNIQUE_IDENTITY),
|
|
671
|
+
map(DB_IDENT, kwd(":user/name"),
|
|
672
|
+
DB_VALUE_TYPE, STRING,
|
|
673
|
+
DB_CARDINALITY, ONE)
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
Map<String, Object> config = Database.file("/tmp/app-db")
|
|
677
|
+
.initialTx(schema)
|
|
678
|
+
.schemaFlexibility(SchemaFlexibility.READ)
|
|
679
|
+
.keepHistory(true)
|
|
680
|
+
.build();
|
|
681
|
+
|
|
682
|
+
// 2. Create and connect
|
|
683
|
+
Datahike.createDatabase(config);
|
|
684
|
+
Object conn = Datahike.connect(config);
|
|
685
|
+
|
|
686
|
+
// 3. Add data
|
|
687
|
+
Datahike.transact(conn, List.of(
|
|
688
|
+
Map.of(":user/email", "alice@example.com",
|
|
689
|
+
":user/name", "Alice"),
|
|
690
|
+
Map.of(":user/email", "bob@example.com",
|
|
691
|
+
":user/name", "Bob")
|
|
692
|
+
));
|
|
693
|
+
|
|
694
|
+
// 4. Query data
|
|
695
|
+
Set<?> users = (Set<?>) Datahike.q(
|
|
696
|
+
"[:find ?email ?name :where [?e :user/email ?email] [?e :user/name ?name]]",
|
|
697
|
+
Datahike.deref(conn)
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
System.out.println("Users: " + users);
|
|
701
|
+
|
|
702
|
+
// 5. Update data
|
|
703
|
+
Datahike.transact(conn, List.of(
|
|
704
|
+
Map.of(":user/email", "alice@example.com", // Upsert by unique attr
|
|
705
|
+
":user/name", "Alice Smith")
|
|
706
|
+
));
|
|
707
|
+
|
|
708
|
+
// 6. Time travel
|
|
709
|
+
var pastDb = Datahike.asOf(Datahike.deref(conn), new Date(0));
|
|
710
|
+
var pastUsers = Datahike.q(
|
|
711
|
+
"[:find ?name :where [?e :user/name ?name]]",
|
|
712
|
+
pastDb
|
|
713
|
+
);
|
|
714
|
+
System.out.println("Past users: " + pastUsers);
|
|
715
|
+
|
|
716
|
+
// 7. Cleanup
|
|
717
|
+
Datahike.deleteDatabase(config);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
## API Reference
|
|
723
|
+
|
|
724
|
+
Full Javadoc available at: `https://javadoc.io/doc/org.replikativ/datahike/latest/`
|
|
725
|
+
|
|
726
|
+
### Key Classes
|
|
727
|
+
|
|
728
|
+
- **`Datahike`** - Main API with all database operations
|
|
729
|
+
- **`Database`** - Fluent builder for configuration
|
|
730
|
+
- **`Keywords`** - Pre-defined constants for schema and configuration
|
|
731
|
+
- **`EDN`** - EDN data type constructors and conversion
|
|
732
|
+
- **`Util`** - Low-level utilities (map, vec, kwd, etc.)
|
|
733
|
+
- **`SchemaFlexibility`** - Enum for schema modes
|
|
734
|
+
- **`IEntity`** - Entity interface for direct attribute access
|
|
735
|
+
|
|
736
|
+
### Core Methods
|
|
737
|
+
|
|
738
|
+
See auto-generated bindings in `Datahike.java` for complete list. All Datahike API functions are available.
|
|
739
|
+
|
|
740
|
+
## Comparison with Other JVM Databases
|
|
741
|
+
|
|
742
|
+
### vs Datomic
|
|
743
|
+
|
|
744
|
+
Datahike is Datomic-compatible with similar semantics:
|
|
745
|
+
- ✅ Same query language and API
|
|
746
|
+
- ✅ Same time-travel capabilities
|
|
747
|
+
- ✅ Similar schema system
|
|
748
|
+
- ✅ Open source and free
|
|
749
|
+
- ✅ Multiple storage backends
|
|
750
|
+
- ⚠️ Smaller community and ecosystem, but API compatible
|
|
751
|
+
|
|
752
|
+
### vs SQL Databases
|
|
753
|
+
|
|
754
|
+
| Feature | Datahike | SQL |
|
|
755
|
+
|---------|----------|-----|
|
|
756
|
+
| Query Language | Declarative Datalog | Declarative SQL |
|
|
757
|
+
| Schema | Optional, flexible | Usually required |
|
|
758
|
+
| Joins | Implicit, natural | Explicit with JOIN |
|
|
759
|
+
| Time Travel | Built-in | Requires audit tables |
|
|
760
|
+
| Immutability | Yes, all data versioned | No, updates in-place |
|
|
761
|
+
| Transactions | ACID | ACID |
|
|
762
|
+
|
|
763
|
+
## Performance Tips
|
|
764
|
+
|
|
765
|
+
1. **Use indexes** - Define `:db/index true` for frequently queried attributes
|
|
766
|
+
2. **Batch transactions** - Transact multiple entities at once
|
|
767
|
+
3. **Disable history** - Set `:keep-history? false` for write-heavy workloads
|
|
768
|
+
4. **Pull API** - More efficient than multiple queries for related data
|
|
769
|
+
5. **Index selection** - Use appropriate index (:eavt, :aevt, :avet) for datoms access
|
|
770
|
+
|
|
771
|
+
## Troubleshooting
|
|
772
|
+
|
|
773
|
+
### Common Issues
|
|
774
|
+
|
|
775
|
+
**"Could not locate Clojure runtime"**
|
|
776
|
+
- Ensure Clojure is on your classpath
|
|
777
|
+
- Datahike includes it transitively, but check for conflicts
|
|
778
|
+
|
|
779
|
+
**"Memory backend requires UUID"**
|
|
780
|
+
- Use `UUID.randomUUID()` not string IDs
|
|
781
|
+
- Required by konserve store for distributed tracking
|
|
782
|
+
|
|
783
|
+
**"Schema validation failed"**
|
|
784
|
+
- Check schema flexibility setting
|
|
785
|
+
- Verify attribute definitions match data types
|
|
786
|
+
|
|
787
|
+
**ClassCastException in results**
|
|
788
|
+
- Query results are Clojure collections (Set, List, Map)
|
|
789
|
+
- Cast appropriately: `(Set<?>) Datahike.q(...)`
|
|
790
|
+
|
|
791
|
+
## Further Reading
|
|
792
|
+
|
|
793
|
+
- [Main README](../README.md) - Project overview and installation
|
|
794
|
+
- [Schema Documentation](schema.md) - Detailed schema guide
|
|
795
|
+
- [Time Travel Guide](time_variance.md) - Historical queries
|
|
796
|
+
- [Storage Backends](storage-backends.md) - Backend configuration
|
|
797
|
+
- [EDN Conversion](bindings/edn-conversion.md) - Java ↔ EDN mapping
|
|
798
|
+
- [Datalog Tutorial](https://docs.datomic.com/on-prem/query.html) - Query language guide
|
|
799
|
+
|
|
800
|
+
## License
|
|
801
|
+
|
|
802
|
+
Eclipse Public License 1.0 (EPL-1.0)
|
|
803
|
+
|
|
804
|
+
## Support
|
|
805
|
+
|
|
806
|
+
- **GitHub Issues**: https://github.com/replikativ/datahike/issues
|
|
807
|
+
- **Discussions**: https://github.com/replikativ/datahike/discussions
|
|
808
|
+
- **Professional Support**: Contact christian@weilbach.name for consulting
|