mirror of https://github.com/logseq/logseq
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 rulespull/11196/head
parent
30d218169e
commit
c448e9a0d0
|
@ -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)
|
||||
|
|
|
@ -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"))))
|
Loading…
Reference in New Issue