1
0
Эх сурвалжийг харах

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.
Tienson Qin 1 сар өмнө
parent
commit
fa7cd07192

+ 1 - 1
deps/db/bb.edn

@@ -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

+ 3 - 2
deps/db/src/logseq/db/common/view.cljs

@@ -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 - 0
deps/db/src/logseq/db/frontend/rules.cljc

@@ -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]]

+ 3 - 3
src/main/frontend/db/model.cljs

@@ -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)))))

+ 29 - 11
src/main/frontend/db/query_dsl.cljs

@@ -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})))

+ 9 - 1
src/test/frontend/db/query_dsl_test.cljs

@@ -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"})