Ver código fonte

enhance(rtc): add :add op to replace :move + :update combo

rcmerci 2 semanas atrás
pai
commit
4dc4e1be78

+ 48 - 3
src/main/frontend/worker/rtc/client.cljs

@@ -233,6 +233,30 @@
               (string/ends-with? ns ".property"))
               (string/ends-with? ns ".property"))
           (= :db.cardinality/one (:db/cardinality (db-schema a)))))) a-coll)))
           (= :db.cardinality/one (:db/cardinality (db-schema a)))))) a-coll)))
 
 
+(defmethod local-block-ops->remote-ops-aux :add-op
+  [_ & {:keys [db block add-op parent-uuid block-order *remote-ops *depend-on-block-uuid-set]}]
+  (let [block-uuid (:block/uuid block)
+        pos (->pos parent-uuid block-order)
+        av-coll (->> (:av-coll (last add-op))
+                     (remove-redundant-av db)
+                     (remove-non-exist-ref-av db))
+        [schema-av-coll other-av-coll] (group-by-schema-attrs av-coll)
+        update-schema-op (schema-av-coll->update-schema-op db block-uuid (:db/ident block) schema-av-coll)
+        depend-on-block-uuids (keep (fn [[_a v]] (when (uuid? v) v)) other-av-coll)
+        card-one-attrs (seq (av-coll->card-one-attrs (d/schema db) other-av-coll))]
+    (when (seq other-av-coll)
+      (swap! *remote-ops conj
+             [:add (cond-> {:block-uuid block-uuid
+                            :pos pos
+                            :av-coll other-av-coll}
+                     (:db/ident block) (assoc :db/ident (:db/ident block))
+                     card-one-attrs (assoc :card-one-attrs card-one-attrs))]))
+    (when update-schema-op
+      (swap! *remote-ops conj update-schema-op))
+    (swap! *depend-on-block-uuid-set (partial apply conj) depend-on-block-uuids)
+    (when parent-uuid
+      (swap! *depend-on-block-uuid-set conj parent-uuid))))
+
 (defmethod local-block-ops->remote-ops-aux :update-op
 (defmethod local-block-ops->remote-ops-aux :update-op
   [_ & {:keys [db block update-op block-order parent-uuid *remote-ops *depend-on-block-uuid-set]}]
   [_ & {:keys [db block update-op block-order parent-uuid *remote-ops *depend-on-block-uuid-set]}]
   (let [block-uuid (:block/uuid block)
   (let [block-uuid (:block/uuid block)
@@ -281,9 +305,9 @@
   [db block-ops]
   [db block-ops]
   (let [*depend-on-block-uuid-set (atom #{})
   (let [*depend-on-block-uuid-set (atom #{})
         *remote-ops (atom [])
         *remote-ops (atom [])
-        {move-op :move remove-op :remove update-op :update update-page-op :update-page remove-page-op :remove-page}
+        {move-op :move remove-op :remove update-op :update add-op :add update-page-op :update-page remove-page-op :remove-page}
         block-ops]
         block-ops]
-    (when-let [block-uuid (some (comp :block-uuid last) [move-op update-op update-page-op])]
+    (when-let [block-uuid (some (comp :block-uuid last) [move-op update-op add-op update-page-op])]
       (when-let [block (d/entity db [:block/uuid block-uuid])]
       (when-let [block (d/entity db [:block/uuid block-uuid])]
         (let [parent-uuid (some-> block :block/parent :block/uuid)]
         (let [parent-uuid (some-> block :block/parent :block/uuid)]
           ;; remote-move-op
           ;; remote-move-op
@@ -294,6 +318,16 @@
                                              :block-uuid block-uuid
                                              :block-uuid block-uuid
                                              :*remote-ops *remote-ops
                                              :*remote-ops *remote-ops
                                              :*depend-on-block-uuid-set *depend-on-block-uuid-set))
                                              :*depend-on-block-uuid-set *depend-on-block-uuid-set))
+          ;; remote-add-op
+          (when add-op
+            (local-block-ops->remote-ops-aux :add-op
+                                             :db db
+                                             :block block
+                                             :add-op add-op
+                                             :parent-uuid parent-uuid
+                                             :block-order (:block/order block)
+                                             :*remote-ops *remote-ops
+                                             :*depend-on-block-uuid-set *depend-on-block-uuid-set))
           ;; remote-update-op
           ;; remote-update-op
           (when update-op
           (when update-op
             (local-block-ops->remote-ops-aux :update-op
             (local-block-ops->remote-ops-aux :update-op
@@ -394,6 +428,10 @@
                            (some->> (get-in block-uuid->remote-ops [block-uuid :move])
                            (some->> (get-in block-uuid->remote-ops [block-uuid :move])
                                     (vector :move)))
                                     (vector :move)))
                          sorted-uuids)
                          sorted-uuids)
+        add-ops (keep
+                 (fn [[_ remote-ops]]
+                   (some->> (:add remote-ops) (vector :add)))
+                 block-uuid->remote-ops)
         update-schema-ops (keep
         update-schema-ops (keep
                            (fn [[_ remote-ops]]
                            (fn [[_ remote-ops]]
                              (some->> (:update-schema remote-ops) (vector :update-schema)))
                              (some->> (:update-schema remote-ops) (vector :update-schema)))
@@ -415,7 +453,7 @@
                          (fn [[_ remote-ops]]
                          (fn [[_ remote-ops]]
                            (some->> (:remove-page remote-ops) (vector :remove-page)))
                            (some->> (:remove-page remote-ops) (vector :remove-page)))
                          block-uuid->remote-ops)]
                          block-uuid->remote-ops)]
-    (concat update-schema-ops update-page-ops remove-ops sorted-move-ops update-ops remove-page-ops)))
+    (concat add-ops update-schema-ops update-page-ops remove-ops sorted-move-ops update-ops remove-page-ops)))
 
 
 (defn- rollback
 (defn- rollback
   [repo block-ops-map-coll update-kv-value-ops-map-coll rename-db-ident-ops-map-coll]
   [repo block-ops-map-coll update-kv-value-ops-map-coll rename-db-ident-ops-map-coll]
@@ -470,6 +508,13 @@
                 (recur rest-remote-ops
                 (recur rest-remote-ops
                        (conj result [op-type (assoc op-value :av-coll av-coll*)])))
                        (conj result [op-type (assoc op-value :av-coll av-coll*)])))
 
 
+              :add
+              (let [av-coll* (c.m/<?
+                              (crypt/<encrypt-av-coll
+                               aes-key rtc-const/encrypt-attr-set (:av-coll op-value)))]
+                (recur rest-remote-ops
+                       (conj result [op-type (assoc op-value :av-coll av-coll*)])))
+
               ;; else
               ;; else
               (recur rest-remote-ops (conj result remote-op)))))))))
               (recur rest-remote-ops (conj result remote-op)))))))))
 
 

