diff --git a/src/main/frontend/worker/sync.cljs b/src/main/frontend/worker/sync.cljs index f7acded0fb..27981843e3 100644 --- a/src/main/frontend/worker/sync.cljs +++ b/src/main/frontend/worker/sync.cljs @@ -696,6 +696,17 @@ ;; (prn :debug :sanitized-tx-data sanitized-tx-data)) sanitized-tx-data)) +(defn- created-block-uuids + [tx-data] + (->> tx-data + (keep (fn [item] + (when (and (vector? item) + (= :db/add (first item)) + (>= (count item) 4) + (= :block/uuid (nth item 2))) + (nth item 3)))) + set)) + (defn- flush-pending! [repo client] (let [inflight @(:inflight client) @@ -1224,11 +1235,16 @@ *remote-deleted-ids (atom #{}) *rebase-tx-data (atom []) db @conn - remote-deleted-blocks (->> tx-data - (keep (fn [item] - (when (= :db/retractEntity (first item)) - (d/entity db (second item)))))) - remote-deleted-block-ids (set (map :block/uuid remote-deleted-blocks)) + recreated-block-ids (created-block-uuids tx-data) + raw-remote-deleted-blocks (->> tx-data + (keep (fn [item] + (when (= :db/retractEntity (first item)) + (d/entity db (second item)))))) + raw-remote-deleted-block-ids (set (keep :block/uuid raw-remote-deleted-blocks)) + remote-deleted-block-ids (set/difference raw-remote-deleted-block-ids recreated-block-ids) + remote-deleted-blocks (remove (fn [block] + (contains? recreated-block-ids (:block/uuid block))) + raw-remote-deleted-blocks) safe-remote-tx-data (->> tx-data (remove (fn [item] (or (= :db/retractEntity (first item)) diff --git a/src/test/frontend/worker/db_sync_test.cljs b/src/test/frontend/worker/db_sync_test.cljs index acdac4a681..a07508ea1b 100644 --- a/src/test/frontend/worker/db_sync_test.cljs +++ b/src/test/frontend/worker/db_sync_test.cljs @@ -385,6 +385,40 @@ (let [child' (d/entity @conn [:block/uuid child-uuid])] (is (nil? child')))))))) +(deftest ^:long cut-paste-parent-with-child-keeps-child-parent-after-sync-test + (testing "remote tx can retract and recreate target uuid; child should point to recreated parent" + (let [conn (db-test/create-conn-with-blocks + {:pages-and-blocks + [{:page {:block/title "page 1"} + :blocks [{:block/title "parent" + :build/children [{:block/title "child"}]} + {:block/title "target"}]}]}) + parent (db-test/find-block-by-content @conn "parent") + child (db-test/find-block-by-content @conn "child") + target (db-test/find-block-by-content @conn "target") + page-uuid (:block/uuid (:block/page parent)) + parent-uuid (:block/uuid parent) + child-uuid (:block/uuid child) + target-uuid (:block/uuid target) + target-order (:block/order target)] + (with-datascript-conns conn nil + (fn [] + (#'db-sync/apply-remote-tx! + test-repo + nil + [[:db/retractEntity [:block/uuid parent-uuid]] + [:db/retractEntity [:block/uuid target-uuid]] + [:db/add -1 :block/uuid target-uuid] + [:db/add -1 :block/title "parent"] + [:db/add -1 :block/parent [:block/uuid page-uuid]] + [:db/add -1 :block/page [:block/uuid page-uuid]] + [:db/add -1 :block/order target-order] + [:db/add [:block/uuid child-uuid] :block/parent [:block/uuid target-uuid]]]) + (let [parent' (d/entity @conn [:block/uuid target-uuid]) + child' (d/entity @conn [:block/uuid child-uuid])] + (is (= "parent" (:block/title parent'))) + (is (= (:db/id parent') (:db/id (:block/parent child')))))))))) + (deftest ^:long fix-duplicate-orders-after-rebase-test (testing "duplicate order updates are fixed after remote rebase" (let [{:keys [conn client-ops-conn child1 child2]} (setup-parent-child)