From c448e9a0d00a01513cf8b5411a10f77d756d9858 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Wed, 3 Apr 2024 17:20:36 -0400 Subject: [PATCH] enhance: convert has-page-property rule with tests also started on page-property rule. Tests confirm that binding won't be an issue unlike the previous version of these rules --- deps/db/src/logseq/db/frontend/rules.cljc | 80 ++++++++------ .../test/logseq/db/frontend/rules_test.cljs | 100 ++++++++++++++++++ 2 files changed, 147 insertions(+), 33 deletions(-) create mode 100644 deps/db/test/logseq/db/frontend/rules_test.cljs diff --git a/deps/db/src/logseq/db/frontend/rules.cljc b/deps/db/src/logseq/db/frontend/rules.cljc index 0ca1fa3f7..d8f28bccc 100644 --- a/deps/db/src/logseq/db/frontend/rules.cljc +++ b/deps/db/src/logseq/db/frontend/rules.cljc @@ -154,52 +154,66 @@ (merge query-dsl-rules {:page-tags - '[(page-tags ?p ?tags) - [?p :block/tags ?t] - [?t :block/name ?tag] - [(missing? $ ?p :block/link)] - [(contains? ?tags ?tag)]] + '[(page-tags ?p ?tags) + [?p :block/tags ?t] + [?t :block/name ?tag] + [(missing? $ ?p :block/link)] + [(contains? ?tags ?tag)]] :has-page-property '[(has-page-property ?p ?prop) [?p :block/name] - [?p :block/properties ?bp] - [(name ?prop) ?prop-name-str] - [?prop-b :block/name ?prop-name-str] - [?prop-b :block/type "property"] - [?prop-b :block/uuid ?prop-uuid] - [(get ?bp ?prop-uuid) ?v] + [?p ?prop ?v] + [?prop-e :db/ident ?prop] + [?prop-e :block/type "property"] ;; Some deleted properties leave #{} which this rule shouldn't match on [(not= #{} ?v)]] + ;; TODO: Delete when DB_GRAPH query-dsl tests are passing + #_'[(has-page-property ?p ?prop) + [?p :block/name] + [?p :block/properties ?bp] + [(name ?prop) ?prop-name-str] + [?prop-b :block/name ?prop-name-str] + [?prop-b :block/type "property"] + [?prop-b :block/uuid ?prop-uuid] + [(get ?bp ?prop-uuid) ?v] + ;; Some deleted properties leave #{} which this rule shouldn't match on + [(not= #{} ?v)]] :page-property '[;; Clause 1: Match non-ref values - [(page-property ?p ?key ?val) + [(page-property ?p ?prop ?val) [?p :block/name] - [?p :block/properties ?prop] - [(name ?key) ?key-str] - [?prop-b :block/name ?key-str] - [?prop-b :block/type "property"] - [?prop-b :block/uuid ?prop-uuid] - [(get ?prop ?prop-uuid) ?v] - (or ([= ?v ?val]) - [(contains? ?v ?val)])] + [?p ?prop ?val] + [?prop-e :db/ident ?prop] + [?prop-e :block/type "property"]] + ;; TODO: Delete when DB_GRAPH query-dsl tests are passing + #_[(page-property ?p ?key ?val) + [?p :block/name] + [?p :block/properties ?prop] + [(name ?key) ?key-str] + [?prop-b :block/name ?key-str] + [?prop-b :block/type "property"] + [?prop-b :block/uuid ?prop-uuid] + [(get ?prop ?prop-uuid) ?v] + (or ([= ?v ?val]) + [(contains? ?v ?val)])] ;; Clause 2: Match values joined by refs - [(page-property ?p ?key ?val) - [?p :block/name] - [?p :block/properties ?prop] - [(name ?key) ?key-str] - [?prop-b :block/name ?key-str] - [?prop-b :block/type "property"] - [?prop-b :block/uuid ?prop-uuid] - [(get ?prop ?prop-uuid) ?v] - [(str ?val) ?str-val] + #_[(page-property ?p ?key ?val) + [?p :block/name] + [?p :block/properties ?prop] + [(name ?key) ?key-str] + [?prop-b :block/name ?key-str] + [?prop-b :block/type "property"] + [?prop-b :block/uuid ?prop-uuid] + [(get ?prop ?prop-uuid) ?v] + [(str ?val) ?str-val] ;; str-val is for integer pages that aren't strings - [?prop-val-b :block/original-name ?str-val] - [?prop-val-b :block/uuid ?val-uuid] - (or ([= ?v ?val-uuid]) - [(contains? ?v ?val-uuid)])]] + [?prop-val-b :block/original-name ?str-val] + [?prop-val-b :block/uuid ?val-uuid] + (or ([= ?v ?val-uuid]) + [(contains? ?v ?val-uuid)])]] :has-property '[(has-property ?b ?prop) diff --git a/deps/db/test/logseq/db/frontend/rules_test.cljs b/deps/db/test/logseq/db/frontend/rules_test.cljs new file mode 100644 index 000000000..5f7185a93 --- /dev/null +++ b/deps/db/test/logseq/db/frontend/rules_test.cljs @@ -0,0 +1,100 @@ +(ns logseq.db.frontend.rules-test + (:require [cljs.test :refer [deftest is testing]] + [datascript.core :as d] + [logseq.db.frontend.schema :as db-schema] + [logseq.db.frontend.rules :as rules] + [logseq.db.sqlite.create-graph :as sqlite-create-graph] + [logseq.db.sqlite.util :as sqlite-util])) + +(defn- new-db-conn [] + (let [conn (d/create-conn db-schema/schema-for-db-based-graph) + _ (d/transact! conn (sqlite-create-graph/build-db-initial-data "{}"))] + conn)) + +(defn q-with-rules [query db] + ;; query assumes no :in given + (d/q (into query [:in '$ '%]) + db + (rules/extract-rules rules/db-query-dsl-rules))) + +(deftest has-page-property-rule + (let [conn (new-db-conn) + _ (d/transact! conn [(sqlite-util/build-new-property :user.property/foo "foo" {}) + (sqlite-util/build-new-property :user.property/foo2 "foo2" {}) + (assoc (sqlite-util/build-new-page "Page") :block/format :markdown) + {:block/original-name "Page" :user.property/foo "bar"}])] + (is (= ["Page"] + (->> (q-with-rules '[:find (pull ?b [:block/original-name]) :where (has-page-property ?b :user.property/foo)] + @conn) + (map (comp :block/original-name first)))) + "has-page-property returns result when page has property") + (is (= [] + (->> (q-with-rules '[:find (pull ?b [:block/original-name]) :where (has-page-property ?b :user.property/foo2)] + @conn) + (map (comp :block/original-name first)))) + "has-page-property returns no result when page doesn't have property") + (is (= [:user.property/foo] + (q-with-rules '[:find [?p ...] + :where (has-page-property ?b ?p) [?b :block/original-name "Page"]] + @conn)) + "has-page-property can bind to property arg"))) + +(deftest page-property-rule + (let [conn (new-db-conn) + _ (d/transact! conn [(sqlite-util/build-new-property :user.property/foo "foo" {}) + (sqlite-util/build-new-property :user.property/foo2 "foo2" {}) + (sqlite-util/build-new-property :user.property/number-many "number-many" {:type :number :cardinality :many}) + (assoc (sqlite-util/build-new-page "Page") :block/format :markdown) + {:block/original-name "Page" :user.property/foo "bar"} + {:block/original-name "Page" :user.property/number-many #{5 10}}])] + (testing "cardinality :one property" + (is (= ["Page"] + (->> (q-with-rules '[:find (pull ?b [:block/original-name]) :where (page-property ?b :user.property/foo "bar")] + @conn) + (map (comp :block/original-name first)))) + "page-property returns result when page has property") + (is (= [] + (->> (q-with-rules '[:find (pull ?b [:block/original-name]) :where (page-property ?b :user.property/foo "baz")] + @conn) + (map (comp :block/original-name first)))) + "page-property returns no result when page doesn't have property value") + (is (= #{:user.property/foo} + (->> (q-with-rules '[:find [?p ...] + :where (page-property ?b ?p "bar") [?b :block/original-name "Page"]] + @conn) + set)) + "page-property can bind to property arg with bound property value")) + + (testing "cardinality :many property" + (is (= ["Page"] + (->> (q-with-rules '[:find (pull ?b [:block/original-name]) :where (page-property ?b :user.property/number-many 5)] + @conn) + (map (comp :block/original-name first)))) + "page-property returns result when page has property") + (is (= [] + (->> (q-with-rules '[:find (pull ?b [:block/original-name]) :where (page-property ?b :user.property/number-many 20)] + @conn) + (map (comp :block/original-name first)))) + "page-property returns no result when page doesn't have property value") + (is (= #{:user.property/number-many} + (->> (q-with-rules '[:find [?p ...] + :where (page-property ?b ?p 5) [?b :block/original-name "Page"]] + @conn) + set)) + "page-property can bind to property arg with bound property value")) + + (testing "binding when property value is unspecified" + (is (= #{:user.property/foo :user.property/number-many} + (->> (q-with-rules '[:find [?p ...] + :where (page-property ?b ?p _) [?b :block/original-name "Page"]] + @conn) + set)) + "page-property can bind to property arg with unbound property value") + (is (= #{[:user.property/number-many 10] + [:user.property/number-many 5] + [:user.property/foo "bar"]} + (->> (q-with-rules '[:find ?p ?v + :where (page-property ?b ?p ?v) [?b :block/original-name "Page"]] + @conn) + set)) + "page-property can bind to property and property value args")))) \ No newline at end of file