+ 44 - 22
src/main/frontend/worker/rtc/client_op.cljs

@@ -58,6 +58,13 @@
      [:value [:map
      [:value [:map
               [:block-uuid :uuid]
               [:block-uuid :uuid]
               [:av-coll [:sequential rtc-schema/av-schema]]]]]]
               [:av-coll [:sequential rtc-schema/av-schema]]]]]]
+   [:add
+    [:catn
+     [:op :keyword]
+     [:t :int]
+     [:value [:map
+              [:block-uuid :uuid]
+              [:av-coll [:sequential rtc-schema/av-schema]]]]]]
 
 
    [:update-asset
    [:update-asset
     [:catn
     [:catn
@@ -77,7 +84,7 @@
                              #(do (log/error ::bad-ops (:value %))
                              #(do (log/error ::bad-ops (:value %))
                                   (ma/-fail! ::ops-schema (select-keys % [:value])))))
                                   (ma/-fail! ::ops-schema (select-keys % [:value])))))
 
 
-(def ^:private block-op-types #{:move :remove :update-page :remove-page :update})
+(def ^:private block-op-types #{:move :remove :update-page :remove-page :update :add})
 (def ^:private asset-op-types #{:update-asset :remove-asset})
 (def ^:private asset-op-types #{:update-asset :remove-asset})
 (def ^:private update-kv-value-op-types #{:update-kv-value})
 (def ^:private update-kv-value-op-types #{:update-kv-value})
 (def ^:private db-ident-rename-op-types #{:rename-db-ident})
 (def ^:private db-ident-rename-op-types #{:rename-db-ident})
@@ -128,18 +135,21 @@
       r)))
       r)))
 
 
 (defn- merge-update-ops
 (defn- merge-update-ops
-  [update-op1 update-op2]
-  {:pre [(= :update (first update-op1))
-         (= :update (first update-op2))
-         (= (:block-uuid (last update-op1))
-            (:block-uuid (last update-op2)))]}
-  (let [t1 (second update-op1)
-        t2 (second update-op2)]
+  [op1 op2]
+  {:pre [(contains? #{:add :update} (first op1))
+         (= :update (first op2))
+         (= (:block-uuid (last op1))
+            (:block-uuid (last op2)))]}
+  (let [t1 (second op1)
+        t2 (second op2)
+        op-type1 (first op1)
+        op-type2 (first op2)]
     (if (> t1 t2)
     (if (> t1 t2)
-      (merge-update-ops update-op2 update-op1)
-      (let [{av-coll1 :av-coll block-uuid :block-uuid} (last update-op1)
-            {av-coll2 :av-coll} (last update-op2)]
-        [:update t2
+      (merge-update-ops op2 op1)
+      (let [{av-coll1 :av-coll block-uuid :block-uuid} (last op1)
+            {av-coll2 :av-coll} (last op2)
+            result-op-type (if (or (= :add op-type1) (= :add op-type2)) :add :update)]
+        [result-op-type t2
          {:block-uuid block-uuid
          {:block-uuid block-uuid
           :av-coll (concat av-coll1 av-coll2)}]))))
           :av-coll (concat av-coll1 av-coll2)}]))))
 
 
@@ -152,22 +162,34 @@
          [_ move-op-t _move-op-value :as move-op] :move
          [_ move-op-t _move-op-value :as move-op] :move
          [_ update-op-t _update-op-value :as update-op] :update
          [_ update-op-t _update-op-value :as update-op] :update
          [_ update-page-op-t _update-page-op-value :as update-page-op] :update-page
          [_ update-page-op-t _update-page-op-value :as update-page-op] :update-page
-         [_ remove-page-op-t _remove-page-op-value :as remove-page-op] :remove-page}
+         [_ remove-page-op-t _remove-page-op-value :as remove-page-op] :remove-page
+         [_ add-op-t _add-op-value :as add-op] :add}
         (into {} (filter (fn [[_op-type op]] (some-> op (not= :retract))) current-block-op-map))]
         (into {} (filter (fn [[_op-type op]] (some-> op (not= :retract))) current-block-op-map))]
     (case op-type
     (case op-type
-      :move
+      :add
       (if (>= remove-op-t op-t) current-block-op-map
       (if (>= remove-op-t op-t) current-block-op-map
           (cond-> (assoc current-block-op-map :remove :retract)
           (cond-> (assoc current-block-op-map :remove :retract)
-            (or (nil? move-op) (> op-t move-op-t)) (assoc :move op-to-add)))
+            (or (nil? add-op) (> op-t add-op-t)) (assoc :add op-to-add)))
+      :move
+      (if (>= remove-op-t op-t) current-block-op-map
+          (if add-op
+            (let [[_ add-t add-val] add-op
+                  new-t (max add-t op-t)]
+              (assoc current-block-op-map :add [:add new-t add-val]))
+            (cond-> (assoc current-block-op-map :remove :retract)
+              (or (nil? move-op) (> op-t move-op-t)) (assoc :move op-to-add))))
       :update
       :update
       (if (>= remove-op-t op-t) current-block-op-map
       (if (>= remove-op-t op-t) current-block-op-map
-          (assoc current-block-op-map
-                 :remove :retract
-                 :update (if update-op (merge-update-ops update-op op-to-add) op-to-add)))
+          (if add-op
+            (assoc current-block-op-map :add (merge-update-ops add-op op-to-add))
+            (assoc current-block-op-map
+                   :remove :retract
+                   :update (if update-op (merge-update-ops update-op op-to-add) op-to-add))))
       :remove
       :remove
-      (if (or (>= move-op-t op-t) (>= update-op-t op-t)) current-block-op-map
-          (cond-> (assoc current-block-op-map :move :retract :update :retract)
-            (or (nil? remove-op) (> op-t remove-op-t)) (assoc :remove op-to-add)))
+      (if (or (>= move-op-t op-t) (>= update-op-t op-t) (and add-op (>= add-op-t op-t)))
+        current-block-op-map
+        (cond-> (assoc current-block-op-map :move :retract :update :retract :add :retract)
+          (or (nil? remove-op) (> op-t remove-op-t)) (assoc :remove op-to-add)))
       :update-page
       :update-page
       (if (>= remove-page-op-t op-t) current-block-op-map
       (if (>= remove-page-op-t op-t) current-block-op-map
           (cond-> (assoc current-block-op-map :remove-page :retract)
           (cond-> (assoc current-block-op-map :remove-page :retract)
@@ -182,7 +204,7 @@
   (let [sorted-ops (sort-by second ops)
   (let [sorted-ops (sort-by second ops)
         block-uuids (map (fn [[_op-type _t value]] (:block-uuid value)) sorted-ops)
         block-uuids (map (fn [[_op-type _t value]] (:block-uuid value)) sorted-ops)
         ents (d/pull-many client-ops-db '[*] (map (fn [block-uuid] [:block/uuid block-uuid]) block-uuids))
         ents (d/pull-many client-ops-db '[*] (map (fn [block-uuid] [:block/uuid block-uuid]) block-uuids))
-        op-types [:move :update :remove :update-page :remove-page]
+        op-types [:add :move :update :remove :update-page :remove-page]
         init-block-uuid->op-type->op
         init-block-uuid->op-type->op
         (into {}
         (into {}
               (map (fn [ent]
               (map (fn [ent]

+ 9 - 0
src/main/frontend/worker/rtc/gen_client_op.cljs

@@ -134,6 +134,7 @@
          add?->block-order->t  :block/order}
          add?->block-order->t  :block/order}
         a->add?->v->t
         a->add?->v->t
         [retract-block-uuid t1]  (some-> add?->block-uuid->t (get false) first)
         [retract-block-uuid t1]  (some-> add?->block-uuid->t (get false) first)
+        [add-block-uuid t-uuid]  (some-> add?->block-uuid->t (get true) first)
         [retract-block-name _]   (some-> add?->block-name->t (get false) first)
         [retract-block-name _]   (some-> add?->block-name->t (get false) first)
         [add-block-name t2]      (some-> add?->block-name->t latest-add?->v->t (get-first-vt true))
         [add-block-name t2]      (some-> add?->block-name->t latest-add?->v->t (get-first-vt true))
         [add-block-title t3]     (some-> add?->block-title->t latest-add?->v->t (get-first-vt true))
         [add-block-title t3]     (some-> add?->block-title->t latest-add?->v->t (get-first-vt true))
@@ -152,6 +153,14 @@
       retract-block-uuid
       retract-block-uuid
       [[:remove t1 {:block-uuid retract-block-uuid}]]
       [[:remove t1 {:block-uuid retract-block-uuid}]]
 
 
+      add-block-uuid
+      (let [av-coll (update-op-av-coll db-before db-after a->add?->v->t*)
+            add-op  [:add (or t-uuid t4 t5) {:block-uuid block-uuid :av-coll av-coll}]]
+        (if (or add-block-name
+                (and (ldb/page? entity) add-block-title))
+          [[:update-page (or t2 t3) {:block-uuid block-uuid}] add-op]
+          [add-op]))
+
       :else
       :else
       (let [ops (cond-> []
       (let [ops (cond-> []
                   (or add-block-parent add-block-order)
                   (or add-block-parent add-block-order)

+ 61 - 0
src/test/frontend/worker/rtc/client_op_test.cljs

@@ -186,3 +186,64 @@
               (is (some? (:move result-op)))
               (is (some? (:move result-op)))
               (is (= 3 (second (:move result-op))))
               (is (= 3 (second (:move result-op))))
               (is (nil? (:remove result-op))))))))))
               (is (nil? (:remove result-op))))))))))
+
+(deftest add-op-merge-test
+  (testing "Merge :add and :move"
+    (let [conn (d/create-conn client-op/schema-in-db)
+          block-uuid (random-uuid)
+          add-op [:add 1 {:block-uuid block-uuid :av-coll []}]
+          move-op [:move 2 {:block-uuid block-uuid}]]
+      (with-redefs [worker-state/get-client-ops-conn (constantly conn)]
+        (client-op/add-ops! "repo" [add-op])
+        (client-op/add-ops! "repo" [move-op])
+        (let [ops (client-op/get&remove-all-block-ops "repo")
+              result-op (first ops)]
+          (is (= 1 (count ops)))
+          (is (some? (:add result-op)))
+          (is (= 2 (second (:add result-op))))
+          (is (nil? (:move result-op)))))))
+
+  (testing "Merge :add and :update"
+    (let [conn (d/create-conn client-op/schema-in-db)
+          block-uuid (random-uuid)
+          add-op [:add 1 {:block-uuid block-uuid :av-coll [[:block/title "A" 1 true]]}]
+          update-op [:update 2 {:block-uuid block-uuid :av-coll [[:block/title "B" 2 true]]}]]
+      (with-redefs [worker-state/get-client-ops-conn (constantly conn)]
+        (client-op/add-ops! "repo" [add-op])
+        (client-op/add-ops! "repo" [update-op])
+        (let [ops (client-op/get&remove-all-block-ops "repo")
+              result-op (first ops)]
+          (is (= 1 (count ops)))
+          (is (some? (:add result-op)))
+          (is (= 2 (second (:add result-op))))
+          (let [av-coll (:av-coll (last (:add result-op)))]
+            (is (= [[:block/title "A" 1 true] [:block/title "B" 2 true]] av-coll)))
+          (is (nil? (:update result-op)))))))
+
+  (testing "Merge :add and :remove (Newer Remove)"
+    (let [conn (d/create-conn client-op/schema-in-db)
+          block-uuid (random-uuid)
+          add-op [:add 1 {:block-uuid block-uuid :av-coll []}]
+          remove-op [:remove 2 {:block-uuid block-uuid}]]
+      (with-redefs [worker-state/get-client-ops-conn (constantly conn)]
+        (client-op/add-ops! "repo" [add-op])
+        (client-op/add-ops! "repo" [remove-op])
+        (let [ops (client-op/get&remove-all-block-ops "repo")
+              result-op (first ops)]
+          (is (= 1 (count ops)))
+          (is (some? (:remove result-op)))
+          (is (nil? (:add result-op)))))))
+
+  (testing "Merge :remove and :add (Newer Add)"
+    (let [conn (d/create-conn client-op/schema-in-db)
+          block-uuid (random-uuid)
+          remove-op [:remove 1 {:block-uuid block-uuid}]
+          add-op [:add 2 {:block-uuid block-uuid :av-coll []}]]
+      (with-redefs [worker-state/get-client-ops-conn (constantly conn)]
+        (client-op/add-ops! "repo" [remove-op])
+        (client-op/add-ops! "repo" [add-op])
+        (let [ops (client-op/get&remove-all-block-ops "repo")
+              result-op (first ops)]
+          (is (= 1 (count ops)))
+          (is (some? (:add result-op)))
+          (is (nil? (:remove result-op))))))))

+ 27 - 1
src/test/frontend/worker/rtc/client_test.cljs

@@ -104,4 +104,30 @@
                            [:block/title (ldb/write-transit-str "xxx") 1 true]
                            [:block/title (ldb/write-transit-str "xxx") 1 true]
                            [:block/type (ldb/write-transit-str "property") 1 true]
                            [:block/type (ldb/write-transit-str "property") 1 true]
                            [:db/cardinality (ldb/write-transit-str :db.cardinality/one) 1 true]
                            [:db/cardinality (ldb/write-transit-str :db.cardinality/one) 1 true]
-                           [:db/index (ldb/write-transit-str true) 1 true]]}]})))))))
+                           [:db/index (ldb/write-transit-str true) 1 true]]}]}))))))
+
+  (testing "user.class/zzz creation (add op)"
+    (let [block-uuid (random-uuid)
+          db (d/db-with empty-db [{:block/uuid block-uuid,
+                                   :block/updated-at 1720017595873,
+                                   :block/created-at 1720017595872,
+                                   :db/ident :user.class/zzz,
+                                   :block/type "class",
+                                   :block/name "zzz",
+                                   :block/title "zzz"}])]
+      (is (= {:add
+              {:block-uuid block-uuid
+               :db/ident :user.class/zzz
+               :pos [nil nil]
+               :av-coll
+               [[:block/name "[\"~#'\",\"zzz\"]" 1 true]
+                [:block/title "[\"~#'\",\"zzz\"]" 1 true]
+                [:block/type "[\"~#'\",\"class\"]" 1 true]]}}
+             (:remote-ops
+              (#'subject/local-block-ops->remote-ops
+               db
+               {:add [:add 1 {:block-uuid block-uuid
+                              :av-coll
+                              [[:block/name (ldb/write-transit-str "zzz") 1 true]
+                               [:block/title (ldb/write-transit-str "zzz") 1 true]
+                               [:block/type (ldb/write-transit-str "class") 1 true]]}]})))))))

