Просмотр исходного кода

fix: filters not work for linked references (#11937)

* fix: linked references

* Using datascript query for linked references

* don't render blocks children that have excluded refs

* fix: set persistent width for reference filter

* fix: duplicated refs

* fix: separate queries for children refs and non-children refs

* refactor: move reference fns to logseq.db.common.reference

* fix: set matched children ids even if it's empty

* add tests

* add unlinked reference test

* add transit files to typos ignore

* don't memoize on node

* add comment
Tienson Qin 6 месяцев назад
Родитель
Сommit
be66270a49

+ 1 - 1
deps/db/src/logseq/db/common/entity_plus.cljc

@@ -63,7 +63,7 @@
 
 (defn entity-memoized
   [db eid]
-  (if (qualified-keyword? eid)
+  (if (and (qualified-keyword? eid) (not (exists? js/process))) ; don't memoize on node
     (when-not (contains? nil-db-ident-entities eid) ;fast return nil
       (if (and @*reset-cache-background-task-running?
                (contains? immutable-db-ident-entities eid)) ;return cache entity if possible which isn't nil

+ 6 - 3
deps/db/src/logseq/db/common/initial_data.cljs

@@ -9,6 +9,7 @@
             [logseq.db.common.entity-plus :as entity-plus]
             [logseq.db.common.entity-util :as common-entity-util]
             [logseq.db.common.order :as db-order]
+            [logseq.db.frontend.class :as db-class]
             [logseq.db.frontend.entity-util :as entity-util]
             [logseq.db.frontend.rules :as rules]))
 
@@ -153,8 +154,7 @@
   [db block-uuid]
   (let [ids (get-block-children-ids db block-uuid)]
     (when (seq ids)
-      (let [ids' (map (fn [id] [:block/uuid id]) ids)]
-        (d/pull-many db '[*] ids')))))
+      (map (fn [id] (d/entity db [:block/uuid id])) ids))))
 
 (defn- with-raw-title
   [m entity]
@@ -180,7 +180,10 @@
          (= id (:db/id (:logseq.property/view-for ref-block)))
          (entity-util/hidden? (:block/page ref-block))
          (entity-util/hidden? ref-block)
-         (contains? (set (map :db/id (:block/tags ref-block))) (:db/id entity))
+         (and (entity-util/class? entity)
+              (let [children (db-class/get-structured-children db id)
+                    class-ids (set (conj children id))]
+                (some class-ids (map :db/id (:block/tags ref-block)))))
          (some? (get ref-block (:db/ident entity)))))
       (or
        (= (:db/id ref-block) id)

+ 146 - 0
deps/db/src/logseq/db/common/reference.cljs

@@ -0,0 +1,146 @@
+(ns logseq.db.common.reference
+  "References"
+  (:require [cljs.reader :as reader]
+            [clojure.string :as string]
+            [datascript.core :as d]
+            [logseq.common.log :as log]
+            [logseq.db :as ldb]
+            [logseq.db.common.entity-plus :as entity-plus]
+            [logseq.db.common.initial-data :as common-initial-data]
+            [logseq.db.frontend.class :as db-class]
+            [logseq.db.frontend.rules :as rules]))
+
+(defn get-filters
+  [db page]
+  (let [db-based? (entity-plus/db-based-graph? db)]
+    (if db-based?
+      (let [included-pages (:logseq.property.linked-references/includes page)
+            excluded-pages (:logseq.property.linked-references/excludes page)]
+        (when (or (seq included-pages) (seq excluded-pages))
+          {:included included-pages
+           :excluded excluded-pages}))
+      (let [k :filters
+            properties (:block/properties page)
+            properties-str (or (get properties k) "{}")]
+        (try (let [result (reader/read-string properties-str)]
+               (when (seq result)
+                 (let [excluded-pages (->> (filter #(false? (second %)) result)
+                                           (keep first)
+                                           (keep #(ldb/get-page db %)))
+                       included-pages (->> (filter #(true? (second %)) result)
+                                           (keep first)
+                                           (keep #(ldb/get-page db %)))]
+                   {:included included-pages
+                    :excluded excluded-pages})))
+             (catch :default e
+               (log/error :syntax/filters e)))))))
+
+(defn- build-include-exclude-query
+  [variable includes excludes]
+  (concat
+   (for [include includes]
+     [variable :block/path-refs include])
+   (for [exclude excludes]
+     (list 'not [variable :block/path-refs exclude]))))
+
+(defn- filter-refs-children-query
+  [includes excludes class-ids]
+  (let [clauses (concat
+                 [;; find refs from refed block's children only
+                  '(block-parent ?b ?c)
+                  ;; find all levels of parents
+                  '(block-parent ?p ?c)]
+                 (build-include-exclude-query '?c includes excludes)
+                 (when class-ids
+                   (mapcat
+                    (fn [class-id]
+                      (map
+                       (fn [variable]
+                         (list 'not [variable :block/tags class-id]))
+                       ['?b '?p '?c]))
+                    class-ids)))]
+    (into [:find '?b '?p '?c
+           :in '$ '% '[?id ...]
+           :where
+           ['?b :block/refs '?id]]
+          clauses)))
+
+(defn- filter-refs-query
+  [includes excludes class-ids]
+  (let [clauses (concat
+                 (build-include-exclude-query '?b includes excludes)
+                 (for [class-id class-ids]
+                   (list 'not ['?b :block/tags class-id])))]
+    (into [:find '[?b ...]
+           :in '$ '% '[?id ...]
+           :where
+           ['?b :block/refs '?id]]
+          clauses)))
+
+(defn- remove-hidden-ref
+  [db page-id refs]
+  (remove (fn [block] (common-initial-data/hidden-ref? db block page-id)) refs))
+
+(defn- get-ref-pages-count
+  [db id ref-blocks children-ids]
+  (when (seq ref-blocks)
+    (let [children (->> children-ids
+                        (map (fn [id] (d/entity db id)))
+                        (remove-hidden-ref db id))]
+      (->> (concat (mapcat :block/path-refs ref-blocks)
+                   (mapcat :block/refs children))
+           frequencies
+           (keep (fn [[ref size]]
+                   (when (and (ldb/page? ref)
+                              (not= (:db/id ref) id)
+                              (not= :block/tags (:db/ident ref))
+                              (not (common-initial-data/hidden-ref? db ref id)))
+                     [(:block/title ref) size])))
+           (sort-by second #(> %1 %2))))))
+
+(defn get-linked-references
+  [db id]
+  (let [entity (d/entity db id)
+        ids (set (cons id (ldb/get-block-alias db id)))
+        page-filters (get-filters db entity)
+        excludes (map :db/id (:excluded page-filters))
+        includes (map :db/id (:included page-filters))
+        filter-exists? (or (seq excludes) (seq includes))
+        class-ids (when (ldb/class? entity)
+                    (let [class-children (db-class/get-structured-children db id)]
+                      (set (conj class-children id))))
+        rules (rules/extract-rules rules/db-query-dsl-rules [:block-parent] {})
+        ref-blocks-query-result (d/q (filter-refs-query includes excludes class-ids) db rules ids)
+        children-query-result (d/q (filter-refs-children-query includes excludes class-ids) db rules ids)
+        ref-blocks (->> (map first children-query-result)
+                        (concat ref-blocks-query-result)
+                        distinct
+                        (map (fn [id] (d/entity db id)))
+                        (remove-hidden-ref db id))
+        children-ids (->>
+                      (distinct (concat
+                                 (map second children-query-result)
+                                 (map last children-query-result)))
+                      (remove (set (map :db/id ref-blocks))))
+        ref-pages-count (get-ref-pages-count db id ref-blocks children-ids)]
+    {:ref-pages-count ref-pages-count
+     :ref-blocks ref-blocks
+     :ref-matched-children-ids (when filter-exists? (set children-ids))}))
+
+(defn get-unlinked-references
+  [db id]
+  (let [entity (d/entity db id)
+        title (string/lower-case (:block/title entity))]
+    (when-not (string/blank? title)
+      (let [ids (->> (d/datoms db :avet :block/title)
+                     (keep (fn [d]
+                             (when (and (not= id (:e d)) (string/includes? (string/lower-case (:v d)) title))
+                               (:e d)))))]
+        (keep
+         (fn [eid]
+           (let [e (d/entity db eid)]
+             (when-not (or (some #(= id %) (map :db/id (:block/refs e)))
+                           (:block/link e)
+                           (ldb/built-in? e))
+               e)))
+         ids)))))

+ 5 - 99
deps/db/src/logseq/db/common/view.cljs

@@ -1,15 +1,13 @@
 (ns logseq.db.common.view
   "Main namespace for view fns."
-  (:require [cljs.reader :as reader]
-            [clojure.set :as set]
+  (:require [clojure.set :as set]
             [clojure.string :as string]
             [datascript.core :as d]
             [datascript.impl.entity :as de]
-            [logseq.common.log :as log]
             [logseq.common.util :as common-util]
             [logseq.db :as ldb]
             [logseq.db.common.entity-plus :as entity-plus]
-            [logseq.db.common.initial-data :as common-initial-data]
+            [logseq.db.common.reference :as db-reference]
             [logseq.db.frontend.class :as db-class]
             [logseq.db.frontend.entity-util :as entity-util]
             [logseq.db.frontend.property :as db-property]
@@ -263,98 +261,6 @@
             result)))
       (:filters filters)))))
 
-(defn filter-blocks
-  [filters ref-blocks]
-  (let [exclude-ids (set (map :db/id (:excluded filters)))
-        include-ids (set (map :db/id (:included filters)))
-        get-ids (fn [block]
-                  (set (map :db/id (:block/path-refs block))))]
-    (cond->> ref-blocks
-      (seq exclude-ids)
-      (remove (fn [block]
-                (let [ids (get-ids block)]
-                  (seq (set/intersection exclude-ids ids)))))
-
-      (seq include-ids)
-      (filter (fn [block]
-                (let [ids (get-ids block)]
-                  (set/subset? include-ids ids)))))))
-
-(defn get-filters
-  [db page]
-  (let [db-based? (entity-plus/db-based-graph? db)]
-    (if db-based?
-      (let [included-pages (:logseq.property.linked-references/includes page)
-            excluded-pages (:logseq.property.linked-references/excludes page)]
-        (when (or (seq included-pages) (seq excluded-pages))
-          {:included included-pages
-           :excluded excluded-pages}))
-      (let [k :filters
-            properties (:block/properties page)
-            properties-str (or (get properties k) "{}")]
-        (try (let [result (reader/read-string properties-str)]
-               (when (seq result)
-                 (let [excluded-pages (->> (filter #(false? (second %)) result)
-                                           (keep first)
-                                           (keep #(ldb/get-page db %)))
-                       included-pages (->> (filter #(true? (second %)) result)
-                                           (keep first)
-                                           (keep #(ldb/get-page db %)))]
-                   {:included included-pages
-                    :excluded excluded-pages})))
-             (catch :default e
-               (log/error :syntax/filters e)))))))
-
-(defn- get-linked-references
-  [db id]
-  (let [entity (d/entity db id)
-        ids (set (cons id (ldb/get-block-alias db id)))
-        refs (mapcat (fn [id] (:block/_path-refs (d/entity db id))) ids)
-        page-filters (get-filters db entity)
-        full-ref-blocks (->> refs
-                             (remove (fn [block] (common-initial-data/hidden-ref? db block id)))
-                             (common-util/distinct-by :db/id))
-        ref-blocks (cond->> full-ref-blocks
-                     (seq page-filters)
-                     (filter-blocks page-filters))
-        ref-pages-count (->> ref-blocks
-                             (remove (fn [block]
-                                       (common-initial-data/hidden-ref? db block id)))
-                             (mapcat (fn [block]
-                                       (->>
-                                        (cons
-                                         (:block/title (:block/page block))
-                                         (map (fn [b]
-                                                (when (and (ldb/page? b)
-                                                           (not= (:db/id b) id)
-                                                           (not (contains? #{:block/tags} (:db/ident b))))
-                                                  (:block/title b)))
-                                              (:block/path-refs block)))
-                                        distinct)))
-                             (remove nil?)
-                             (frequencies)
-                             (sort-by second #(> %1 %2)))]
-    {:ref-pages-count ref-pages-count
-     :ref-blocks ref-blocks}))
-
-(defn- get-unlinked-references
-  [db id]
-  (let [entity (d/entity db id)
-        title (string/lower-case (:block/title entity))]
-    (when-not (string/blank? title)
-      (let [ids (->> (d/datoms db :avet :block/title)
-                     (keep (fn [d]
-                             (when (and (not= id (:e d)) (string/includes? (string/lower-case (:v d)) title))
-                               (:e d)))))]
-        (keep
-         (fn [eid]
-           (let [e (d/entity db eid)]
-             (when-not (or (some #(= id %) (map :db/id (:block/refs e)))
-                           (:block/link e)
-                           (ldb/built-in? e))
-               e)))
-         ids)))))
-
 (defn- get-exclude-page-ids
   [db]
   (->>
@@ -413,10 +319,10 @@
        (keep (fn [id] (non-hidden-e id))))
 
       :linked-references
-      (get-linked-references db view-for-id)
+      (db-reference/get-linked-references db view-for-id)
 
       :unlinked-references
-      (get-unlinked-references db view-for-id)
+      (db-reference/get-unlinked-references db view-for-id)
 
       :query-result
       nil
@@ -589,6 +495,6 @@
        {:count (count filtered-entities)
         :data (distinct data')}
         (= feat-type :linked-references)
-        (assoc :ref-pages-count (:ref-pages-count entities-result))
+        (merge (select-keys entities-result [:ref-pages-count :ref-matched-children-ids]))
         query?
         (assoc :properties (get-query-properties entities-result))))))

+ 7 - 1
deps/db/src/logseq/db/file_based/rules.cljc

@@ -14,7 +14,13 @@
   "Rules used by frontend.db.query-dsl for file graphs. The symbols ?b and ?p
   respectively refer to block and page. Do not alter them as they are
   programmatically built by the query-dsl ns"
-  {:page-property
+  {:block-parent
+   '[[(block-parent ?p ?c)
+      [?c :block/parent ?p]]
+     [(block-parent ?p ?c)
+      [?t :block/parent ?p]
+      (block-parent ?t ?c)]]
+   :page-property
    '[(page-property ?p ?key ?val)
      [?p :block/name]
      [?p :block/properties ?prop]

+ 1 - 2
deps/shui/src/logseq/shui/base/core.cljs

@@ -51,8 +51,7 @@
           {:variant variant
            :data-button :icon
            :style (when size {:width size :height size})})
-   (tabler-icon/root (name icon-name) (merge {:size 20
-                                              :key "icon"} icon-props))
+   (tabler-icon/root (name icon-name) (merge {:size 20} icon-props))
    child))
 
 (def button-ghost-icon (partial button-icon :ghost))

+ 7 - 3
src/main/frontend/components/block.cljs

@@ -2117,7 +2117,11 @@
   (let [ref?        (:ref? config)
         query?      (:custom-query? config)
         children    (when (coll? children)
-                      (remove nil? children))]
+                      (let [ref-matched-children-ids (:ref-matched-children-ids config)]
+                        (cond->> (remove nil? children)
+                          ref-matched-children-ids
+                          ;; Block children will not be rendered if the filters do not match them
+                          (filter (fn [b] (ref-matched-children-ids (:db/id b)))))))]
     (when (and (coll? children)
                (seq children)
                (not collapsed?))
@@ -3261,7 +3265,7 @@
                                         (rum/with-key (breadcrumb-fragment config block label opts)
                                           (str (:block/uuid block))))
                                       [:span.opacity-70 {:key "dots"} "⋯"])))
-                             (interpose (rum/with-key (breadcrumb-separator) "icon")))]
+                             (interpose (breadcrumb-separator)))]
         (when (seq breadcrumbs)
           [:div.breadcrumb.block-parents
            {:class (when (seq breadcrumbs)
@@ -3761,7 +3765,7 @@
 
 (defn- config-block-should-update?
   [old-state new-state]
-  (let [config-compare-keys [:show-cloze? :hide-children? :own-order-list-type :own-order-list-index :original-block :edit? :hide-bullet?]
+  (let [config-compare-keys [:show-cloze? :hide-children? :own-order-list-type :own-order-list-index :original-block :edit? :hide-bullet? :ref-matched-children-ids]
         b1                  (second (:rum/args old-state))
         b2                  (second (:rum/args new-state))
         result              (or

+ 2 - 2
src/main/frontend/components/reference.cljs

@@ -7,7 +7,7 @@
             [frontend.db-mixins :as db-mixins]
             [frontend.state :as state]
             [frontend.ui :as ui]
-            [logseq.db.common.view :as db-view]
+            [logseq.db.common.reference :as db-reference]
             [logseq.shui.hooks :as hooks]
             [logseq.shui.ui :as shui]
             [missionary.core :as m]
@@ -15,7 +15,7 @@
 
 (rum/defc references-aux
   [page-entity config]
-  (let [filters (db-view/get-filters (db/get-db) page-entity)
+  (let [filters (db-reference/get-filters (db/get-db) page-entity)
         reference-filter (fn [{:keys [ref-pages-count]}]
                            (shui/button
                             {:title "Page filter"

+ 9 - 1
src/main/frontend/components/reference.css

@@ -15,7 +15,15 @@
 }
 
 .ls-filters {
-  max-width: 704px;
+    @screen md {
+        min-width: 700px;
+        width: 700px;
+    }
+
+    @screen sm {
+        min-width: 600px;
+        width: 600px;
+    }
 }
 
 .custom-query-page-result {

+ 2 - 2
src/main/frontend/components/reference_filters.cljs

@@ -11,7 +11,7 @@
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.util :as util]
-            [logseq.db.common.view :as db-view]
+            [logseq.db.common.reference :as db-reference]
             [logseq.shui.hooks :as hooks]
             [promesa.core :as p]
             [rum.core :as rum]))
@@ -75,7 +75,7 @@
   [page-entity references]
   (let [[filter-search set-filter-search!] (hooks/use-state "")
         [filtered-references set-filtered-references!] (hooks/use-state references)
-        filters (db-view/get-filters (db/get-db) page-entity)
+        filters (db-reference/get-filters (db/get-db) page-entity)
         {:keys [included excluded]} filters]
     (hooks/use-effect!
      (fn []

+ 23 - 8
src/main/frontend/components/views.cljs

@@ -1524,11 +1524,17 @@
            (shui/table-footer (add-new-row (:view-entity option) table)))]]))))
 
 (rum/defc list-view < rum/static
-  [{:keys [config] :as option} _view-entity {:keys [rows]} *scroller-ref]
+  [{:keys [config ref-matched-children-ids] :as option} view-entity {:keys [rows]} *scroller-ref]
   (let [lazy-item-render (fn [rows idx]
                            (lazy-item rows idx (assoc option :list-view? true)
                                       (fn [block]
-                                        (block-container (assoc config :list-view? true :block-level 1) block))))
+                                        (let [config' (cond->
+                                                       (assoc config
+                                                              :list-view? true
+                                                              :block-level 1)
+                                                        (= :linked-references (:logseq.property.view/feature-type view-entity))
+                                                        (assoc :ref-matched-children-ids ref-matched-children-ids))]
+                                          (block-container config' block)))))
         list-cp (fn [rows]
                   (when (seq rows)
                     (ui/virtualized-list
@@ -2022,7 +2028,7 @@
 (defn- load-view-data-aux
   [view-entity view-parent {:keys [query? query-entity-ids sorting filters input
                                    view-feature-type group-by-property-ident
-                                   set-data! set-ref-pages-count! set-properties! set-loading!]}]
+                                   set-data! set-ref-pages-count! set-ref-matched-children-ids! set-properties! set-loading!]}]
   (c.m/run-task*
    (m/sp
      (let [need-query? (and query? (seq query-entity-ids) (or sorting filters (not (string/blank? input))))]
@@ -2034,7 +2040,7 @@
          :else
          (when (or (not query?) need-query?)
            (try
-             (let [{:keys [data ref-pages-count properties]}
+             (let [{:keys [data ref-pages-count ref-matched-children-ids properties]}
                    (c.m/<?
                     (<load-view-data view-entity
                                      (cond->
@@ -2049,7 +2055,8 @@
                                        (assoc :query-entity-ids query-entity-ids))))]
                (set-data! data)
                (when ref-pages-count
-                 (set-ref-pages-count! ref-pages-count))
+                 (set-ref-pages-count! ref-pages-count)
+                 (set-ref-matched-children-ids! ref-matched-children-ids))
                (set-properties! properties))
              (finally
                (set-loading! false)))))))))
@@ -2086,13 +2093,14 @@
         [loading? set-loading!] (hooks/use-state (not query?))
         [data set-data!] (hooks/use-state data)
         [ref-pages-count set-ref-pages-count!] (hooks/use-state nil)
+        [ref-matched-children-ids set-ref-matched-children-ids!] (hooks/use-state nil)
         load-view-data (fn load-view-data []
                          (load-view-data-aux view-entity view-parent
                                              {:query? query?
                                               :query-entity-ids query-entity-ids
                                               :sorting sorting :filters filters :input input
                                               :view-feature-type view-feature-type :group-by-property-ident group-by-property-ident
-                                              :set-data! set-data! :set-ref-pages-count! set-ref-pages-count!
+                                              :set-data! set-data! :set-ref-pages-count! set-ref-pages-count! :set-ref-matched-children-ids! set-ref-matched-children-ids!
                                               :set-properties! set-properties! :set-loading! set-loading!}))]
     (let [sorting-filters {:sorting sorting
                            :filters filters}]
@@ -2126,10 +2134,17 @@
                                           :items-count (if (every? number? data)
                                                          (count data)
                                                          ;; grouped
-                                                         (reduce (fn [total [_ col]]
-                                                                   (+ total (count col))) 0 data))
+                                                         (let [f (fn count-col
+                                                                   [data]
+                                                                   (reduce (fn [total [_k col]]
+                                                                             (if (and (vector? (first col))
+                                                                                      (uuid? (ffirst col)))
+                                                                               (+ total (count-col col))
+                                                                               (+ total (count col)))) 0 data))]
+                                                           (f data)))
                                           :group-by-property-ident group-by-property-ident
                                           :ref-pages-count ref-pages-count
+                                          :ref-matched-children-ids ref-matched-children-ids
                                           :display-type display-type
                                           :load-view-data load-view-data
                                           :set-view-entity! set-view-entity!))])))

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/test/fixtures/references.transit


+ 182 - 0
src/test/frontend/db/reference_test.cljs

@@ -0,0 +1,182 @@
+(ns frontend.db.reference-test
+  (:require [cljs.test :refer [deftest is testing]]
+            [datascript.core :as d]
+            [logseq.db :as ldb]
+            [logseq.db.common.reference :as db-reference]
+            [shadow.resource :as rc]))
+
+(def test-transit (rc/inline "fixtures/references.transit"))
+;; (use-fixtures :each test-helper/db-based-start-and-destroy-db)
+
+(defn- create-conn!
+  []
+  (let [db (ldb/read-transit-str test-transit)]
+    (d/conn-from-db db)))
+
+;; FIXME: EDN import doesn't work
+(comment
+  (def test-page-blocks
+    {:pages-and-blocks
+     [{:page
+       {:build/journal 20250611},
+       :blocks
+       [{:block/title "[[68485f78-1e70-4173-a569-1ebcb2ba69e6]] 1",
+         :build/children
+         [{:block/title "[[68485f7a-d9c1-495a-a364-e7aae6ab0147]] 1",
+           :build/children
+           [{:block/title "test",
+             :build/children
+             [{:block/title "[[68485f7f-3de9-46d3-a1e5-50a7d052066e]] 1"}]}
+            {:block/title "another test",
+             :build/children
+             [{:block/title "[[68485f7f-3de9-46d3-a1e5-50a7d052066e]] 2"}]}]}
+          {:block/title "[[68485f7f-3de9-46d3-a1e5-50a7d052066e]] 3"}]}
+        {:block/title "[[68485f78-1e70-4173-a569-1ebcb2ba69e6]] 2",
+         :build/children
+         [{:block/title "[[68485f7f-3de9-46d3-a1e5-50a7d052066e]] 4",
+           :build/children
+           [{:block/title "[[68485f7a-d9c1-495a-a364-e7aae6ab0147]] 1"}]}]}]}
+      {:page
+       {:block/title "bar",
+        :block/uuid #uuid "68485f7a-d9c1-495a-a364-e7aae6ab0147",
+        :build/keep-uuid? true}}
+      {:page
+       {:block/title "baz",
+        :block/uuid #uuid "68485f7f-3de9-46d3-a1e5-50a7d052066e",
+        :build/keep-uuid? true}}
+      {:page
+       {:block/title "foo",
+        :block/uuid #uuid "68485f78-1e70-4173-a569-1ebcb2ba69e6",
+        :build/keep-uuid? true}}],
+     :logseq.db.sqlite.export/export-type :page}))
+
+(comment
+  (defn- import-edn!
+    [conn data]
+    (let [{:keys [init-tx block-props-tx misc-tx error] :as _txs} (sqlite-export/build-import data @conn {})]
+      (when error
+        (throw (ex-info "Build import failed" {:data test-page-blocks})))
+      (d/transact! conn init-tx)
+      (when (seq block-props-tx)
+        (d/transact! conn block-props-tx))
+      (when (seq misc-tx)
+        (d/transact! conn misc-tx)))))
+
+(defn- retract-filters!
+  [conn foo-id]
+  (d/transact! conn [[:db/retract foo-id :logseq.property.linked-references/includes]
+                     [:db/retract foo-id :logseq.property.linked-references/excludes]]))
+
+(deftest ^:large-vars/cleanup-todo get-linked-references
+  (let [conn (create-conn!)
+        foo-id (:db/id (ldb/get-page @conn "foo"))
+        _ (retract-filters! conn foo-id)
+        db @conn
+        [foo bar baz] (map #(ldb/get-page @conn %) ["foo" "bar" "baz"])]
+
+    (testing "Linked references without filters"
+      (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references db (:db/id foo))]
+        (is (= [["baz" 4] ["Journal" 3] ["Jun 11th, 2025" 2] ["bar" 2]] (vec ref-pages-count))
+            "ref-pages-count check failed")
+        (is (empty? ref-matched-children-ids)
+            "ref-matched-children-ids check failed")
+        (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
+            "ref-blocks check failed")))
+
+    (testing "Linked references include \"bar\""
+      (d/transact! conn
+                   [{:db/id (:db/id foo)
+                     :logseq.property.linked-references/includes (:db/id bar)}])
+      (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
+        (is (= [["Journal" 3] ["baz" 3] ["Jun 11th, 2025" 2] ["bar" 2]] (vec ref-pages-count))
+            "ref-pages-count check failed")
+        (is (= 8 (count ref-matched-children-ids))
+            "ref-matched-children-ids check failed")
+        (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
+            "ref-blocks check failed")))
+
+    (testing "Linked references include \"bar\" and \"baz\""
+      (d/transact! conn
+                   [{:db/id (:db/id foo)
+                     :logseq.property.linked-references/includes (:db/id baz)}])
+      (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
+        (is (= [["Journal" 3] ["baz" 3] ["Jun 11th, 2025" 2] ["bar" 2]] (vec ref-pages-count))
+            "ref-pages-count check failed")
+        (is (= 8 (count ref-matched-children-ids))
+            "ref-matched-children-ids check failed")
+        (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
+            "ref-blocks check failed")))
+
+    (testing "Linked references exclude \"bar\""
+      (retract-filters! conn foo-id)
+      (d/transact! conn
+                   [{:db/id (:db/id foo)
+                     :logseq.property.linked-references/excludes (:db/id bar)}])
+      (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
+        (is (= [["Journal" 3] ["Jun 11th, 2025" 2] ["baz" 2]] (vec ref-pages-count))
+            "ref-pages-count check failed")
+        (is (= 3 (count ref-matched-children-ids))
+            "ref-matched-children-ids check failed")
+        (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
+            "ref-blocks check failed")))
+
+    (testing "Linked references exclude \"baz\""
+      (retract-filters! conn foo-id)
+      (d/transact! conn
+                   [{:db/id (:db/id foo)
+                     :logseq.property.linked-references/excludes (:db/id baz)}])
+      (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
+        (is (= [["Journal" 3] ["Jun 11th, 2025" 2] ["bar" 1]] (vec ref-pages-count))
+            "ref-pages-count check failed")
+        (is (= 4 (count ref-matched-children-ids))
+            "ref-matched-children-ids check failed")
+        (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
+            "ref-blocks check failed")))
+
+    (testing "Linked references exclude both \"baz\" and \"bar\""
+      (retract-filters! conn foo-id)
+      (d/transact! conn
+                   [{:db/id (:db/id foo)
+                     :logseq.property.linked-references/excludes #{(:db/id baz) (:db/id bar)}}])
+      (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
+        (is (= [["Journal" 2] ["Jun 11th, 2025" 2]] (vec ref-pages-count))
+            "ref-pages-count check failed")
+        (is (zero? (count ref-matched-children-ids))
+            "ref-matched-children-ids check failed")
+        (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
+            "ref-blocks check failed")))
+
+    (testing "Linked references includes \"bar\" and excludes \"baz\""
+      (retract-filters! conn foo-id)
+      (d/transact! conn
+                   [{:db/id (:db/id foo)
+                     :logseq.property.linked-references/includes (:db/id bar)
+                     :logseq.property.linked-references/excludes (:db/id baz)}])
+      (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
+        (is (= [["Journal" 2] ["Jun 11th, 2025" 1] ["bar" 1]] (vec ref-pages-count))
+            "ref-pages-count check failed")
+        (is (= 4 (count ref-matched-children-ids))
+            "ref-matched-children-ids check failed")
+        (is (= #{"[[foo]] 1"} (set (map :block/title ref-blocks)))
+            "ref-blocks check failed")))
+
+    (testing "Linked references includes \"baz\" and excludes \"bar\""
+      (retract-filters! conn foo-id)
+      (d/transact! conn
+                   [{:db/id (:db/id foo)
+                     :logseq.property.linked-references/includes (:db/id baz)
+                     :logseq.property.linked-references/excludes (:db/id bar)}])
+      (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
+        (is (= [["Journal" 3] ["Jun 11th, 2025" 2] ["baz" 2]] (vec ref-pages-count))
+            "ref-pages-count check failed")
+        (is (= 3 (count ref-matched-children-ids))
+            "ref-matched-children-ids check failed")
+        (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
+            "ref-blocks check failed")))))
+
+(deftest get-unlinked-references
+  (let [conn (create-conn!)
+        db @conn
+        ids (map #(:db/id (ldb/get-page @conn %)) ["foo" "bar" "baz"])]
+    (is (= [3 2 3]
+           (mapv #(count (db-reference/get-unlinked-references db %)) ids)))))

+ 1 - 1
typos.toml

@@ -18,4 +18,4 @@ fom = "fom"
 tne = "tne"
 Damon = "Damon"
 [files]
-extend-exclude = ["resources/*", "src/resources/*", "scripts/resources/*", "e2e-tests/plugin/lsplugin.user.js"]
+extend-exclude = ["resources/*", "src/resources/*", "scripts/resources/*", "e2e-tests/plugin/lsplugin.user.js", "src/test/fixtures/*"]

Некоторые файлы не были показаны из-за большого количества измененных файлов