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,134 @@
|
|
|
1
|
+
"""Datahike Python bindings.
|
|
2
|
+
|
|
3
|
+
This package provides Python bindings to Datahike, a durable Datalog database
|
|
4
|
+
powered by an efficient Datalog query engine.
|
|
5
|
+
|
|
6
|
+
High-Level API (Recommended):
|
|
7
|
+
>>> from datahike import Database
|
|
8
|
+
>>>
|
|
9
|
+
>>> db = Database(backend=':mem', id='example')
|
|
10
|
+
>>> db.create()
|
|
11
|
+
>>>
|
|
12
|
+
>>> db.transact([{"name": "Alice", "age": 30}])
|
|
13
|
+
>>> result = db.q('[:find ?name :where [?e :name ?name]]')
|
|
14
|
+
>>> print(result) # [['Alice']]
|
|
15
|
+
>>>
|
|
16
|
+
>>> db.delete()
|
|
17
|
+
|
|
18
|
+
Context Manager:
|
|
19
|
+
>>> from datahike import database
|
|
20
|
+
>>> with database(backend=':mem', id='test') as db:
|
|
21
|
+
... db.transact([{'name': 'Alice'}])
|
|
22
|
+
... result = db.q('[:find ?name :where [?e :name ?name]]')
|
|
23
|
+
... print(result)
|
|
24
|
+
|
|
25
|
+
Time Travel:
|
|
26
|
+
>>> import time
|
|
27
|
+
>>> t = int(time.time() * 1000)
|
|
28
|
+
>>> past = db.as_of(t)
|
|
29
|
+
>>> results = past.q('[:find ?name :where [?e :name ?name]]')
|
|
30
|
+
|
|
31
|
+
EDN Helpers:
|
|
32
|
+
>>> from datahike import edn, kw
|
|
33
|
+
>>> schema = [{
|
|
34
|
+
... "db/ident": edn.keyword("person/name"),
|
|
35
|
+
... "db/valueType": kw.STRING,
|
|
36
|
+
... "db/cardinality": kw.ONE
|
|
37
|
+
... }]
|
|
38
|
+
>>> db.transact(schema)
|
|
39
|
+
|
|
40
|
+
Low-Level API (Advanced):
|
|
41
|
+
>>> from datahike import create_database, transact, q, delete_database
|
|
42
|
+
>>>
|
|
43
|
+
>>> config = '{:store {:backend :mem :id "example"}}'
|
|
44
|
+
>>> create_database(config)
|
|
45
|
+
>>> transact(config, '[{"name": "Alice"}]')
|
|
46
|
+
>>> result = q('[:find ?name :where [?e :name ?name]]', [('db', config)])
|
|
47
|
+
>>> delete_database(config)
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
from ._version import __version__
|
|
51
|
+
from ._native import DatahikeException
|
|
52
|
+
|
|
53
|
+
# High-level API (recommended)
|
|
54
|
+
from .database import Database, DatabaseSnapshot, database
|
|
55
|
+
|
|
56
|
+
# EDN helpers
|
|
57
|
+
from .edn import (
|
|
58
|
+
# Types
|
|
59
|
+
Keyword,
|
|
60
|
+
Symbol,
|
|
61
|
+
UUID,
|
|
62
|
+
Inst,
|
|
63
|
+
# Functions
|
|
64
|
+
keyword,
|
|
65
|
+
symbol,
|
|
66
|
+
uuid,
|
|
67
|
+
inst,
|
|
68
|
+
string,
|
|
69
|
+
# Constants
|
|
70
|
+
Keywords,
|
|
71
|
+
kw,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Low-level API (for advanced use)
|
|
75
|
+
from .generated import (
|
|
76
|
+
database_exists,
|
|
77
|
+
create_database,
|
|
78
|
+
delete_database,
|
|
79
|
+
q,
|
|
80
|
+
transact,
|
|
81
|
+
pull,
|
|
82
|
+
pull_many,
|
|
83
|
+
entity,
|
|
84
|
+
datoms,
|
|
85
|
+
seek_datoms,
|
|
86
|
+
index_range,
|
|
87
|
+
schema,
|
|
88
|
+
reverse_schema,
|
|
89
|
+
metrics,
|
|
90
|
+
gc_storage,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
__all__ = [
|
|
94
|
+
# Version
|
|
95
|
+
'__version__',
|
|
96
|
+
|
|
97
|
+
# Exception
|
|
98
|
+
'DatahikeException',
|
|
99
|
+
|
|
100
|
+
# High-level API (recommended)
|
|
101
|
+
'Database',
|
|
102
|
+
'DatabaseSnapshot',
|
|
103
|
+
'database',
|
|
104
|
+
|
|
105
|
+
# EDN helpers
|
|
106
|
+
'Keyword',
|
|
107
|
+
'Symbol',
|
|
108
|
+
'UUID',
|
|
109
|
+
'Inst',
|
|
110
|
+
'keyword',
|
|
111
|
+
'symbol',
|
|
112
|
+
'uuid',
|
|
113
|
+
'inst',
|
|
114
|
+
'string',
|
|
115
|
+
'Keywords',
|
|
116
|
+
'kw',
|
|
117
|
+
|
|
118
|
+
# Low-level API
|
|
119
|
+
'database_exists',
|
|
120
|
+
'create_database',
|
|
121
|
+
'delete_database',
|
|
122
|
+
'q',
|
|
123
|
+
'transact',
|
|
124
|
+
'pull',
|
|
125
|
+
'pull_many',
|
|
126
|
+
'entity',
|
|
127
|
+
'datoms',
|
|
128
|
+
'seek_datoms',
|
|
129
|
+
'index_range',
|
|
130
|
+
'schema',
|
|
131
|
+
'reverse_schema',
|
|
132
|
+
'metrics',
|
|
133
|
+
'gc_storage',
|
|
134
|
+
]
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"""Native library interface for datahike.
|
|
2
|
+
|
|
3
|
+
This module provides the low-level ctypes interface to libdatahike.
|
|
4
|
+
It handles library loading, isolate initialization, and result parsing.
|
|
5
|
+
|
|
6
|
+
The callback-based architecture avoids shared mutable memory between
|
|
7
|
+
Python and the GraalVM native image.
|
|
8
|
+
"""
|
|
9
|
+
from ctypes import (
|
|
10
|
+
CDLL, CFUNCTYPE, POINTER,
|
|
11
|
+
c_void_p, c_char_p, c_long,
|
|
12
|
+
byref, ARRAY
|
|
13
|
+
)
|
|
14
|
+
import os
|
|
15
|
+
import io
|
|
16
|
+
import json
|
|
17
|
+
import base64
|
|
18
|
+
import cbor2
|
|
19
|
+
from typing import Any, List, Tuple, Optional, Callable, Literal
|
|
20
|
+
|
|
21
|
+
# Type aliases for better documentation
|
|
22
|
+
OutputFormat = Literal["json", "edn", "cbor"]
|
|
23
|
+
InputFormat = str # "db", "history", "since:<timestamp>", "asof:<timestamp>"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class DatahikeException(Exception):
|
|
27
|
+
"""Exception raised by Datahike operations."""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# =============================================================================
|
|
32
|
+
# Library Loading
|
|
33
|
+
# =============================================================================
|
|
34
|
+
|
|
35
|
+
def _find_library() -> str:
|
|
36
|
+
"""Find libdatahike shared library.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Path to library
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
FileNotFoundError: If library not found in any location
|
|
43
|
+
"""
|
|
44
|
+
# Check environment variable first
|
|
45
|
+
if 'LIBDATAHIKE_PATH' in os.environ:
|
|
46
|
+
path = os.environ['LIBDATAHIKE_PATH']
|
|
47
|
+
if os.path.exists(path):
|
|
48
|
+
return path
|
|
49
|
+
raise FileNotFoundError(
|
|
50
|
+
f"LIBDATAHIKE_PATH points to non-existent file: {path}"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Check common locations relative to this file
|
|
54
|
+
possible_paths = [
|
|
55
|
+
# Relative to datahike repo
|
|
56
|
+
os.path.join(os.path.dirname(__file__), '..', '..', '..', '..',
|
|
57
|
+
'libdatahike', 'target', 'libdatahike.so'),
|
|
58
|
+
# Linux system paths
|
|
59
|
+
'/usr/local/lib/libdatahike.so',
|
|
60
|
+
'/usr/lib/libdatahike.so',
|
|
61
|
+
# macOS
|
|
62
|
+
os.path.join(os.path.dirname(__file__), '..', '..', '..', '..',
|
|
63
|
+
'libdatahike', 'target', 'libdatahike.dylib'),
|
|
64
|
+
'/usr/local/lib/libdatahike.dylib',
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
for path in possible_paths:
|
|
68
|
+
abs_path = os.path.abspath(path)
|
|
69
|
+
if os.path.exists(abs_path):
|
|
70
|
+
return abs_path
|
|
71
|
+
|
|
72
|
+
# Provide helpful error with all attempted paths
|
|
73
|
+
tried_paths = '\n'.join(f' - {os.path.abspath(p)}' for p in possible_paths)
|
|
74
|
+
raise FileNotFoundError(
|
|
75
|
+
f"Could not find libdatahike shared library.\n\n"
|
|
76
|
+
f"Tried the following locations:\n{tried_paths}\n\n"
|
|
77
|
+
f"To fix this:\n"
|
|
78
|
+
f" 1. Build the native library: cd datahike && bb ni-compile\n"
|
|
79
|
+
f" 2. Or set LIBDATAHIKE_PATH environment variable to the library path"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Lazy initialization - don't load library at import time
|
|
84
|
+
_dll: Optional[CDLL] = None
|
|
85
|
+
_isolatethread: Optional[c_void_p] = None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _ensure_initialized() -> None:
|
|
89
|
+
"""Ensure native library is loaded and GraalVM isolate is initialized.
|
|
90
|
+
|
|
91
|
+
Raises:
|
|
92
|
+
RuntimeError: If GraalVM isolate creation fails
|
|
93
|
+
"""
|
|
94
|
+
global _dll, _isolatethread
|
|
95
|
+
|
|
96
|
+
if _dll is not None:
|
|
97
|
+
return # Already initialized
|
|
98
|
+
|
|
99
|
+
# Find and load library
|
|
100
|
+
lib_path = _find_library()
|
|
101
|
+
_dll = CDLL(lib_path)
|
|
102
|
+
|
|
103
|
+
# Initialize GraalVM isolate
|
|
104
|
+
isolate = c_void_p()
|
|
105
|
+
_isolatethread = c_void_p()
|
|
106
|
+
|
|
107
|
+
if _dll.graal_create_isolate(None, byref(isolate), byref(_isolatethread)) != 0:
|
|
108
|
+
raise RuntimeError(
|
|
109
|
+
"Failed to initialize GraalVM isolate. "
|
|
110
|
+
"The native library may be corrupted. Try rebuilding: bb ni-compile"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# =============================================================================
|
|
115
|
+
# Callback Types
|
|
116
|
+
# =============================================================================
|
|
117
|
+
|
|
118
|
+
# Callback function type for receiving results
|
|
119
|
+
CALLBACK_FUNC = CFUNCTYPE(c_void_p, c_char_p)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# =============================================================================
|
|
123
|
+
# Result Parsing
|
|
124
|
+
# =============================================================================
|
|
125
|
+
|
|
126
|
+
def _cbor_tag_hook(decoder, tag, shareable_index=None):
|
|
127
|
+
"""Handle CBOR tags (e.g., Clojure keywords)."""
|
|
128
|
+
# Tag 39 is used for Clojure keywords - just return the value
|
|
129
|
+
if tag.tag == 39:
|
|
130
|
+
return tag.value
|
|
131
|
+
return tag.value
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def parse_result(data: bytes, output_format: OutputFormat) -> Any:
|
|
135
|
+
"""Parse result bytes based on output format.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
data: Raw bytes from callback
|
|
139
|
+
output_format: One of 'json', 'edn', 'cbor'
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Parsed result
|
|
143
|
+
|
|
144
|
+
Raises:
|
|
145
|
+
DatahikeException: If result is an exception
|
|
146
|
+
ValueError: If output_format is unknown
|
|
147
|
+
"""
|
|
148
|
+
if len(data) == 0:
|
|
149
|
+
return None
|
|
150
|
+
|
|
151
|
+
# Check for exception
|
|
152
|
+
if data.startswith(b"exception:"):
|
|
153
|
+
raise DatahikeException(data.decode("utf8").replace("exception:", ""))
|
|
154
|
+
|
|
155
|
+
if output_format == "json":
|
|
156
|
+
return json.loads(data)
|
|
157
|
+
elif output_format == "edn":
|
|
158
|
+
return data.decode("utf8") # Return as string for now
|
|
159
|
+
elif output_format == "cbor":
|
|
160
|
+
# Decode from base64 string, stripping any whitespace/newlines
|
|
161
|
+
decoded = base64.b64decode(data.strip())
|
|
162
|
+
return cbor2.loads(decoded, tag_hook=_cbor_tag_hook)
|
|
163
|
+
else:
|
|
164
|
+
raise ValueError(
|
|
165
|
+
f"Unknown output format: {output_format!r}. "
|
|
166
|
+
f"Expected one of: 'json', 'edn', 'cbor'"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def make_callback(output_format: OutputFormat) -> Tuple[CALLBACK_FUNC, Callable[[], Any]]:
|
|
171
|
+
"""Create a callback function and result getter.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
output_format: Format for parsing results
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Tuple of (callback_func, get_result_func)
|
|
178
|
+
"""
|
|
179
|
+
result = None
|
|
180
|
+
exception = None
|
|
181
|
+
|
|
182
|
+
def callback(data: bytes) -> None:
|
|
183
|
+
nonlocal result, exception
|
|
184
|
+
try:
|
|
185
|
+
result = parse_result(data, output_format)
|
|
186
|
+
except Exception as e:
|
|
187
|
+
exception = e
|
|
188
|
+
|
|
189
|
+
def get_result() -> Any:
|
|
190
|
+
if exception is not None:
|
|
191
|
+
raise exception
|
|
192
|
+
return result
|
|
193
|
+
|
|
194
|
+
return CALLBACK_FUNC(callback), get_result
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# =============================================================================
|
|
198
|
+
# Query Input Helpers
|
|
199
|
+
# =============================================================================
|
|
200
|
+
|
|
201
|
+
def prepare_query_inputs(inputs: List[Tuple[InputFormat, str]]) -> Tuple[int, Any, Any]:
|
|
202
|
+
"""Prepare query inputs for native call.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
inputs: List of (format, value) tuples
|
|
206
|
+
Format can be 'db', 'history', 'since:<timestamp>', 'asof:<timestamp>', or 'param'
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
Tuple of (count, formats_array, values_array)
|
|
210
|
+
"""
|
|
211
|
+
n = len(inputs)
|
|
212
|
+
char_p_array = ARRAY(c_char_p, n)
|
|
213
|
+
formats = char_p_array()
|
|
214
|
+
values = char_p_array()
|
|
215
|
+
|
|
216
|
+
for i, (fmt, val) in enumerate(inputs):
|
|
217
|
+
formats[i] = fmt.encode("utf8")
|
|
218
|
+
values[i] = val.encode("utf8")
|
|
219
|
+
|
|
220
|
+
return n, formats, values
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# =============================================================================
|
|
224
|
+
# Native Function Wrappers
|
|
225
|
+
# =============================================================================
|
|
226
|
+
|
|
227
|
+
def get_isolatethread() -> c_void_p:
|
|
228
|
+
"""Get the current isolate thread context.
|
|
229
|
+
|
|
230
|
+
Ensures library is initialized before returning thread context.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
GraalVM isolate thread pointer
|
|
234
|
+
"""
|
|
235
|
+
_ensure_initialized()
|
|
236
|
+
assert _isolatethread is not None
|
|
237
|
+
return _isolatethread
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def get_dll() -> CDLL:
|
|
241
|
+
"""Get the loaded native library.
|
|
242
|
+
|
|
243
|
+
Ensures library is initialized before returning.
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
Loaded CDLL instance
|
|
247
|
+
"""
|
|
248
|
+
_ensure_initialized()
|
|
249
|
+
assert _dll is not None
|
|
250
|
+
return _dll
|