mirror of
https://github.com/logseq/logseq.git
synced 2026-04-24 14:14:55 +00:00
fix: :and ref query should return nodes that having at least one ref (#12085)
This commit also adds a new :self-ref rule. `[[page]]` will uses :self-ref, `(or [[page1]] [[page2]])` will be `(or [:self-ref page1] [:self-ref page2]`. `(and [[page1]] [[page2]])` will be `(and [:page-ref page1] [:page-ref page2] (or [:self-ref page1] [:self-ref page2]))` to ensure the query result nodes to have at least one page reference.
This commit is contained in:
2
deps/db/bb.edn
vendored
2
deps/db/bb.edn
vendored
@@ -29,7 +29,7 @@
|
||||
:doc "Lint datalog rules for parsability and unbound variables"
|
||||
:task (datalog/lint-rules
|
||||
(set
|
||||
(concat (mapcat val (merge file-rules/rules rules/rules))
|
||||
(concat (mapcat val (merge file-rules/rules (dissoc rules/rules :self-ref)))
|
||||
;; TODO: Update linter to handle false positive on ?str-val for :property
|
||||
(rules/extract-rules (dissoc file-rules/query-dsl-rules :property))
|
||||
;; TODO: Update linter to handle false positive on :task, :priority, :*property* rules
|
||||
|
||||
5
deps/db/src/logseq/db/common/view.cljs
vendored
5
deps/db/src/logseq/db/common/view.cljs
vendored
@@ -455,8 +455,9 @@
|
||||
entities-result (if query?
|
||||
(keep (fn [id]
|
||||
(let [e (d/entity db id)]
|
||||
(when-not (contains? query-entity-ids (:db/id (:block/parent e)))
|
||||
e))) query-entity-ids)
|
||||
(when-not (= :logseq.property/query (:db/ident (:logseq.property/created-from-property e)))
|
||||
e)))
|
||||
query-entity-ids)
|
||||
(get-view-entities db view-id opts))
|
||||
entities (if (= feat-type :linked-references)
|
||||
(:ref-blocks entities-result)
|
||||
|
||||
5
deps/db/src/logseq/db/frontend/rules.cljc
vendored
5
deps/db/src/logseq/db/frontend/rules.cljc
vendored
@@ -32,6 +32,11 @@
|
||||
[?e1 :block/alias ?e2]
|
||||
[?e2 :block/alias ?e3]]]
|
||||
|
||||
:self-ref
|
||||
'[(self-ref ?b ?page-name)
|
||||
[?br :block/name ?page-name]
|
||||
[?b :block/refs ?br]]
|
||||
|
||||
:has-ref
|
||||
'[[(has-ref ?b ?r)
|
||||
[?b :block/refs ?r]]
|
||||
|
||||
@@ -381,11 +381,11 @@ independent of format as format specific heading characters are stripped"
|
||||
(->>
|
||||
(d/q
|
||||
'[:find [(pull ?block ?block-attrs) ...]
|
||||
:in $ % [?ref-page ...] ?block-attrs
|
||||
:in $ [?ref-page ...] ?block-attrs
|
||||
:where
|
||||
(has-ref ?block ?ref-page)]
|
||||
[?r :block/name ?ref-page]
|
||||
[?block :block/refs ?r]]
|
||||
db
|
||||
(rules/extract-rules rules/db-query-dsl-rules [:parent :has-ref])
|
||||
pages
|
||||
(butlast file-model/file-graph-block-attrs))
|
||||
(remove (fn [block] (= page-id (:db/id (:block/page block)))))
|
||||
|
||||
@@ -486,6 +486,13 @@
|
||||
{:query (list 'page-ref '?b page-name)
|
||||
:rules [:page-ref]}))
|
||||
|
||||
(defn- build-self-ref
|
||||
[e]
|
||||
(let [page-name (-> (page-ref/get-page-name! e)
|
||||
(util/page-name-sanity-lc))]
|
||||
{:query (list 'self-ref '?b page-name)
|
||||
:rules [:self-ref]}))
|
||||
|
||||
(defn- build-block-content [e]
|
||||
{:query (list 'block-content '?b e)
|
||||
:rules [:block-content]})
|
||||
@@ -532,7 +539,7 @@ Some bindings in this fn:
|
||||
* fe - the query operator e.g. `property`"
|
||||
([e env]
|
||||
(build-query e (assoc env :vars (atom {})) 0))
|
||||
([e {:keys [blocks? sample] :as env :or {blocks? (atom nil)}} level]
|
||||
([e {:keys [form blocks? sample current-filter] :as env :or {blocks? (atom nil)}} level]
|
||||
; {:post [(or (nil? %) (map? %))]}
|
||||
(let [fe (first e)
|
||||
fe (when fe
|
||||
@@ -547,7 +554,7 @@ Some bindings in this fn:
|
||||
(when (or
|
||||
(:db-graph? env)
|
||||
(and page-ref?
|
||||
(not (contains? #{'page-property 'page-tags} (:current-filter env))))
|
||||
(not (contains? #{'page-property 'page-tags} current-filter)))
|
||||
(contains? #{'between 'property 'private-property 'todo 'task 'priority 'page} fe)
|
||||
(and (not page-ref?) (string? e)))
|
||||
(reset! blocks? true))
|
||||
@@ -559,8 +566,13 @@ Some bindings in this fn:
|
||||
{:query [e]
|
||||
:rules []}
|
||||
|
||||
(and (= fe 'and) (every? page-ref/page-ref? (rest e)))
|
||||
(build-query (concat e [(cons 'or (rest e))]) env level)
|
||||
|
||||
page-ref?
|
||||
(build-page-ref e)
|
||||
(if (or (= current-filter 'or) (= form e))
|
||||
(build-self-ref e)
|
||||
(build-page-ref e))
|
||||
|
||||
(string? e) ; block content full-text search, could be slow
|
||||
(build-block-content e)
|
||||
@@ -688,7 +700,8 @@ Some bindings in this fn:
|
||||
sample (atom nil)
|
||||
form (simplify-query form)
|
||||
{result :query rules :rules}
|
||||
(when form (build-query form {:sort-by sort-by
|
||||
(when form (build-query form {:form form
|
||||
:sort-by sort-by
|
||||
:blocks? blocks?
|
||||
:db-graph? db-graph?
|
||||
:sample sample
|
||||
@@ -701,14 +714,19 @@ Some bindings in this fn:
|
||||
(keyword (first result)))]
|
||||
(add-bindings! (if (= key :and) (rest result) result) opts)))
|
||||
extract-rules (fn [rules]
|
||||
(rules/extract-rules rules/db-query-dsl-rules rules {:deps rules/rules-dependencies}))]
|
||||
(rules/extract-rules rules/db-query-dsl-rules rules {:deps rules/rules-dependencies}))
|
||||
rules' (if db-graph?
|
||||
(let [rules' (if (contains? (set rules) :page-ref)
|
||||
(conj (set rules) :self-ref)
|
||||
rules)]
|
||||
(extract-rules rules'))
|
||||
(->> (concat (map file-rules/query-dsl-rules (remove #{:page-ref} rules))
|
||||
(when (some #{:page-ref :self-ref} rules)
|
||||
(extract-rules [:self-ref :page-ref])))
|
||||
(remove nil?)
|
||||
vec))]
|
||||
{:query result'
|
||||
:rules (if db-graph?
|
||||
(extract-rules rules)
|
||||
(->> (concat (map file-rules/query-dsl-rules (remove #{:page-ref} rules))
|
||||
(when (some #{:page-ref} rules)
|
||||
(extract-rules [:page-ref])))
|
||||
vec))
|
||||
:rules rules'
|
||||
:sort-by @sort-by
|
||||
:blocks? (boolean @blocks?)
|
||||
:sample sample})))
|
||||
|
||||
@@ -598,6 +598,7 @@ prop-d:: [[nada]]"}])
|
||||
:file/content "foo:: bar
|
||||
- b1 [[page 1]] [[tag2]]
|
||||
- b2 [[page 2]] [[tag1]]
|
||||
- b4 [[page 4]] [[tag4]]
|
||||
- b3"}])
|
||||
|
||||
(testing "page-ref queries"
|
||||
@@ -625,9 +626,16 @@ prop-d:: [[nada]]"}])
|
||||
(dsl-query "(or [[tag2]] [[page 2]])")))
|
||||
"OR query")
|
||||
|
||||
(comment
|
||||
;; FIXME: load-test-files doesn't save `b4` to the db when DB_GRAPH=1
|
||||
(is (= ["b1" "b4"]
|
||||
(map testable-content
|
||||
(dsl-query "(or [[tag2]] [[page 4]])")))
|
||||
"OR query"))
|
||||
|
||||
(is (= ["b1"]
|
||||
(map testable-content
|
||||
(dsl-query "(or [[tag2]] [[page 3]])")))
|
||||
(dsl-query "(or [[tag2]] [[page not exists]])")))
|
||||
"OR query with nonexistent page should return meaningful results")
|
||||
|
||||
(is (= (if js/process.env.DB_GRAPH #{"b1" "bar" "b3"} #{"b1" "foo:: bar" "b3"})
|
||||
|
||||
Reference in New Issue
Block a user