diff --git a/src/main/frontend/worker/react.cljs b/src/main/frontend/worker/react.cljs index 37183197e1..7c8e1038fe 100644 --- a/src/main/frontend/worker/react.cljs +++ b/src/main/frontend/worker/react.cljs @@ -2,7 +2,8 @@ "Compute reactive query affected keys" (:require [cljs.spec.alpha :as s] [datascript.core :as d] - [logseq.common.util :as common-util])) + [logseq.common.util :as common-util] + [logseq.db.frontend.property :as db-property])) ;;; keywords specs for reactive query, used by `react/q` calls ;; ::block @@ -41,6 +42,96 @@ (= journal-tag-id (:db/id tag))) (:block/tags (d/entity db eid))))) +(def ^:private block-query-affecting-attrs + #{:logseq.property/order-list-type}) + +(def ^:private order-list-affecting-attrs + #{:block/parent :block/page :block/order :logseq.property/order-list-type}) + +(defn- block-attr? + [attr] + (= "block" (namespace attr))) + +(defn- block-query-affecting-attr? + [attr] + (or (block-attr? attr) + (contains? block-query-affecting-attrs attr))) + +(defn- block-key + [block] + [::block (:db/id block)]) + +(defn- order-list-type + [block] + (db-property/lookup block :logseq.property/order-list-type)) + +(defn- sibling-entities + [block] + (cond + (:block/parent block) + (some-> (:block/parent block) :block/_parent) + + (:block/page block) + (some-> (:block/page block) :block/_page) + + :else + nil)) + +(defn- ordered-siblings + [block] + (some->> (sibling-entities block) + (sort-by :block/order))) + +(defn- right-ordered-siblings + [block] + (when-let [siblings (seq (ordered-siblings block))] + (->> siblings + (drop-while #(not= (:db/id %) (:db/id block))) + rest))) + +(defn- collect-right-order-list-sibling-keys + [siblings target-order-list-type] + (when target-order-list-type + (->> siblings + (take-while #(= target-order-list-type (order-list-type %))) + (map block-key)))) + +(defn- affected-right-order-list-sibling-keys + [db block-id] + (when-let [block (and db (d/entity db block-id))] + (let [right-siblings (right-ordered-siblings block) + right-sibling (first right-siblings)] + (concat + (collect-right-order-list-sibling-keys right-siblings (order-list-type block)) + (collect-right-order-list-sibling-keys right-siblings (order-list-type right-sibling)))))) + +(defn- affected-order-list-descendant-keys + [db block-id] + (when-let [block (and db (d/entity db block-id))] + (letfn [(collect [parent] + (when-let [parent-list-type (order-list-type parent)] + (mapcat + (fn [child] + (when (= parent-list-type (order-list-type child)) + (cons (block-key child) (collect child)))) + (:block/_parent parent))))] + (collect block)))) + +(defn- affected-block-keys + [block] + (let [page-id (or + (when (:block/name block) (:db/id block)) + (:db/id (:block/page block))) + blocks [(when-let [parent-id (:db/id (:block/parent block))] + [::block parent-id]) + [::block (:db/id block)]] + refs (->> (keep (fn [ref] + (when-not (= (:db/id ref) page-id) + [[::refs (:db/id ref)] + [::block (:db/id ref)]])) (:block/refs block)) + (apply concat))] + (concat blocks refs))) + (defn get-affected-queries-keys "Get affected queries through transaction datoms." [{:keys [tx-data db-before db-after]}] @@ -77,8 +168,12 @@ recycle-roots? (some (fn [datom] (= :logseq.property/deleted-at (:a datom))) tx-data) - other-blocks (->> (filter (fn [datom] (= "block" (namespace (:a datom)))) tx-data) + other-blocks (->> (filter (fn [datom] (block-query-affecting-attr? (:a datom))) tx-data) (map :e)) + order-list-affected-blocks (->> (filter (fn [datom] + (contains? order-list-affecting-attrs (:a datom))) tx-data) + (map :e) + (distinct)) blocks (-> (concat blocks other-blocks) distinct) block-entities (keep (fn [block-id] (let [block-id (if (and (string? block-id) (common-util/uuid-string? block-id)) @@ -87,20 +182,7 @@ (d/entity db-after block-id))) blocks) affected-keys (concat (mapcat - (fn [block] - (let [page-id (or - (when (:block/name block) (:db/id block)) - (:db/id (:block/page block))) - blocks [(when-let [parent-id (:db/id (:block/parent block))] - [::block parent-id]) - [::block (:db/id block)]] - block-refs (:block/refs block) - refs (->> (keep (fn [ref] - (when-not (= (:db/id ref) page-id) - [[::refs (:db/id ref)] - [::block (:db/id ref)]])) block-refs) - (apply concat))] - (concat blocks refs))) + affected-block-keys block-entities) (mapcat @@ -115,6 +197,15 @@ [::block target-id]]) reaction-targets) + (mapcat + (fn [block-id] + (concat + (affected-right-order-list-sibling-keys db-before block-id) + (affected-right-order-list-sibling-keys db-after block-id) + (affected-order-list-descendant-keys db-before block-id) + (affected-order-list-descendant-keys db-after block-id))) + order-list-affected-blocks) + (keep (fn [tag] (when tag [::objects tag])) diff --git a/src/test/frontend/worker/react_test.cljs b/src/test/frontend/worker/react_test.cljs index 337ff2a755..46a8ec137d 100644 --- a/src/test/frontend/worker/react_test.cljs +++ b/src/test/frontend/worker/react_test.cljs @@ -2,6 +2,7 @@ (:require [cljs.test :refer [deftest is testing]] [datascript.core :as d] [frontend.worker.react :as worker-react] + [logseq.db.common.order :as db-order] [logseq.db.test.helper :as db-test])) (deftest affected-keys-block-reactions @@ -20,6 +21,66 @@ affected (worker-react/get-affected-queries-keys tx-report)] (is (some #{[:frontend.worker.react/block-reactions target-id]} affected))))) +(deftest affected-keys-order-list-type + (testing "changing order list type affects block query key" + (let [conn (db-test/create-conn-with-blocks + [{:page {:block/title "Test"} + :blocks [{:block/title "Block" + :build/properties {:logseq.property/order-list-type "number"}}]}]) + block (db-test/find-block-by-content @conn "Block") + target-id (:db/id block) + tx-report (d/transact! conn + [[:db/retract target-id :logseq.property/order-list-type + (:db/id (:logseq.property/order-list-type block))]]) + affected (worker-react/get-affected-queries-keys tx-report)] + (is (some #{[:frontend.worker.react/block target-id]} affected))))) + +(deftest affected-keys-order-list-right-siblings + (testing "inserting a block before ordered-list siblings affects their block query keys" + (let [conn (db-test/create-conn-with-blocks + [{:page {:block/title "Test"} + :blocks [{:block/title "Block 1" + :build/properties {:logseq.property/order-list-type "number"}} + {:block/title "Block 2" + :build/properties {:logseq.property/order-list-type "number"}} + {:block/title "Block 3" + :build/properties {:logseq.property/order-list-type "number"}}]}]) + block-1 (db-test/find-block-by-content @conn "Block 1") + block-2 (db-test/find-block-by-content @conn "Block 2") + block-3 (db-test/find-block-by-content @conn "Block 3") + tx-report (d/transact! conn + [{:block/uuid (random-uuid) + :block/title "Inserted" + :block/page (:db/id (:block/page block-1)) + :block/parent (:db/id (:block/parent block-1)) + :block/order (db-order/gen-key (:block/order block-1) + (:block/order block-2)) + :block/created-at 1 + :block/updated-at 1}]) + affected (worker-react/get-affected-queries-keys tx-report)] + (is (some #{[:frontend.worker.react/block (:db/id block-2)]} affected)) + (is (some #{[:frontend.worker.react/block (:db/id block-3)]} affected))))) + +(deftest affected-keys-order-list-descendants + (testing "changing ordered-list parent type affects nested ordered-list descendants" + (let [conn (db-test/create-conn-with-blocks + [{:page {:block/title "Test"} + :blocks [{:block/title "Parent" + :build/properties {:logseq.property/order-list-type "number"} + :build/children [{:block/title "Child" + :build/properties {:logseq.property/order-list-type "number"} + :build/children [{:block/title "Grandchild" + :build/properties {:logseq.property/order-list-type "number"}}]}]}]}]) + parent (db-test/find-block-by-content @conn "Parent") + child (db-test/find-block-by-content @conn "Child") + grandchild (db-test/find-block-by-content @conn "Grandchild") + tx-report (d/transact! conn + [[:db/retract (:db/id parent) :logseq.property/order-list-type + (:db/id (:logseq.property/order-list-type parent))]]) + affected (worker-react/get-affected-queries-keys tx-report)] + (is (some #{[:frontend.worker.react/block (:db/id child)]} affected)) + (is (some #{[:frontend.worker.react/block (:db/id grandchild)]} affected))))) + (deftest affected-keys-journals-when-journal-recycled (testing "recycling a journal page should refresh journals query key" (let [conn (db-test/create-conn-with-blocks