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,984 @@
|
|
|
1
|
+
(ns datahike.test.query-test
|
|
2
|
+
(:require
|
|
3
|
+
#?(:cljs [cljs.test :as t :refer-macros [is deftest testing]]
|
|
4
|
+
:clj [clojure.test :as t :refer [is deftest testing]])
|
|
5
|
+
[datahike.api :as d]
|
|
6
|
+
[datahike.db :as db]
|
|
7
|
+
[datahike.test.utils :as utils]
|
|
8
|
+
[datahike.query :as dq]
|
|
9
|
+
[taoensso.timbre :as log])
|
|
10
|
+
#?(:clj
|
|
11
|
+
(:import [clojure.lang ExceptionInfo])))
|
|
12
|
+
|
|
13
|
+
#?(:cljs (def Throwable js/Error))
|
|
14
|
+
|
|
15
|
+
(deftest test-joins
|
|
16
|
+
(let [db (-> (db/empty-db)
|
|
17
|
+
(d/db-with [{:db/id 1, :name "Ivan", :age 15}
|
|
18
|
+
{:db/id 2, :name "Petr", :age 37}
|
|
19
|
+
{:db/id 3, :name "Ivan", :age 37}
|
|
20
|
+
{:db/id 4, :age 15}]))]
|
|
21
|
+
(is (= (d/q '[:find ?e
|
|
22
|
+
:where [?e :name]] db)
|
|
23
|
+
#{[1] [2] [3]}))
|
|
24
|
+
(is (= (d/q '[:find ?e ?v
|
|
25
|
+
:where [?e :name "Ivan"]
|
|
26
|
+
[?e :age ?v]] db)
|
|
27
|
+
#{[1 15] [3 37]}))
|
|
28
|
+
(is (= (d/q '[:find ?e1 ?e2
|
|
29
|
+
:where [?e1 :name ?n]
|
|
30
|
+
[?e2 :name ?n]] db)
|
|
31
|
+
#{[1 1] [2 2] [3 3] [1 3] [3 1]}))
|
|
32
|
+
(is (= (d/q '[:find ?e ?e2 ?n
|
|
33
|
+
:where [?e :name "Ivan"]
|
|
34
|
+
[?e :age ?a]
|
|
35
|
+
[?e2 :age ?a]
|
|
36
|
+
[?e2 :name ?n]] db)
|
|
37
|
+
#{[1 1 "Ivan"]
|
|
38
|
+
[3 3 "Ivan"]
|
|
39
|
+
[3 2 "Petr"]}))))
|
|
40
|
+
|
|
41
|
+
(deftest test-mixed-age-types
|
|
42
|
+
(let [db (-> (db/empty-db)
|
|
43
|
+
(d/db-with [{:db/id 1, :name "Ivan", :age 15}
|
|
44
|
+
{:db/id 2, :name "Petr", :age "37"}
|
|
45
|
+
{:db/id 3, :name "Ivan", :age :thirtyseven}
|
|
46
|
+
{:db/id 4, :age 15}]))]
|
|
47
|
+
(is (= (d/q '[:find ?e ?name
|
|
48
|
+
:where
|
|
49
|
+
[?e :name ?name]
|
|
50
|
+
[?e :age "37"]] db)
|
|
51
|
+
#{[2 "Petr"]}))))
|
|
52
|
+
|
|
53
|
+
(deftest test-q-many
|
|
54
|
+
(let [db (-> (db/empty-db {:aka {:db/cardinality :db.cardinality/many}})
|
|
55
|
+
(d/db-with [[:db/add 1 :name "Ivan"]
|
|
56
|
+
[:db/add 1 :aka "ivolga"]
|
|
57
|
+
[:db/add 1 :aka "pi"]
|
|
58
|
+
[:db/add 2 :name "Petr"]
|
|
59
|
+
[:db/add 2 :aka "porosenok"]
|
|
60
|
+
[:db/add 2 :aka "pi"]]))]
|
|
61
|
+
(is (= (d/q '[:find ?n1 ?n2
|
|
62
|
+
:where
|
|
63
|
+
[?e1 :aka ?x]
|
|
64
|
+
[?e2 :aka ?x]
|
|
65
|
+
[?e1 :name ?n1]
|
|
66
|
+
[?e2 :name ?n2]] db)
|
|
67
|
+
#{["Ivan" "Ivan"]
|
|
68
|
+
["Petr" "Petr"]
|
|
69
|
+
["Ivan" "Petr"]
|
|
70
|
+
["Petr" "Ivan"]}))))
|
|
71
|
+
|
|
72
|
+
(deftest test-q-coll
|
|
73
|
+
(let [db [[1 :name "Ivan"]
|
|
74
|
+
[1 :age 19]
|
|
75
|
+
[1 :aka "dragon_killer_94"]
|
|
76
|
+
[1 :aka "-=autobot=-"]]]
|
|
77
|
+
(is (= (d/q '[:find ?n ?a
|
|
78
|
+
:where [?e :aka "dragon_killer_94"]
|
|
79
|
+
[?e :name ?n]
|
|
80
|
+
[?e :age ?a]] db)
|
|
81
|
+
#{["Ivan" 19]})))
|
|
82
|
+
|
|
83
|
+
(testing "Query over long tuples"
|
|
84
|
+
(let [db [[1 :name "Ivan" 945 :db/add]
|
|
85
|
+
[1 :age 39 999 :db/retract]]]
|
|
86
|
+
(is (= (d/q '[:find ?e ?v
|
|
87
|
+
:where [?e :name ?v]] db)
|
|
88
|
+
#{[1 "Ivan"]}))
|
|
89
|
+
(is (= (d/q '[:find ?e ?a ?v ?t
|
|
90
|
+
:where [?e ?a ?v ?t :db/retract]] db)
|
|
91
|
+
#{[1 :age 39 999]})))))
|
|
92
|
+
|
|
93
|
+
(deftest test-q-in
|
|
94
|
+
(let [db (-> (db/empty-db)
|
|
95
|
+
(d/db-with [{:db/id 1, :name "Ivan", :age 15}
|
|
96
|
+
{:db/id 2, :name "Petr", :age 37}
|
|
97
|
+
{:db/id 3, :name "Ivan", :age 37}]))
|
|
98
|
+
query '{:find [?e]
|
|
99
|
+
:in [$ ?attr ?value]
|
|
100
|
+
:where [[?e ?attr ?value]]}]
|
|
101
|
+
(is (= (d/q query db :name "Ivan")
|
|
102
|
+
#{[1] [3]}))
|
|
103
|
+
(is (= (d/q query db :age 37)
|
|
104
|
+
#{[2] [3]}))
|
|
105
|
+
|
|
106
|
+
(testing "Named DB"
|
|
107
|
+
(is (= (d/q '[:find ?a ?v
|
|
108
|
+
:in $db ?e
|
|
109
|
+
:where [$db ?e ?a ?v]] db 1)
|
|
110
|
+
#{[:name "Ivan"]
|
|
111
|
+
[:age 15]})))
|
|
112
|
+
|
|
113
|
+
(testing "DB join with collection"
|
|
114
|
+
(is (= (d/q '[:find ?e ?email
|
|
115
|
+
:in $ $b
|
|
116
|
+
:where [?e :name ?n]
|
|
117
|
+
[$b ?n ?email]]
|
|
118
|
+
db
|
|
119
|
+
[["Ivan" "ivan@mail.ru"]
|
|
120
|
+
["Petr" "petr@gmail.com"]])
|
|
121
|
+
#{[1 "ivan@mail.ru"]
|
|
122
|
+
[2 "petr@gmail.com"]
|
|
123
|
+
[3 "ivan@mail.ru"]})))
|
|
124
|
+
|
|
125
|
+
(testing "Query without DB"
|
|
126
|
+
(is (= (d/q '[:find ?a ?b
|
|
127
|
+
:in ?a ?b]
|
|
128
|
+
10 20)
|
|
129
|
+
#{[10 20]})))))
|
|
130
|
+
|
|
131
|
+
(deftest test-bindings
|
|
132
|
+
(let [db (-> (db/empty-db)
|
|
133
|
+
(d/db-with [{:db/id 1, :name "Ivan", :age 15}
|
|
134
|
+
{:db/id 2, :name "Petr", :age 37}
|
|
135
|
+
{:db/id 3, :name "Ivan", :age 37}]))]
|
|
136
|
+
(testing "Relation binding"
|
|
137
|
+
(is (= (d/q '[:find ?e ?email
|
|
138
|
+
:in $ [[?n ?email]]
|
|
139
|
+
:where [?e :name ?n]]
|
|
140
|
+
db
|
|
141
|
+
[["Ivan" "ivan@mail.ru"]
|
|
142
|
+
["Petr" "petr@gmail.com"]])
|
|
143
|
+
#{[1 "ivan@mail.ru"]
|
|
144
|
+
[2 "petr@gmail.com"]
|
|
145
|
+
[3 "ivan@mail.ru"]})))
|
|
146
|
+
|
|
147
|
+
(testing "Tuple binding"
|
|
148
|
+
(is (= (d/q '[:find ?e
|
|
149
|
+
:in $ [?name ?age]
|
|
150
|
+
:where [?e :name ?name]
|
|
151
|
+
[?e :age ?age]]
|
|
152
|
+
db ["Ivan" 37])
|
|
153
|
+
#{[3]})))
|
|
154
|
+
|
|
155
|
+
(testing "Collection binding"
|
|
156
|
+
(is (= (d/q '[:find ?attr ?value
|
|
157
|
+
:in $ ?e [?attr ...]
|
|
158
|
+
:where [?e ?attr ?value]]
|
|
159
|
+
db 1 [:name :age])
|
|
160
|
+
#{[:name "Ivan"] [:age 15]})))
|
|
161
|
+
|
|
162
|
+
(testing "Empty coll handling"
|
|
163
|
+
(is (= (d/q '[:find ?id
|
|
164
|
+
:in $ [?id ...]
|
|
165
|
+
:where [?id :age _]]
|
|
166
|
+
[[1 :name "Ivan"]
|
|
167
|
+
[2 :name "Petr"]]
|
|
168
|
+
[])
|
|
169
|
+
#{}))
|
|
170
|
+
(is (= (d/q '[:find ?id
|
|
171
|
+
:in $ [[?id]]
|
|
172
|
+
:where [?id :age _]]
|
|
173
|
+
[[1 :name "Ivan"]
|
|
174
|
+
[2 :name "Petr"]]
|
|
175
|
+
[])
|
|
176
|
+
#{})))
|
|
177
|
+
|
|
178
|
+
(testing "Placeholders"
|
|
179
|
+
(is (= (d/q '[:find ?x ?z
|
|
180
|
+
:in [?x _ ?z]]
|
|
181
|
+
[:x :y :z])
|
|
182
|
+
#{[:x :z]}))
|
|
183
|
+
(is (= (d/q '[:find ?x ?z
|
|
184
|
+
:in [[?x _ ?z]]]
|
|
185
|
+
[[:x :y :z] [:a :b :c]])
|
|
186
|
+
#{[:x :z] [:a :c]})))
|
|
187
|
+
|
|
188
|
+
(testing "Error reporting"
|
|
189
|
+
(is (thrown-with-msg? ExceptionInfo #"Cannot bind value :a to tuple \[\?a \?b\]"
|
|
190
|
+
(d/q '[:find ?a ?b :in [?a ?b]] :a)))
|
|
191
|
+
(is (thrown-with-msg? ExceptionInfo #"Cannot bind value :a to collection \[\?a \.\.\.\]"
|
|
192
|
+
(d/q '[:find ?a :in [?a ...]] :a)))
|
|
193
|
+
(is (thrown-with-msg? ExceptionInfo #"Not enough elements in a collection \[:a\] to bind tuple \[\?a \?b\]"
|
|
194
|
+
(d/q '[:find ?a ?b :in [?a ?b]] [:a]))))))
|
|
195
|
+
|
|
196
|
+
(deftest test-nested-bindings
|
|
197
|
+
(is (= (d/q '[:find ?k ?v
|
|
198
|
+
:in [[?k ?v] ...]
|
|
199
|
+
:where [(> ?v 1)]]
|
|
200
|
+
{:a 1, :b 2, :c 3})
|
|
201
|
+
#{[:b 2] [:c 3]}))
|
|
202
|
+
|
|
203
|
+
(is (= (d/q '[:find ?k ?min ?max
|
|
204
|
+
:in [[?k ?v] ...] ?minmax
|
|
205
|
+
:where [(?minmax ?v) [?min ?max]]
|
|
206
|
+
[(> ?max ?min)]]
|
|
207
|
+
{:a [1 2 3 4]
|
|
208
|
+
:b [5 6 7]
|
|
209
|
+
:c [3]}
|
|
210
|
+
#(vector (reduce min %) (reduce max %)))
|
|
211
|
+
#{[:a 1 4] [:b 5 7]}))
|
|
212
|
+
|
|
213
|
+
(is (= (d/q '[:find ?k ?x
|
|
214
|
+
:in [[?k [?min ?max]] ...] ?range
|
|
215
|
+
:where [(?range ?min ?max) [?x ...]]
|
|
216
|
+
[(even? ?x)]]
|
|
217
|
+
{:a [1 7]
|
|
218
|
+
:b [2 4]}
|
|
219
|
+
range)
|
|
220
|
+
#{[:a 2] [:a 4] [:a 6]
|
|
221
|
+
[:b 2]})))
|
|
222
|
+
|
|
223
|
+
(deftest test-offset
|
|
224
|
+
(let [db (-> (db/empty-db)
|
|
225
|
+
(d/db-with [{:db/id 1, :name "Alice", :age 15}
|
|
226
|
+
{:db/id 2, :name "Bob", :age 37}
|
|
227
|
+
{:db/id 3, :name "Charlie", :age 37}]))]
|
|
228
|
+
(is (= 3 (count (d/q {:query '[:find ?e :where [?e :name _]]
|
|
229
|
+
:args [db]
|
|
230
|
+
:limit -1}))))
|
|
231
|
+
(is (= 3 (count (d/q {:query '[:find ?e :where [?e :name _]]
|
|
232
|
+
:args [db]}))))
|
|
233
|
+
(is (= 3 (count (d/q {:query '[:find ?e :where [?e :name _]]
|
|
234
|
+
:args [db]
|
|
235
|
+
:limit nil}))))
|
|
236
|
+
(is (= 3 (count (d/q {:query '[:find ?e :where [?e :name _]]
|
|
237
|
+
:args [db]
|
|
238
|
+
:offset -1}))))
|
|
239
|
+
(is (= 3 (count (d/q {:query '[:find ?e :where [?e :name _]]
|
|
240
|
+
:args [db]
|
|
241
|
+
:offset nil}))))
|
|
242
|
+
(is (= 1 (count (d/q {:query '[:find ?e :where [?e :name _]]
|
|
243
|
+
:args [db]
|
|
244
|
+
:offset 1
|
|
245
|
+
:limit 1}))))
|
|
246
|
+
(is (= 2 (count (d/q {:query '[:find ?e :where [?e :name _]]
|
|
247
|
+
:args [db]
|
|
248
|
+
:limit 2}))))
|
|
249
|
+
(is (= 2 (count (d/q {:query '[:find ?e :where [?e :name _]]
|
|
250
|
+
:args [db]
|
|
251
|
+
:offset 1
|
|
252
|
+
:limit 2}))))
|
|
253
|
+
(is (= 1 (count (d/q {:query '[:find ?e :where [?e :name _]]
|
|
254
|
+
:args [db]
|
|
255
|
+
:offset 2
|
|
256
|
+
:limit 2}))))
|
|
257
|
+
(is (not (= (d/q {:query '[:find ?e :where [?e :name _]]
|
|
258
|
+
:args [db]
|
|
259
|
+
:limit 2})
|
|
260
|
+
(d/q {:query '[:find ?e :where [?e :name _]]
|
|
261
|
+
:args [db]
|
|
262
|
+
:offset 1
|
|
263
|
+
:limit 2}))))
|
|
264
|
+
(is (= (d/q {:query '[:find ?e :where [?e :name _]]
|
|
265
|
+
:args [db]
|
|
266
|
+
:offset 4})
|
|
267
|
+
#{}))
|
|
268
|
+
(is (= (d/q {:query '[:find ?e :where [?e :name _]]
|
|
269
|
+
:args [db]
|
|
270
|
+
:offset 10
|
|
271
|
+
:limit 5})
|
|
272
|
+
#{}))
|
|
273
|
+
(is (= (d/q {:query '[:find ?e :where [?e :name _]]
|
|
274
|
+
:args [db]
|
|
275
|
+
:offset 1
|
|
276
|
+
:limit 0})
|
|
277
|
+
#{}))))
|
|
278
|
+
|
|
279
|
+
(deftest test-return-maps
|
|
280
|
+
(let [db (-> (db/empty-db)
|
|
281
|
+
(d/db-with [{:db/id 1, :name "Alice", :age 15}
|
|
282
|
+
{:db/id 2, :name "Bob", :age 37}
|
|
283
|
+
{:db/id 3, :name "Charlie", :age 37}]))]
|
|
284
|
+
(testing "returns map"
|
|
285
|
+
(is (map? (first (d/q {:query '[:find ?e :keys name :where [?e :name _]]
|
|
286
|
+
:args [db]})))))
|
|
287
|
+
(testing "returns set without return-map"
|
|
288
|
+
(is (= #{["Charlie"] ["Alice"] ["Bob"]}
|
|
289
|
+
(d/q {:query '[:find ?name :where [_ :name ?name]]
|
|
290
|
+
:args [db]}))))
|
|
291
|
+
(testing "returns map with key return-map"
|
|
292
|
+
(is (= [{:foo 3} {:foo 2} {:foo 1}]
|
|
293
|
+
(d/q {:query '[:find ?e :keys foo :where [?e :name _]]
|
|
294
|
+
:args [db]}))))
|
|
295
|
+
(testing "returns map with string return-map"
|
|
296
|
+
(is (= [{"foo" "Charlie"} {"foo" "Alice"} {"foo" "Bob"}]
|
|
297
|
+
(d/q {:query '[:find ?name :strs foo :where [?e :name ?name]]
|
|
298
|
+
:args [db]}))))
|
|
299
|
+
(testing "return map with keys using multiple find vars"
|
|
300
|
+
(is (= #{["Bob" {:age 37 :db/id 2}]
|
|
301
|
+
["Charlie" {:age 37 :db/id 3}]
|
|
302
|
+
["Alice" {:age 15 :db/id 1}]}
|
|
303
|
+
(into #{} (d/q {:find '[?name (pull ?e ?p)]
|
|
304
|
+
:args [db '[:age :db/id]]
|
|
305
|
+
:in '[$ ?p]
|
|
306
|
+
:where '[[?e :name ?name]]})))))))
|
|
307
|
+
|
|
308
|
+
(deftest test-memoized-parse-query
|
|
309
|
+
(testing "no map return"
|
|
310
|
+
(is (= nil
|
|
311
|
+
(:qreturnmap (dq/memoized-parse-query '[:find ?e :where [?e :name]])))))
|
|
312
|
+
(testing "key map return"
|
|
313
|
+
(is (= '#datalog.parser.type.ReturnMaps{:mapping-type :keys, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo})}
|
|
314
|
+
(:qreturnmaps (dq/memoized-parse-query '[:find ?e :keys foo :where [?e :name]])))))
|
|
315
|
+
(testing "key map return multiple"
|
|
316
|
+
(is (= '#datalog.parser.type.ReturnMaps{:mapping-type :keys, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo}, #datalog.parser.type.MappingKey{:mapping-key bar})}
|
|
317
|
+
(:qreturnmaps (dq/memoized-parse-query '[:find ?e ?f :keys foo bar :where [?e :name ?f]])))))
|
|
318
|
+
(testing "string map return multiple"
|
|
319
|
+
(is (= '#datalog.parser.type.ReturnMaps{:mapping-type :strs, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo}, #datalog.parser.type.MappingKey{:mapping-key bar})}
|
|
320
|
+
(:qreturnmaps (dq/memoized-parse-query '[:find ?e ?f :strs foo bar :where [?e :name ?f]])))))
|
|
321
|
+
(testing "symbol map return multiple"
|
|
322
|
+
(is (= '#datalog.parser.type.ReturnMaps{:mapping-type :syms, :mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo}, #datalog.parser.type.MappingKey{:mapping-key bar})}
|
|
323
|
+
(:qreturnmaps (dq/memoized-parse-query '[:find ?e ?f :syms foo bar :where [?e :name ?f]]))))))
|
|
324
|
+
|
|
325
|
+
(deftest test-convert-to-return-maps
|
|
326
|
+
(testing "converting keys"
|
|
327
|
+
(is (= [{:foo 3} {:foo 2} {:foo 1}]
|
|
328
|
+
(dq/convert-to-return-maps '#datalog.parser.type.ReturnMaps{:mapping-type :keys,
|
|
329
|
+
:mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo})}
|
|
330
|
+
#{[1] [2] [3]}))))
|
|
331
|
+
(testing "converting strs"
|
|
332
|
+
(is (= [{"foo" 3} {"foo" 2} {"foo" 1}]
|
|
333
|
+
(dq/convert-to-return-maps '#datalog.parser.type.ReturnMaps{:mapping-type :strs,
|
|
334
|
+
:mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo})}
|
|
335
|
+
#{[1] [2] [3]}))))
|
|
336
|
+
(testing "converting syms"
|
|
337
|
+
(is (= [{'foo 3} {'foo 2} {'foo 1}]
|
|
338
|
+
(dq/convert-to-return-maps '#datalog.parser.type.ReturnMaps{:mapping-type :syms,
|
|
339
|
+
:mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo})}
|
|
340
|
+
#{[1] [2] [3]}))))
|
|
341
|
+
(testing "converting keys"
|
|
342
|
+
(is (= '[{:foo 1, :bar 11, :baz "Ivan"} {:foo 3, :bar 21, :baz "Petr"} {:foo 3, :bar 31, :baz "Ivan"}]
|
|
343
|
+
(dq/convert-to-return-maps '#datalog.parser.type.ReturnMaps{:mapping-type :keys,
|
|
344
|
+
:mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo},
|
|
345
|
+
#datalog.parser.type.MappingKey{:mapping-key bar},
|
|
346
|
+
#datalog.parser.type.MappingKey{:mapping-key baz})}
|
|
347
|
+
#{[1 11 "Ivan"]
|
|
348
|
+
[3 31 "Ivan"]
|
|
349
|
+
[3 21 "Petr"]}))))
|
|
350
|
+
(testing "converting strs"
|
|
351
|
+
(is (= '[{"foo" 1, "bar" 11, "baz" "Ivan"} {"foo" 3, "bar" 21, "baz" "Petr"} {"foo" 3, "bar" 31, "baz" "Ivan"}]
|
|
352
|
+
(dq/convert-to-return-maps '#datalog.parser.type.ReturnMaps{:mapping-type :strs,
|
|
353
|
+
:mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo},
|
|
354
|
+
#datalog.parser.type.MappingKey{:mapping-key bar},
|
|
355
|
+
#datalog.parser.type.MappingKey{:mapping-key baz})}
|
|
356
|
+
#{[1 11 "Ivan"]
|
|
357
|
+
[3 31 "Ivan"]
|
|
358
|
+
[3 21 "Petr"]}))))
|
|
359
|
+
(testing "converting syms"
|
|
360
|
+
(is (= '[{foo 1, bar 11, baz "Ivan"} {foo 3, bar 21, baz "Petr"} {foo 3, bar 31, baz "Ivan"}]
|
|
361
|
+
(dq/convert-to-return-maps '#datalog.parser.type.ReturnMaps{:mapping-type :syms,
|
|
362
|
+
:mapping-keys (#datalog.parser.type.MappingKey{:mapping-key foo},
|
|
363
|
+
#datalog.parser.type.MappingKey{:mapping-key bar},
|
|
364
|
+
#datalog.parser.type.MappingKey{:mapping-key baz})}
|
|
365
|
+
#{[1 11 "Ivan"]
|
|
366
|
+
[3 31 "Ivan"]
|
|
367
|
+
[3 21 "Petr"]})))))
|
|
368
|
+
|
|
369
|
+
#_(deftest test-clause-order-invariance ;; TODO: this is what should happen after rewirite of query engine
|
|
370
|
+
(let [db (-> (db/empty-db)
|
|
371
|
+
(d/db-with [{:db/id 1, :name "Ivan", :age 15}
|
|
372
|
+
{:db/id 2, :name "Petr", :age 37}
|
|
373
|
+
{:db/id 3, :name "Ivan", :age 37}
|
|
374
|
+
{:db/id 4, :age 15}]))]
|
|
375
|
+
(testing "Clause order does not matter for predicates"
|
|
376
|
+
(is (= (d/q {:query '{:find [?e]
|
|
377
|
+
:where [[?e :age ?age]
|
|
378
|
+
[(= ?age 37)]]}
|
|
379
|
+
:args [db]})
|
|
380
|
+
#{[2] [3]}))
|
|
381
|
+
(is (= (d/q {:query '{:find [?e]
|
|
382
|
+
:where [[(= ?age 37)]
|
|
383
|
+
[?e :age ?age]]}
|
|
384
|
+
:args [db]})
|
|
385
|
+
#{[2] [3]})))))
|
|
386
|
+
|
|
387
|
+
(deftest test-clause-order
|
|
388
|
+
(let [db (-> (db/empty-db)
|
|
389
|
+
(d/db-with [{:db/id 1, :name "Ivan", :age 15}
|
|
390
|
+
{:db/id 2, :name "Petr", :age 37}
|
|
391
|
+
{:db/id 3, :name "Ivan", :age 37}
|
|
392
|
+
{:db/id 4, :age 15}]))]
|
|
393
|
+
(testing "Predicate clause before variable binding throws exception"
|
|
394
|
+
(is (= (d/q {:query '{:find [?e]
|
|
395
|
+
:where [[?e :age ?age]
|
|
396
|
+
[(= ?age 37)]]}
|
|
397
|
+
:args [db]})
|
|
398
|
+
#{[2] [3]}))
|
|
399
|
+
(is (thrown-with-msg? Throwable #"Insufficient bindings: #\{\?age\} not bound"
|
|
400
|
+
(d/q {:query '{:find [?e]
|
|
401
|
+
:where [[(= ?age 37)]
|
|
402
|
+
[?e :age ?age]]}
|
|
403
|
+
:args [db]}))))))
|
|
404
|
+
|
|
405
|
+
(deftest test-zeros-in-pattern
|
|
406
|
+
(let [cfg {:store {:backend :memory
|
|
407
|
+
:id #uuid "b0000000-0000-0000-0000-00000000000b"}
|
|
408
|
+
:schema-flexibility :write
|
|
409
|
+
:attribute-refs? false}
|
|
410
|
+
conn (do
|
|
411
|
+
(d/delete-database cfg)
|
|
412
|
+
(d/create-database cfg)
|
|
413
|
+
(d/connect cfg))]
|
|
414
|
+
(d/transact conn [{:db/ident :version/id
|
|
415
|
+
:db/valueType :db.type/long
|
|
416
|
+
:db/cardinality :db.cardinality/one
|
|
417
|
+
:db/unique :db.unique/identity}
|
|
418
|
+
{:version/id 0}
|
|
419
|
+
{:version/id 1}])
|
|
420
|
+
(is (= 1
|
|
421
|
+
(count (d/q '[:find ?t :in $ :where
|
|
422
|
+
[?t :version/id 0]]
|
|
423
|
+
@conn))))
|
|
424
|
+
(d/release conn)))
|
|
425
|
+
|
|
426
|
+
;; https://github.com/replikativ/datahike/issues/471
|
|
427
|
+
(deftest keyword-keys-test
|
|
428
|
+
(let [schema [{:db/ident :name
|
|
429
|
+
:db/cardinality :db.cardinality/one
|
|
430
|
+
:db/index true
|
|
431
|
+
:db/unique :db.unique/identity
|
|
432
|
+
:db/valueType :db.type/string}
|
|
433
|
+
{:db/ident :parents
|
|
434
|
+
:db/cardinality :db.cardinality/many
|
|
435
|
+
:db/valueType :db.type/ref}
|
|
436
|
+
{:db/ident :age
|
|
437
|
+
:db/cardinality :db.cardinality/one
|
|
438
|
+
:db/valueType :db.type/long}]
|
|
439
|
+
cfg {:store {:backend :memory
|
|
440
|
+
:id #uuid "c0000000-0000-0000-0000-00000000000c"}
|
|
441
|
+
:schema-flexibility :write
|
|
442
|
+
:attribute-refs? true}
|
|
443
|
+
conn (utils/setup-db cfg)]
|
|
444
|
+
(d/transact conn schema)
|
|
445
|
+
(d/transact conn [{:name "Alice"
|
|
446
|
+
:age 25}
|
|
447
|
+
{:name "Bob"
|
|
448
|
+
:age 35}])
|
|
449
|
+
(d/transact conn [{:name "Charlie"
|
|
450
|
+
:age 5
|
|
451
|
+
:parents [[:name "Alice"] [:name "Bob"]]}])
|
|
452
|
+
(let [db @conn
|
|
453
|
+
keyword-result (into #{} (d/q '[:find ?n ?a
|
|
454
|
+
:keys :name :age
|
|
455
|
+
:where
|
|
456
|
+
[?e :name ?n]
|
|
457
|
+
[?e :age ?a]]
|
|
458
|
+
db))
|
|
459
|
+
symbol-result (into #{} (d/q '[:find ?n ?a
|
|
460
|
+
:keys name age
|
|
461
|
+
:where
|
|
462
|
+
[?e :name ?n]
|
|
463
|
+
[?e :age ?a]]
|
|
464
|
+
db))]
|
|
465
|
+
(testing "keyword result keys"
|
|
466
|
+
(is (= #{{:name "Alice" :age 25}
|
|
467
|
+
{:name "Charlie" :age 5}
|
|
468
|
+
{:name "Bob" :age 35}}
|
|
469
|
+
keyword-result)))
|
|
470
|
+
(testing "keyword equals symbol keys"
|
|
471
|
+
(is (= symbol-result
|
|
472
|
+
keyword-result))))
|
|
473
|
+
(d/release conn)))
|
|
474
|
+
|
|
475
|
+
(deftest test-normalize-q-input
|
|
476
|
+
(testing "query as vector"
|
|
477
|
+
(is (= {:query {:find '[?n]
|
|
478
|
+
:where '[[?e :name ?n]]}
|
|
479
|
+
:args :db}
|
|
480
|
+
(dq/normalize-q-input '[:find ?n
|
|
481
|
+
:where [?e :name ?n]]
|
|
482
|
+
:db))))
|
|
483
|
+
|
|
484
|
+
(testing "query in :query field"
|
|
485
|
+
(is (= {:query {:find '[?n]
|
|
486
|
+
:where '[[?e :name ?n]]}
|
|
487
|
+
:args [:db]}
|
|
488
|
+
(dq/normalize-q-input {:query '{:find [?n]
|
|
489
|
+
:where [[?e :name ?n]]}
|
|
490
|
+
:args [:db]}
|
|
491
|
+
[])))
|
|
492
|
+
(is (= {:query {:find '[?n], :where '[[?e :name ?n]]}
|
|
493
|
+
:args [:db]}
|
|
494
|
+
(dq/normalize-q-input {:query '{:find [?n]
|
|
495
|
+
:where [[?e :name ?n]]}}
|
|
496
|
+
[:db])))
|
|
497
|
+
(is (= {:query {:find '[?n], :where '[[?e :name ?n]]}
|
|
498
|
+
:args [:db]}
|
|
499
|
+
(dq/normalize-q-input {:query '{:find [?n]
|
|
500
|
+
:where [[?e :name ?n]]}
|
|
501
|
+
:args [:db]}
|
|
502
|
+
[:db2])))
|
|
503
|
+
(is (= {:query {:find '[?n]
|
|
504
|
+
:where '[[?e :name ?n]]}
|
|
505
|
+
:args [:db]
|
|
506
|
+
:limit 100
|
|
507
|
+
:offset 0}
|
|
508
|
+
(dq/normalize-q-input {:query '[:find ?n
|
|
509
|
+
:where [?e :name ?n]]
|
|
510
|
+
:offset 0
|
|
511
|
+
:limit 100
|
|
512
|
+
:args [:db]}
|
|
513
|
+
[]))))
|
|
514
|
+
|
|
515
|
+
(testing "query in top-level map"
|
|
516
|
+
(is (= {:query {:find '[?e]
|
|
517
|
+
:where '[[?e :name ?value]]}
|
|
518
|
+
:args []
|
|
519
|
+
:limit 100
|
|
520
|
+
:offset 0}
|
|
521
|
+
(dq/normalize-q-input {:find '[?e]
|
|
522
|
+
:where '[[?e :name ?value]]
|
|
523
|
+
:offset 0
|
|
524
|
+
:limit 100} [])))))
|
|
525
|
+
|
|
526
|
+
(deftest test-distinct-tuples
|
|
527
|
+
(is (= [[3 4]] (dq/distinct-tuples [[3 4]])))
|
|
528
|
+
(let [arrays [(object-array [:a]) (object-array [:a])]
|
|
529
|
+
result (dq/distinct-tuples arrays)
|
|
530
|
+
object-array-type (type (object-array []))]
|
|
531
|
+
(is (every? #(= object-array-type (type %)) result))
|
|
532
|
+
(is (= [[:a]] (map vec result)))
|
|
533
|
+
|
|
534
|
+
;; This is just to highlight the difference w.r.t. `distinct`:
|
|
535
|
+
(is (= [[:a] [:a]] (map vec (distinct arrays)))))
|
|
536
|
+
(is (= [[3 4]] (dq/distinct-tuples [[3 4] [3 4]])))
|
|
537
|
+
(is (= [[3 4]] (dq/distinct-tuples [[3 4]
|
|
538
|
+
(long-array [3 4])])))
|
|
539
|
+
(is (= [[3 4] [9 7]] (dq/distinct-tuples [[3 4] [9 7] [3 4]]))))
|
|
540
|
+
|
|
541
|
+
;; A good one
|
|
542
|
+
(def ex1 '{:source {:max-tx 536926163},
|
|
543
|
+
:pattern1 [?r1 79 ?oc],
|
|
544
|
+
:context
|
|
545
|
+
{:rels
|
|
546
|
+
[{:attrs {?oc 0},
|
|
547
|
+
:tuples
|
|
548
|
+
[[5289]
|
|
549
|
+
[5294]
|
|
550
|
+
[5299]
|
|
551
|
+
[5304]
|
|
552
|
+
[5307]
|
|
553
|
+
[5310]
|
|
554
|
+
[5313]
|
|
555
|
+
[5317]
|
|
556
|
+
[5322]
|
|
557
|
+
[5325]],
|
|
558
|
+
:tuple-count 3654}
|
|
559
|
+
{:attrs {?__auto__1 0}, :tuples [], :tuple-count 0}],
|
|
560
|
+
:consts {?__auto__1 "narrow-match"}},
|
|
561
|
+
:clause [?r1 :relation/concept-1 ?oc],
|
|
562
|
+
:constrained-patterns
|
|
563
|
+
[[?r1 79 5289]
|
|
564
|
+
[?r1 79 5294]
|
|
565
|
+
[?r1 79 5299]
|
|
566
|
+
[?r1 79 5304]
|
|
567
|
+
[?r1 79 5307]
|
|
568
|
+
[?r1 79 5310]
|
|
569
|
+
[?r1 79 5313]
|
|
570
|
+
[?r1 79 5317]
|
|
571
|
+
[?r1 79 5322]
|
|
572
|
+
[?r1 79 5325]],
|
|
573
|
+
:constrained-pattern-count 3654})
|
|
574
|
+
|
|
575
|
+
(deftest test-new-search-strategy
|
|
576
|
+
(let [;; pattern1 = [?r1 79 ?oc]
|
|
577
|
+
{:keys [context pattern1]} ex1
|
|
578
|
+
rels (vec (:rels context))
|
|
579
|
+
bsm (dq/bound-symbol-map rels)
|
|
580
|
+
|
|
581
|
+
clean-pattern (dq/replace-unbound-symbols-by-nil bsm pattern1)
|
|
582
|
+
|
|
583
|
+
strategy0 [nil :substitute :substitute nil]
|
|
584
|
+
strategy1 [nil :substitute :filter nil]
|
|
585
|
+
|
|
586
|
+
subst-inds0 (dq/substitution-relation-indices
|
|
587
|
+
{:bsm bsm
|
|
588
|
+
:clean-pattern clean-pattern
|
|
589
|
+
:strategy-vec strategy0})
|
|
590
|
+
subst-inds1 (dq/substitution-relation-indices
|
|
591
|
+
{:bsm bsm
|
|
592
|
+
:clean-pattern clean-pattern
|
|
593
|
+
:strategy-vec strategy1})
|
|
594
|
+
filt-inds0 (dq/filtering-relation-indices
|
|
595
|
+
{:bsm bsm
|
|
596
|
+
:clean-pattern clean-pattern
|
|
597
|
+
:strategy-vec strategy0}
|
|
598
|
+
subst-inds0)
|
|
599
|
+
filt-inds1 (dq/filtering-relation-indices
|
|
600
|
+
{:bsm bsm
|
|
601
|
+
:clean-pattern clean-pattern
|
|
602
|
+
:strategy-vec strategy1}
|
|
603
|
+
subst-inds1)]
|
|
604
|
+
(is (seq rels))
|
|
605
|
+
(is (= '{?oc {:relation-index 0, :tuple-element-index 0},
|
|
606
|
+
?__auto__1 {:relation-index 1, :tuple-element-index 0}}
|
|
607
|
+
bsm))
|
|
608
|
+
(is (= #{0} subst-inds0))
|
|
609
|
+
(is (= #{} subst-inds1))
|
|
610
|
+
(is (= #{} filt-inds0))
|
|
611
|
+
(is (= #{0} filt-inds1))))
|
|
612
|
+
|
|
613
|
+
(defn pack6 [step]
|
|
614
|
+
(fn
|
|
615
|
+
([] (step))
|
|
616
|
+
([dst] (step dst))
|
|
617
|
+
([dst e a v tx added? filt]
|
|
618
|
+
(step dst [[e a v tx added?] filt]))))
|
|
619
|
+
|
|
620
|
+
(deftest test-substitution-plan
|
|
621
|
+
(let [-pattern1 '[?w ?x ?y]
|
|
622
|
+
context '{:rels [{:attrs {?x 0
|
|
623
|
+
?y 1}
|
|
624
|
+
:tuples [[1 2]
|
|
625
|
+
[3 4]
|
|
626
|
+
[3 5]
|
|
627
|
+
[5 6]]}
|
|
628
|
+
{:attrs {?z 0}
|
|
629
|
+
:tuples [[9] [10] [11]]}]}
|
|
630
|
+
rels (vec (:rels context))
|
|
631
|
+
bsm (dq/bound-symbol-map rels)
|
|
632
|
+
clean-pattern (dq/replace-unbound-symbols-by-nil bsm -pattern1)
|
|
633
|
+
strategy [nil :substitute :filter nil]
|
|
634
|
+
subst-inds (dq/substitution-relation-indices
|
|
635
|
+
{:bsm bsm
|
|
636
|
+
:clean-pattern clean-pattern
|
|
637
|
+
:strategy-vec strategy
|
|
638
|
+
:rels rels})
|
|
639
|
+
filt-inds (dq/filtering-relation-indices
|
|
640
|
+
{:bsm bsm
|
|
641
|
+
:clean-pattern clean-pattern
|
|
642
|
+
:strategy-vec strategy
|
|
643
|
+
:rels rels}
|
|
644
|
+
subst-inds)
|
|
645
|
+
[init-coll subst-xform] (dq/initialization-and-substitution-xform
|
|
646
|
+
{:bsm bsm
|
|
647
|
+
:clean-pattern clean-pattern
|
|
648
|
+
:strategy-vec strategy
|
|
649
|
+
:rels rels}
|
|
650
|
+
subst-inds)
|
|
651
|
+
|
|
652
|
+
result (into []
|
|
653
|
+
(comp dq/unpack6
|
|
654
|
+
subst-xform
|
|
655
|
+
pack6)
|
|
656
|
+
init-coll)
|
|
657
|
+
[[_ p0] [_ p1] [_ p2] [_ p3]] result]
|
|
658
|
+
(is (= #{0} subst-inds))
|
|
659
|
+
(is (= #{} filt-inds))
|
|
660
|
+
(is (= {'?x {:relation-index 0 :tuple-element-index 0}
|
|
661
|
+
'?y {:relation-index 0 :tuple-element-index 1}
|
|
662
|
+
'?z {:relation-index 1 :tuple-element-index 0}}
|
|
663
|
+
bsm))
|
|
664
|
+
(is (= [[nil 1 nil nil nil]
|
|
665
|
+
[nil 3 nil nil nil]
|
|
666
|
+
[nil 3 nil nil nil]
|
|
667
|
+
[nil 5 nil nil nil]] (map first result)))
|
|
668
|
+
(is (p0 [1 2 2]))
|
|
669
|
+
(is (not (p0 [1 2 3])))
|
|
670
|
+
(is (p1 [1 2 4]))
|
|
671
|
+
(is (p2 [1 2 5]))
|
|
672
|
+
(is (not (p1 [1 2 6])))
|
|
673
|
+
(is (p3 [1 2 6]))
|
|
674
|
+
(is (not (p3 [1 2 5])))))
|
|
675
|
+
|
|
676
|
+
(deftest test-index-feature-extractor
|
|
677
|
+
(let [e (dq/index-feature-extractor [1] true)]
|
|
678
|
+
(is (= 3 (e [119 3])))
|
|
679
|
+
(is (= 4 (e [120 4 9 3]))))
|
|
680
|
+
(let [e (dq/index-feature-extractor [1 0] true)]
|
|
681
|
+
(is (= [3 119] (e [119 3])))
|
|
682
|
+
(is (= [4 120] (e [120 4 9 3]))))
|
|
683
|
+
(let [e (dq/index-feature-extractor [] true)]
|
|
684
|
+
(is (nil? (e [119 3])))
|
|
685
|
+
(is (nil? (e [120 4 9 3]))))
|
|
686
|
+
(is (nil? (dq/index-feature-extractor [] false))))
|
|
687
|
+
|
|
688
|
+
(deftest test-filtering-plan
|
|
689
|
+
(let [pattern1 '[?w ?x ?y]
|
|
690
|
+
context '{:rels [{:attrs {?x 0}
|
|
691
|
+
:tuples [[1]
|
|
692
|
+
[3]
|
|
693
|
+
[5]]}
|
|
694
|
+
{:attrs {?y 0}
|
|
695
|
+
:tuples [[2] [4] [6]]}
|
|
696
|
+
{:attrs {?z 0}
|
|
697
|
+
:tuples [[9] [10] [11]]}]}
|
|
698
|
+
|
|
699
|
+
rels (vec (:rels context))
|
|
700
|
+
bsm (dq/bound-symbol-map rels)
|
|
701
|
+
clean-pattern (dq/replace-unbound-symbols-by-nil bsm pattern1)
|
|
702
|
+
strategy [nil :substitute :filter nil]
|
|
703
|
+
subst-inds (dq/substitution-relation-indices
|
|
704
|
+
{:bsm bsm
|
|
705
|
+
:clean-pattern pattern1
|
|
706
|
+
:strategy-vec strategy})
|
|
707
|
+
filt-inds (dq/filtering-relation-indices
|
|
708
|
+
{:bsm bsm
|
|
709
|
+
:clean-pattern clean-pattern
|
|
710
|
+
:strategy-vec strategy}
|
|
711
|
+
subst-inds)
|
|
712
|
+
[init-coll subst-xform] (dq/initialization-and-substitution-xform
|
|
713
|
+
{:bsm bsm
|
|
714
|
+
:clean-pattern clean-pattern
|
|
715
|
+
:strategy-vec strategy
|
|
716
|
+
:rels rels}
|
|
717
|
+
subst-inds)
|
|
718
|
+
|
|
719
|
+
subst-result (into []
|
|
720
|
+
(comp dq/unpack6
|
|
721
|
+
subst-xform
|
|
722
|
+
pack6)
|
|
723
|
+
init-coll)
|
|
724
|
+
[[_ p0]] subst-result]
|
|
725
|
+
(is (nil? p0))
|
|
726
|
+
(is (= '[nil ?x ?y nil nil] clean-pattern))
|
|
727
|
+
(is (= #{0} subst-inds))
|
|
728
|
+
(is (= #{1} filt-inds))
|
|
729
|
+
(is (= {'?x {:relation-index 0 :tuple-element-index 0}
|
|
730
|
+
'?y {:relation-index 1 :tuple-element-index 0}
|
|
731
|
+
'?z {:relation-index 2 :tuple-element-index 0}}
|
|
732
|
+
bsm))
|
|
733
|
+
(is (= '([nil 1 nil nil nil]
|
|
734
|
+
[nil 3 nil nil nil]
|
|
735
|
+
[nil 5 nil nil nil])
|
|
736
|
+
(map first subst-result)))))
|
|
737
|
+
|
|
738
|
+
(defn pcmp [x y]
|
|
739
|
+
(or (nil? x) (= x y)))
|
|
740
|
+
|
|
741
|
+
(defn mock-backend-fn [datoms]
|
|
742
|
+
(fn [e0 a0 v0 t0 added0]
|
|
743
|
+
(filter (fn [[e1 a1 v1 t1 added1]]
|
|
744
|
+
(and (pcmp e0 e1)
|
|
745
|
+
(pcmp a0 a1)
|
|
746
|
+
(pcmp v0 v1)
|
|
747
|
+
(pcmp t0 t1)
|
|
748
|
+
(pcmp added0 added1)))
|
|
749
|
+
datoms)))
|
|
750
|
+
|
|
751
|
+
(deftest test-full-lookup-pipeline
|
|
752
|
+
(let [pattern1 '[?x ?w ?y]
|
|
753
|
+
context '{:rels [{:attrs {?x 0}
|
|
754
|
+
:tuples [[1] [3] [5]]}
|
|
755
|
+
{:attrs {?y 0}
|
|
756
|
+
:tuples [[4] [5] [6]]}]}
|
|
757
|
+
strategy-vec [:substitute nil :filter nil]
|
|
758
|
+
rels (vec (:rels context))
|
|
759
|
+
bsm (dq/bound-symbol-map rels)
|
|
760
|
+
clean-pattern (dq/replace-unbound-symbols-by-nil bsm pattern1)
|
|
761
|
+
sfn (dq/search-batch-fn {:bsm bsm
|
|
762
|
+
:clean-pattern clean-pattern
|
|
763
|
+
:rels rels})
|
|
764
|
+
result (sfn strategy-vec
|
|
765
|
+
(mock-backend-fn [[0 :abc 5]
|
|
766
|
+
[5 :xyz 6]
|
|
767
|
+
[1 :k 4]
|
|
768
|
+
[5 :p 7]])
|
|
769
|
+
identity)]
|
|
770
|
+
(is (= #{[1 :k 4] [5 :xyz 6]} (set result)))))
|
|
771
|
+
|
|
772
|
+
(defn concept-id [index]
|
|
773
|
+
(let [s (format "%010d" index)]
|
|
774
|
+
(str (subs s 0 4) "_" (subs s 4 7) "_" (subs s 7 10))))
|
|
775
|
+
|
|
776
|
+
(defn temp-id [x]
|
|
777
|
+
(str "tmp-" x))
|
|
778
|
+
|
|
779
|
+
(defn make-forest
|
|
780
|
+
"This function constructs tx-data for a forest of concepts in a terminology,
|
|
781
|
+
for example a labor market terminology of occupations. The edges in the
|
|
782
|
+
forest point toward the root and are labeled `:concept/broader` because the
|
|
783
|
+
closer to the root we get, the broader the concept is. For instance, we could
|
|
784
|
+
have a concept for the occupation name 'Software Engineer' and an edge from
|
|
785
|
+
that concept pointing at a broader concept 'Occuptions in Computer Science'.
|
|
786
|
+
|
|
787
|
+
This function takes as input a concatenated list of pairs of `m` and `t`
|
|
788
|
+
on the form `[m1 t1 m2 t2 ... mN tN]` that specifies how many sub nodes
|
|
789
|
+
should be generated at each level from the root and the type. For example,
|
|
790
|
+
`[5 'ssyk-level-1' 3 'ssyk-level-2']` means that we will construct 5 trees
|
|
791
|
+
of root node type 'ssyk-level-1' and each one of them will have 3 children
|
|
792
|
+
of node type 'ssyk-level-2'."
|
|
793
|
+
([tree-spec] (make-forest tree-spec 0))
|
|
794
|
+
([[root-count & tree-spec] init-counter]
|
|
795
|
+
{:pre [(number? root-count)]}
|
|
796
|
+
(loop [[tos & stack] (repeat root-count [nil tree-spec])
|
|
797
|
+
tx-data []
|
|
798
|
+
counter init-counter
|
|
799
|
+
concept-map {}]
|
|
800
|
+
(if (nil? tos)
|
|
801
|
+
{:tx-data tx-data
|
|
802
|
+
:concept-map concept-map}
|
|
803
|
+
(let [[parent-id [this-type child-count & remaining-pairs]] tos
|
|
804
|
+
concept-id (concept-id counter)
|
|
805
|
+
tid (temp-id concept-id)
|
|
806
|
+
parent-tid (temp-id parent-id)]
|
|
807
|
+
(assert (or (nil? parent-id) (string? parent-id)))
|
|
808
|
+
(recur (into stack
|
|
809
|
+
(when (seq remaining-pairs)
|
|
810
|
+
(repeat child-count [concept-id remaining-pairs])))
|
|
811
|
+
(into tx-data
|
|
812
|
+
cat
|
|
813
|
+
[[[:db/add tid :concept/id concept-id]
|
|
814
|
+
[:db/add tid :concept/type this-type]]
|
|
815
|
+
(when parent-id
|
|
816
|
+
[[:db/add tid :concept/broader parent-tid]])])
|
|
817
|
+
(inc counter)
|
|
818
|
+
(cond-> concept-map
|
|
819
|
+
true (update concept-id
|
|
820
|
+
merge {:parent-id parent-id
|
|
821
|
+
:type this-type
|
|
822
|
+
:id concept-id})
|
|
823
|
+
parent-id (update-in [parent-id :child-ids] #(conj (or % []) concept-id)))))))))
|
|
824
|
+
|
|
825
|
+
(def schema [#:db{:ident :concept/id,
|
|
826
|
+
:valueType :db.type/string,
|
|
827
|
+
:cardinality :db.cardinality/one,
|
|
828
|
+
:doc "Unique identifier for concepts",
|
|
829
|
+
:unique :db.unique/identity}
|
|
830
|
+
#:db{:ident :concept/type,
|
|
831
|
+
:valueType :db.type/string,
|
|
832
|
+
:cardinality :db.cardinality/one,
|
|
833
|
+
:doc "The concepts main type"}
|
|
834
|
+
#:db {:ident :concept/broader
|
|
835
|
+
:valueType :db.type/ref
|
|
836
|
+
:cardinality :db.cardinality/one
|
|
837
|
+
:doc "A broader concept. NOTE: This the JobTech Taxonomy, every relation between two concepts has an entity with attributes :relation/concept-1, :relation-concept-2 and :relation/type."}])
|
|
838
|
+
|
|
839
|
+
(defn initialize-test-db0 []
|
|
840
|
+
(let [conn (utils/setup-db {:store {:backend :memory :id (random-uuid)}
|
|
841
|
+
:schema-flexibility :write
|
|
842
|
+
:attribute-refs? false
|
|
843
|
+
:keep-history? true})]
|
|
844
|
+
(d/transact conn {:tx-data schema})
|
|
845
|
+
conn))
|
|
846
|
+
|
|
847
|
+
(defn group-concepts-by-type [concept-map]
|
|
848
|
+
(let [groups (update-vals (group-by (comp :type val)
|
|
849
|
+
concept-map)
|
|
850
|
+
(fn [kv-pairs]
|
|
851
|
+
(mapv first kv-pairs)))]
|
|
852
|
+
(doseq [[k v] (sort-by val (update-vals groups count))]
|
|
853
|
+
(log/info k v))
|
|
854
|
+
(log/info "Total count:" (count concept-map))
|
|
855
|
+
groups))
|
|
856
|
+
|
|
857
|
+
(deftest synthetic-ssyk-tree-test
|
|
858
|
+
|
|
859
|
+
"In this test we construct a labor market taxonomy of occupations. Given
|
|
860
|
+
some concept ids, we look up broader concepts. The queries in this test will
|
|
861
|
+
include clauses with up to two unknown variables.
|
|
862
|
+
|
|
863
|
+
We perform two queries. In the first query, we only provide one input id and
|
|
864
|
+
look up concepts broader than that id.
|
|
865
|
+
|
|
866
|
+
In the second query, we provide two input ids."
|
|
867
|
+
|
|
868
|
+
(testing "Given some concepts, query concepts that are broader."
|
|
869
|
+
(let [conn (initialize-test-db0)
|
|
870
|
+
ssyk-data (make-forest
|
|
871
|
+
[3 "ssyk-level-1"
|
|
872
|
+
5 "ssyk-level-2"
|
|
873
|
+
30 "ssyk-level-3"
|
|
874
|
+
5 "ssyk-level-4"
|
|
875
|
+
2 "occupation-name"])
|
|
876
|
+
ssyk-concept-map (:concept-map ssyk-data)
|
|
877
|
+
_ (d/transact conn {:tx-data (:tx-data ssyk-data)})
|
|
878
|
+
concepts-per-type (group-concepts-by-type ssyk-concept-map)
|
|
879
|
+
ssyk-level-3-ids (concepts-per-type "ssyk-level-3")
|
|
880
|
+
expected-result-fn (fn [concept-ids]
|
|
881
|
+
(into #{}
|
|
882
|
+
(map (fn [cid]
|
|
883
|
+
{:from_id cid
|
|
884
|
+
:id (get-in ssyk-concept-map
|
|
885
|
+
[cid :parent-id])}))
|
|
886
|
+
concept-ids))
|
|
887
|
+
|
|
888
|
+
related-query '{:find [?from-id ?id],
|
|
889
|
+
:keys [from_id id],
|
|
890
|
+
:in [$ [?from-id ...]],
|
|
891
|
+
:where
|
|
892
|
+
[[?c :concept/id ?from-id]
|
|
893
|
+
[?c :concept/broader ?related-c]
|
|
894
|
+
[?related-c :concept/id ?id]]}]
|
|
895
|
+
(testing "Query for 1 input concept id."
|
|
896
|
+
(let [input-concept-id (first ssyk-level-3-ids)
|
|
897
|
+
_ (is (string? input-concept-id))
|
|
898
|
+
result (d/q {:query related-query
|
|
899
|
+
:args [(d/db conn) #{input-concept-id}]})]
|
|
900
|
+
(is (= (expected-result-fn [input-concept-id])
|
|
901
|
+
(set result)))))
|
|
902
|
+
(testing "Query for 2 input ids."
|
|
903
|
+
(let [input-ids (set (take 2 ssyk-level-3-ids))
|
|
904
|
+
result (d/q {:query related-query
|
|
905
|
+
:args [(d/db conn) input-ids]})]
|
|
906
|
+
(is (= (expected-result-fn input-ids)
|
|
907
|
+
(set result))))))))
|
|
908
|
+
|
|
909
|
+
(deftest synthetic-ssyk-tree-test2
|
|
910
|
+
|
|
911
|
+
"We construct a forest of four trees with each tree having 2000 subnodes each. We then pick the ids
|
|
912
|
+
of two of the root nodes of the trees and the ids from three of the children of one
|
|
913
|
+
trees. Then we we query for all (parent,child) pairs."
|
|
914
|
+
|
|
915
|
+
(let [conn (initialize-test-db0)
|
|
916
|
+
ssyk-data (make-forest [4 "ssyk-level-1" 2000 "ssyk-level-2"])
|
|
917
|
+
ssyk-concept-map (:concept-map ssyk-data)
|
|
918
|
+
_ (d/transact conn {:tx-data (:tx-data ssyk-data)})
|
|
919
|
+
concepts-per-type (group-concepts-by-type ssyk-concept-map)]
|
|
920
|
+
(testing "Query (parent,child) pairs from a *small* set of possible combinations in a labour market taxonomy."
|
|
921
|
+
(let [parent-ids (take 2 (concepts-per-type "ssyk-level-1"))
|
|
922
|
+
parent-id (first parent-ids)
|
|
923
|
+
child-ids (take 3 (get-in ssyk-concept-map [parent-id :child-ids]))
|
|
924
|
+
_ (is (= 2 (count parent-ids)))
|
|
925
|
+
_ (is (= 3 (count child-ids)))
|
|
926
|
+
result (d/q {:query '{:find [?parent-id ?child-id]
|
|
927
|
+
:keys [parent_id child_id]
|
|
928
|
+
:in [$
|
|
929
|
+
[?parent-id ...]
|
|
930
|
+
[?child-id ...]],
|
|
931
|
+
:where
|
|
932
|
+
[[?pc :concept/id ?parent-id]
|
|
933
|
+
[?cc :concept/id ?child-id]
|
|
934
|
+
[?cc :concept/broader ?pc]]}
|
|
935
|
+
:args [(d/db conn)
|
|
936
|
+
parent-ids
|
|
937
|
+
child-ids]})
|
|
938
|
+
expected-result (into #{}
|
|
939
|
+
(map (fn [child-id] {:parent_id parent-id :child_id child-id}))
|
|
940
|
+
child-ids)]
|
|
941
|
+
(is (= 3 (count expected-result)))
|
|
942
|
+
(is (= (set result)
|
|
943
|
+
expected-result))))))
|
|
944
|
+
|
|
945
|
+
(deftest synthetic-ssyk-tree-test3
|
|
946
|
+
"We construct a labor market taxonomy of 200 trees where each root node has one child. Then
|
|
947
|
+
we query all (parent, child) pairs."
|
|
948
|
+
|
|
949
|
+
(let [conn (initialize-test-db0)
|
|
950
|
+
ssyk-data (make-forest [200 "ssyk-level-1" 1 "ssyk-level-2"])
|
|
951
|
+
ssyk-concept-map (:concept-map ssyk-data)
|
|
952
|
+
_ (d/transact conn {:tx-data (:tx-data ssyk-data)})
|
|
953
|
+
|
|
954
|
+
;; Adding some extra data here also makes `expand-once` perform better than
|
|
955
|
+
;; `identity` and `select-simple`. If we remove these two lines, then
|
|
956
|
+
;; `expand-once`, `identity` and `select-simple` will perform roughly the same.
|
|
957
|
+
extra-data (make-forest [100 "skill-headline" 100 "skill"] (count ssyk-concept-map))
|
|
958
|
+
_ (d/transact conn {:tx-data (:tx-data extra-data)})
|
|
959
|
+
|
|
960
|
+
_concepts-per-type (group-concepts-by-type ssyk-concept-map)]
|
|
961
|
+
(testing "Query (parent,child) pairs from a *large* set of possible combinations in a labour market taxonomy."
|
|
962
|
+
(let [result (d/q {:query '{:find [?parent-id ?child-id]
|
|
963
|
+
:keys [parent_id child_id]
|
|
964
|
+
:in [$ %],
|
|
965
|
+
:where
|
|
966
|
+
[[?pc :concept/type "ssyk-level-1"]
|
|
967
|
+
[?cc :concept/type "ssyk-level-2"]
|
|
968
|
+
[?cc :concept/broader ?pc]
|
|
969
|
+
[?pc :concept/id ?parent-id]
|
|
970
|
+
[?cc :concept/id ?child-id]]}
|
|
971
|
+
:args [(d/db conn)]})
|
|
972
|
+
expected-result (into #{}
|
|
973
|
+
(keep (fn [[child-id {:keys [parent-id]}]]
|
|
974
|
+
(when parent-id
|
|
975
|
+
{:child_id child-id :parent_id parent-id})))
|
|
976
|
+
ssyk-concept-map)]
|
|
977
|
+
(is (= 200 (count expected-result)))
|
|
978
|
+
(is (= expected-result
|
|
979
|
+
(set result)))))))
|
|
980
|
+
|
|
981
|
+
(deftest basic-index-selector-test
|
|
982
|
+
(let [f (dq/basic-index-selector 5)]
|
|
983
|
+
(is (= [10 7] ((f [1 3]) [9 10 4 7 1234])))
|
|
984
|
+
(is (= [7 10] ((f [3 1]) [9 10 4 7 1234])))))
|