+ 54 - 33
src/test/frontend/worker/rtc/gen_client_op_test.cljs

@@ -24,7 +24,7 @@
         id->same-entity-datoms (group-by first datom-vec-coll)]
         id->same-entity-datoms (group-by first datom-vec-coll)]
     (update-vals id->same-entity-datoms #'subject/entity-datoms=>a->add?->v->t)))
     (update-vals id->same-entity-datoms #'subject/entity-datoms=>a->add?->v->t)))
 
 
-(deftest entity-datoms=>ops-test
+(deftest ^:large-vars/cleanup-todo entity-datoms=>ops-test
   (testing "remove whiteboard page-block"
   (testing "remove whiteboard page-block"
     (let [conn (db-test/create-conn)
     (let [conn (db-test/create-conn)
           block-uuid (random-uuid)
           block-uuid (random-uuid)
@@ -43,6 +43,31 @@
       (is (= [[:remove-page {:block-uuid block-uuid}]]
       (is (= [[:remove-page {:block-uuid block-uuid}]]
              (map (fn [[op-type _t op-value]] [op-type op-value]) r)))))
              (map (fn [[op-type _t op-value]] [op-type op-value]) r)))))
 
 
+  (testing "create page block"
+    (let [conn (db-test/create-conn)
+          block-uuid (random-uuid)
+          tx-data [[:db/add 1000000 :block/uuid block-uuid]
+                   [:db/add 1000000 :block/name "page-name"]
+                   [:db/add 1000000 :block/title "Page Title"]
+                   [:db/add 1000000 :block/created-at 1716882111476]
+                   [:db/add 1000000 :block/updated-at 1716882111476]]
+          {:keys [db-before db-after tx-data]} (d/transact! conn tx-data)
+          ops (#'subject/entity-datoms=>ops db-before db-after
+                                            (tx-data=>e->a->add?->v->t tx-data)
+                                            nil
+                                            (map vec tx-data))]
+      (is (= [[:update-page {:block-uuid block-uuid}]
+              [:add {:block-uuid block-uuid
+                     :av-coll
+                     (set [[:block/updated-at "[\"~#'\",1716882111476]"]
+                           [:block/created-at "[\"~#'\",1716882111476]"]
+                           [:block/title "[\"~#'\",\"Page Title\"]"]])}]]
+             (map (fn [[op-type _t op-value]]
+                    [op-type (cond-> op-value
+                               (:av-coll op-value)
+                               (assoc :av-coll (set (map #(take 2 %) (:av-coll op-value)))))])
+                  ops)))))
+
   (testing "update-schema op"
   (testing "update-schema op"
     (let [conn (db-test/create-conn)
     (let [conn (db-test/create-conn)
           tx-data [[:db/add 1000000 :db/index true]
           tx-data [[:db/add 1000000 :db/index true]
@@ -64,20 +89,19 @@
                                             #{:logseq.property/ignored-attr-x}
                                             #{:logseq.property/ignored-attr-x}
                                             (map vec tx-data))]
                                             (map vec tx-data))]
       (is (=
       (is (=
-           [[:move {:block-uuid #uuid "66558abf-6512-469d-9e83-8f1ba0be9305"}]
-            [:update-page {:block-uuid #uuid "66558abf-6512-469d-9e83-8f1ba0be9305"}]
-            [:update {:block-uuid #uuid "66558abf-6512-469d-9e83-8f1ba0be9305"
-                      :av-coll
-                      [[:db/index "[\"~#'\",true]"]
-                       [:logseq.property/type "[\"~#'\",\"~:number\"]"]
-                       [:db/valueType "[\"~#'\",\"~:db.type/ref\"]"]
-                       [:block/updated-at "[\"~#'\",1716882111476]"]
-                       [:block/created-at "[\"~#'\",1716882111476]"]
-                       [:block/tags #uuid "00000002-1038-7670-4800-000000000000"]
-                       [:block/title "[\"~#'\",\"qqq\"]"]
-                       [:db/cardinality "[\"~#'\",\"~:db.cardinality/one\"]"]
+           [[:update-page {:block-uuid #uuid "66558abf-6512-469d-9e83-8f1ba0be9305"}]
+            [:add {:block-uuid #uuid "66558abf-6512-469d-9e83-8f1ba0be9305"
+                   :av-coll
+                   [[:db/index "[\"~#'\",true]"]
+                    [:logseq.property/type "[\"~#'\",\"~:number\"]"]
+                    [:db/valueType "[\"~#'\",\"~:db.type/ref\"]"]
+                    [:block/updated-at "[\"~#'\",1716882111476]"]
+                    [:block/created-at "[\"~#'\",1716882111476]"]
+                    [:block/tags #uuid "00000002-1038-7670-4800-000000000000"]
+                    [:block/title "[\"~#'\",\"qqq\"]"]
+                    [:db/cardinality "[\"~#'\",\"~:db.cardinality/one\"]"]
                        ;; [:db/ident "[\"~#'\",\"~:user.property/qqq\"]"]
                        ;; [:db/ident "[\"~#'\",\"~:user.property/qqq\"]"]
-                       ]}]]
+                    ]}]]
            (map (fn [[op-type _t op-value]]
            (map (fn [[op-type _t op-value]]
                   [op-type (cond-> op-value
                   [op-type (cond-> op-value
                              (:av-coll op-value)
                              (:av-coll op-value)
@@ -101,16 +125,16 @@
                                             (map vec tx-data))]
                                             (map vec tx-data))]
       (is (=
       (is (=
            [[:update-page {:block-uuid #uuid "66856a29-6eb3-4122-af97-8580a853c6a6"}]
            [[:update-page {:block-uuid #uuid "66856a29-6eb3-4122-af97-8580a853c6a6"}]
-            [:update {:block-uuid #uuid "66856a29-6eb3-4122-af97-8580a853c6a6",
-                      :av-coll
-                      (set
-                       [[:block/updated-at "[\"~#'\",1720019497643]"]
-                        [:block/created-at "[\"~#'\",1720019497643]"]
-                        [:block/tags #uuid "00000002-5389-0208-3000-000000000000"]
-                        [:block/title "[\"~#'\",\"zzz\"]"]
-                        [:logseq.property.class/extends #uuid "00000002-2737-8382-7000-000000000000"]
+            [:add {:block-uuid #uuid "66856a29-6eb3-4122-af97-8580a853c6a6",
+                   :av-coll
+                   (set
+                    [[:block/updated-at "[\"~#'\",1720019497643]"]
+                     [:block/created-at "[\"~#'\",1720019497643]"]
+                     [:block/tags #uuid "00000002-5389-0208-3000-000000000000"]
+                     [:block/title "[\"~#'\",\"zzz\"]"]
+                     [:logseq.property.class/extends #uuid "00000002-2737-8382-7000-000000000000"]
                        ;;1. shouldn't have :db/ident, :db/ident is special, will be handled later
                        ;;1. shouldn't have :db/ident, :db/ident is special, will be handled later
-                        ])}]]
+                     ])}]]
            (map (fn [[op-type _t op-value]]
            (map (fn [[op-type _t op-value]]
                   [op-type (cond-> op-value
                   [op-type (cond-> op-value
                              (:av-coll op-value)
                              (:av-coll op-value)
@@ -129,7 +153,7 @@
       (testing "add page"
       (testing "add page"
         (worker-page/create! conn "TEST-PAGE" {:uuid page-uuid})
         (worker-page/create! conn "TEST-PAGE" {:uuid page-uuid})
         (is (some? (d/pull @conn '[*] [:block/uuid page-uuid])))
         (is (some? (d/pull @conn '[*] [:block/uuid page-uuid])))
-        (is (= {page-uuid #{:update-page :update}}
+        (is (= {page-uuid #{:add :update-page}}
                (ops-coll=>block-uuid->op-types (client-op/get&remove-all-block-ops repo)))))
                (ops-coll=>block-uuid->op-types (client-op/get&remove-all-block-ops repo)))))
       (testing "add blocks to this page"
       (testing "add blocks to this page"
         (let [target-entity (d/entity @conn [:block/uuid page-uuid])]
         (let [target-entity (d/entity @conn [:block/uuid page-uuid])]
@@ -142,8 +166,8 @@
                                           target-entity
                                           target-entity
                                           {:sibling? false :keep-uuid? true}))
                                           {:sibling? false :keep-uuid? true}))
           (is (=
           (is (=
-               {block-uuid1 #{:move :update}
-                block-uuid2 #{:move :update}}
+               {block-uuid1 #{:add}
+                block-uuid2 #{:add}}
                (ops-coll=>block-uuid->op-types (client-op/get&remove-all-block-ops repo))))))
                (ops-coll=>block-uuid->op-types (client-op/get&remove-all-block-ops repo))))))
 
 
       (testing "delete a block"
       (testing "delete a block"
@@ -164,10 +188,8 @@
                         :block/tags :block/title :db/cardinality}]
                         :block/tags :block/title :db/cardinality}]
     #_{:clj-kondo/ignore [:unresolved-symbol :invalid-arity]}
     #_{:clj-kondo/ignore [:unresolved-symbol :invalid-arity]}
     (is (->> (me/find (subject/generate-rtc-ops-from-property-entities [ent])
     (is (->> (me/find (subject/generate-rtc-ops-from-property-entities [ent])
-                      ([:move _ {:block-uuid ?block-uuid}]
-                       [:update-page _ {:block-uuid ?block-uuid}]
-                       [:update _ {:block-uuid ?block-uuid :av-coll ([!av-coll-attrs . _ ...] ...)}])
-                      !av-coll-attrs)
+               ([:update-page . _ ...] [:add _ {:block-uuid ?block-uuid :av-coll ([!av-coll-attrs . _ ...] ...)}])
+               !av-coll-attrs)
              set
              set
              (set/difference av-coll-attrs)
              (set/difference av-coll-attrs)
              empty?))))
              empty?))))
@@ -180,9 +202,8 @@
                         :block/tags :block/title}]
                         :block/tags :block/title}]
     #_{:clj-kondo/ignore [:unresolved-symbol :invalid-arity]}
     #_{:clj-kondo/ignore [:unresolved-symbol :invalid-arity]}
     (is (->> (me/find (subject/generate-rtc-ops-from-class-entities [ent])
     (is (->> (me/find (subject/generate-rtc-ops-from-class-entities [ent])
-                      ([:update-page _ {:block-uuid ?block-uuid}]
-                       [:update _ {:block-uuid ?block-uuid :av-coll ([!av-coll-attrs . _ ...] ...)}])
-                      !av-coll-attrs)
+               ([:update-page . _ ...] [:add _ {:block-uuid ?block-uuid :av-coll ([!av-coll-attrs . _ ...] ...)}])
+               !av-coll-attrs)
              set
              set
              (set/difference av-coll-attrs)
              (set/difference av-coll-attrs)
              empty?))))
              empty?))))