Browse Source

fix(rtc): move children out when their parent deleted by remote

rcmerci 1 year ago
parent
commit
d45bab4131
2 changed files with 105 additions and 11 deletions
  1. 46 8
      src/main/frontend/worker/rtc/core.cljs
  2. 59 3
      src/test/frontend/worker/rtc/rtc_fns_test.cljs

+ 46 - 8
src/main/frontend/worker/rtc/core.cljs

@@ -130,13 +130,21 @@
                     :conn (second args)}}
    (apply outliner-core/move-blocks! args)))
 
-(defmethod transact-db! :insert-blocks [_ & args]
+(defmethod transact-db! :move-blocks&persist-op [_ & args]
   (outliner-tx/transact!
-   {:persist-op? false
-    :outliner-op :insert-blocks
+   {:persist-op? true
+    :outliner-op :move-blocks
     :transact-opts {:repo (first args)
                     :conn (second args)}}
-   (apply outliner-core/insert-blocks! args)))
+   (apply outliner-core/move-blocks! args)))
+
+(defmethod transact-db! :insert-blocks [_ & args]
+  (outliner-tx/transact!
+      {:persist-op? false
+       :outliner-op :insert-blocks
+       :transact-opts {:repo (first args)
+                       :conn (second args)}}
+      (apply outliner-core/insert-blocks! args)))
 
 (defmethod transact-db! :save-block [_ & args]
   (outliner-tx/transact!
@@ -167,16 +175,46 @@
                  (whiteboard-page-block? (:block/parent block)))))
             remote-remove-ops))
 
+(defn- apply-remote-remove-ops-helper
+  [conn remove-ops]
+  (let [block-uuid->entity (into {}
+                                 (keep
+                                  (fn [op]
+                                    (when-let [block-uuid (:block-uuid op)]
+                                      (when-let [ent (d/entity @conn [:block/uuid block-uuid])]
+                                        [block-uuid ent])))
+                                  remove-ops))
+        block-uuid-set (set (keys block-uuid->entity))
+        block-uuids-need-move
+        (set
+         (mapcat
+          (fn [[_block-uuid ent]]
+            (set/difference (set (map :block/uuid (:block/_parent ent))) block-uuid-set))
+          block-uuid->entity))]
+    {:block-uuids-need-move block-uuids-need-move
+     :block-uuids-to-remove block-uuid-set}))
+
 (defn apply-remote-remove-ops
   [repo conn date-formatter remove-ops]
   (prn :remove-ops remove-ops)
   (let [{whiteboard-block-ops true other-ops false} (group-remote-remove-ops-by-whiteboard-block @conn remove-ops)]
     (transact-db! :delete-whiteboard-blocks conn (map :block-uuid whiteboard-block-ops))
 
-    (doseq [op other-ops]
-      (when-let [block (d/entity @conn [:block/uuid (:block-uuid op)])]
-        (transact-db! :delete-blocks repo conn date-formatter [block] {:children? false})
-        (prn :apply-remote-remove-ops (:block-uuid op))))))
+    (let [{:keys [block-uuids-need-move block-uuids-to-remove] :as r}
+          (apply-remote-remove-ops-helper conn other-ops)]
+      ;; move to page-block's first child
+      (doseq [block-uuid block-uuids-need-move]
+        (transact-db! :move-blocks&persist-op
+                      repo conn
+                      [(d/entity @conn [:block/uuid block-uuid])]
+                      (d/entity @conn (:db/id (:block/page (d/entity @conn [:block/uuid block-uuid]))))
+                      false))
+      (doseq [block-uuid block-uuids-to-remove]
+        (transact-db! :delete-blocks
+                      repo conn date-formatter
+                      [(d/entity @conn [:block/uuid block-uuid])]
+                      {:children? true}))
+      (prn :apply-remote-remove-ops r))))
 
 (defn- insert-or-move-block
   [repo conn block-uuid remote-parents remote-left-uuid move? op-value]

+ 59 - 3
src/test/frontend/worker/rtc/rtc_fns_test.cljs

@@ -324,9 +324,10 @@
                           :affected-blocks
                           {uuid1-client {:op :remove
                                          :block-uuid uuid1-not-exist}}}
-            remove-ops (vals
-                        (:remove-ops-map
-                         (#'rtc-core/affected-blocks->diff-type-ops repo (:affected-blocks data-from-ws))))]
+            remove-ops
+            (vals
+             (:remove-ops-map
+              (#'rtc-core/affected-blocks->diff-type-ops repo (:affected-blocks data-from-ws))))]
         (is (rtc-const/data-from-ws-validator data-from-ws))
         (rtc-core/apply-remote-remove-ops repo conn date-formatter remove-ops)
         (let [page-blocks (ldb/get-page-blocks @conn page-name {})]
@@ -344,6 +345,61 @@
         (let [page-blocks (ldb/get-page-blocks @conn page-name {})]
           (is (= #{uuid2-client} (set (map :block/uuid page-blocks)))))))))
 
+(deftest apply-remote-remove-ops-test2
+  (testing "
+origin:
+- 1
+- 2
+- 3
+client: ;; move 3 as child of 2
+- 1
+- 2
+  - 3
+server: ;; remove 2
+- 1
+- 3"
+    (let [repo (state/get-current-repo)
+          conn (conn/get-db repo false)
+          date-formatter (common-config/get-date-formatter (worker-state/get-config repo))
+          opts {:persist-op? false
+                :transact-opts {:repo repo
+                                :conn conn}}
+          page-name "apply-remote-remove-ops-test2"
+          [page-uuid
+           uuid1 uuid2 uuid3] (repeatedly random-uuid)]
+      (page-handler/create! page-name {:redirect? false :create-first-block? false :uuid page-uuid})
+      (outliner-tx/transact!
+       opts
+       (outliner-core/insert-blocks!
+        ;; - 1
+        ;; - 2
+        ;;   - 3
+        repo conn
+        [{:block/uuid uuid1 :block/content "1"
+          :block/left [:block/uuid page-uuid]
+          :block/parent [:block/uuid page-uuid]}
+         {:block/uuid uuid2 :block/content "2"
+          :block/left [:block/uuid uuid1]
+          :block/parent [:block/uuid page-uuid]}
+         {:block/uuid uuid3 :block/content "3"
+          :block/left [:block/uuid uuid2]
+          :block/parent [:block/uuid uuid2]}]
+        (d/pull @conn '[*] [:block/name page-name])
+        {:sibling? false :keep-uuid? true}))
+      (let [data-from-ws {:req-id "req-id" :t 1 :t-before 0
+                          :affected-blocks
+                          {uuid2 {:op :remove
+                                  :block-uuid uuid2}}}
+            remove-ops
+            (vals
+             (:remove-ops-map
+              (#'rtc-core/affected-blocks->diff-type-ops repo (:affected-blocks data-from-ws))))]
+        (is (rtc-const/data-from-ws-validator data-from-ws))
+        (rtc-core/apply-remote-remove-ops repo conn date-formatter remove-ops)
+        (let [page-blocks (ldb/get-page-blocks @conn page-name {})]
+          (is (= #{uuid1 uuid3} (set (map :block/uuid page-blocks))))
+          (is (= page-uuid (:block/uuid (:block/left (d/entity @conn [:block/uuid uuid3]))))))))))
+
 
 (deftest apply-remote-update&remove-page-ops-test
   (let [repo (state/get-current-repo)