Parcourir la source

Merge pull request #12095 from logseq/enhance/rtc-migrate

enhance: generate rtc-ops from db-migrations
Tienson Qin il y a 4 mois
Parent
commit
fc7729dcbf

+ 2 - 0
deps/db/.carve/ignore

@@ -19,6 +19,8 @@ logseq.db.frontend.class/logseq-class?
 ;; API
 logseq.db.frontend.db-ident/ensure-unique-db-ident
 ;; API
+logseq.db.frontend.db-ident/replace-db-ident-random-suffix
+;; API
 logseq.db.sqlite.build/create-blocks
 ;; API
 logseq.db.sqlite.export/build-export

+ 7 - 0
deps/db/src/logseq/db/frontend/db_ident.cljc

@@ -89,3 +89,10 @@
                "-"
                (rand-nth non-int-char-range)
                (nano-id 7))))))
+
+(defn replace-db-ident-random-suffix
+  [db-ident-kw new-suffix]
+  (assert (keyword? db-ident-kw))
+  (assert (and (string? new-suffix) (= 8 (count new-suffix))))
+  (keyword (namespace db-ident-kw)
+           (string/replace-first (name db-ident-kw) #"-.{8}$" (str "-" new-suffix))))

+ 1 - 1
deps/db/src/logseq/db/sqlite/util.cljs

@@ -40,7 +40,7 @@
     (fn write-transit-str* [o]
       (try (transit/write writer o)
            (catch :default e
-             (prn ::write-transit-str o)
+             (prn ::write-transit-str (type o) o)
              (js/console.trace)
              (throw e))))))
 

+ 7 - 5
src/dev-cljs/shadow/user.clj

@@ -18,11 +18,13 @@
 
 ;; Get the runtime id from http://localhost:9630/runtimes, pick the one which shows `browser-worker`
 (defn worker-repl
-  []
-  (let [runtime-id (->> (api/repl-runtimes :db-worker)
-                        (map :client-id)
-                        first)]
-    (api/repl :db-worker {:runtime-id runtime-id})))
+  ([]
+   (let [runtime-id (->> (api/repl-runtimes :db-worker)
+                         (map :client-id)
+                         first)]
+     (api/repl :db-worker {:runtime-id runtime-id})))
+  ([runtime-id]
+   (api/repl :db-worker {:runtime-id runtime-id})))
 
 (defn runtime-id-list
   [app]

+ 0 - 14
src/main/frontend/db/rtc/debug_ui.cljs

@@ -256,20 +256,6 @@
          (for [{:keys [graph-uuid graph-schema-version graph-status]} (:remote-graphs debug-state*)]
            (shui/select-item {:value [graph-uuid graph-schema-version] :disabled (some? graph-status)} graph-uuid)))))]
 
-     [:div.pb-2.flex.flex-row.items-center.gap-2
-      (ui/button "Run server-migrations"
-                 {:on-click (fn []
-                              (let [repo (state/get-current-repo)]
-                                (when-let [server-schema-version (:server-schema-version debug-state*)]
-                                  (state/<invoke-db-worker :thread-api/rtc-add-migration-client-ops
-                                                           repo server-schema-version))))})
-      [:input.form-input.my-2.py-1.w-32
-       {:on-change (fn [e] (swap! debug-state assoc :server-schema-version (util/evalue e)))
-        :on-focus (fn [e] (let [v (.-value (.-target e))]
-                            (when (= v "server migration start version here(e.g. \"64.2\")")
-                              (set! (.-value (.-target e)) ""))))
-        :placeholder "server migration start version here(e.g. \"64.2\")"}]]
-
      [:hr.my-2]
 
      (let [*keys-state (get state ::keys-state)

+ 3 - 1
src/main/frontend/handler/db_based/import.cljs

@@ -2,6 +2,7 @@
   "Handles DB graph imports"
   (:require [cljs.pprint :as pprint]
             [clojure.edn :as edn]
+            [datascript.core :as d]
             [frontend.config :as config]
             [frontend.db :as db]
             [frontend.handler.notification :as notification]
@@ -38,7 +39,8 @@
 (defn import-from-debug-transit!
   [bare-graph-name raw finished-ok-handler]
   (let [graph (str config/db-version-prefix bare-graph-name)
-        datoms (ldb/read-transit-str raw)]
+        db-or-datoms (ldb/read-transit-str raw)
+        datoms (if (d/db? db-or-datoms) (vec (d/datoms db-or-datoms :eavt)) db-or-datoms)]
     (p/do!
      (persist-db/<new graph {:import-type :debug-transit
                              :datoms datoms})

+ 92 - 29
src/main/frontend/worker/db/migrate.cljs

@@ -5,17 +5,18 @@
             [datascript.core :as d]
             [datascript.impl.entity :as de]
             [frontend.worker-common.util :as worker-util]
+            [frontend.worker.db.rename-db-ident :as rename-db-ident]
             [logseq.common.config :as common-config]
             [logseq.common.util :as common-util]
             [logseq.db :as ldb]
             [logseq.db.common.order :as db-order]
             [logseq.db.frontend.class :as db-class]
+            [logseq.db.frontend.db-ident :as db-ident]
             [logseq.db.frontend.property :as db-property]
             [logseq.db.frontend.schema :as db-schema]
             [logseq.db.sqlite.create-graph :as sqlite-create-graph]
             [logseq.db.sqlite.util :as sqlite-util]))
 
-;; TODO: fixes/rollback
 ;; Frontend migrations
 ;; ===================
 
@@ -156,6 +157,7 @@
                {old-p new-p}
                {:replace-fn (fn [id prop-value]
                               (let [page (d/entity db id)
+                                    ;; bad impl, it's not just simple db/ident renaming
                                     new-p' (if (ldb/class? page) new-p :block/parent)]
                                 [[:db/retract id old-p]
                                  [:db/add id new-p' prop-value]]))})
@@ -289,11 +291,31 @@
                    db)]
     (mapcat
      (fn [id]
-       (let [title (:block/title (d/entity db id))]
-         [[:db/add id :db/ident (db-class/create-user-class-ident-from-name db title)]
-          [:db/add id :logseq.property.class/extends :logseq.class/Root]
-          [:db/retract id :block/tags :logseq.class/Page]
-          [:db/retract id :block/refs :logseq.class/Page]]))
+       [[:db/add id :logseq.property.class/extends :logseq.class/Root]
+        [:db/retract id :block/tags :logseq.class/Page]
+        [:db/retract id :block/refs :logseq.class/Page]
+        [:db/retract id :block/path-refs :logseq.class/Page]])
+     class-ids)))
+
+(defn add-missing-db-ident-for-tags2
+  [db]
+  (let [class-ids
+        (d/q
+         '[:find [?b ...]
+           :where
+           [?b :block/tags :logseq.class/Tag]
+           [(missing? $ ?b :db/ident)]]
+         db)]
+    (keep
+     (fn [id]
+       (let [ent (d/entity db id)
+             title (:block/title ent)
+             block-uuid (:block/uuid ent)]
+         (when block-uuid
+           {:db-ident-or-block-uuid block-uuid
+            :new-db-ident (db-ident/replace-db-ident-random-suffix
+                           (db-class/create-user-class-ident-from-name db title)
+                           (subs (str block-uuid) 28))})))
      class-ids)))
 
 (defn fix-using-properties-as-tags
@@ -310,11 +332,32 @@
                       (map first))]
     (mapcat
      (fn [id]
-       (let [property (d/entity db id)
-             title (:block/title property)]
-         (into (retract-property-attributes id)
-               [[:db/retract id :logseq.property/parent]
-                [:db/add id :db/ident (db-class/create-user-class-ident-from-name db title)]])))
+       (into (retract-property-attributes id)
+             [[:db/retract id :logseq.property/parent]]))
+     property-ids)))
+
+(defn fix-using-properties-as-tags2
+  [db]
+  (let [property-ids
+        (->>
+         (d/q
+          '[:find ?b ?i
+            :where
+            [?b :block/tags :logseq.class/Tag]
+            [?b :db/ident ?i]]
+          db)
+         (filter (fn [[_ ident]] (= "user.property" (namespace ident))))
+         (map first))]
+    (keep
+     (fn [id]
+       (let [ent (d/entity db id)
+             title (:block/title ent)
+             block-uuid (:block/uuid ent)]
+         (when block-uuid
+           {:db-ident-or-block-uuid block-uuid
+            :new-db-ident (db-ident/replace-db-ident-random-suffix
+                           (db-class/create-user-class-ident-from-name db title)
+                           (subs (str block-uuid) 28))})))
      property-ids)))
 
 (defn remove-block-order-for-tags
@@ -364,12 +407,12 @@
 (def schema-version->updates
   "A vec of tuples defining datascript migrations. Each tuple consists of the
    schema version integer and a migration map. A migration map can have keys of :properties, :classes
-   and :fix."
+   :rename-db-idents and :fix."
   [["65.0" {:fix separate-classes-and-properties}]
    ["65.1" {:fix fix-rename-parent-to-extends}]
    ["65.2" {:fix fix-tag-properties}]
-   ["65.3" {:fix add-missing-db-ident-for-tags}]
-   ["65.4" {:fix fix-using-properties-as-tags}]
+   ["65.3" {:rename-db-idents add-missing-db-ident-for-tags2 :fix add-missing-db-ident-for-tags}]
+   ["65.4" {:rename-db-idents fix-using-properties-as-tags2 :fix fix-using-properties-as-tags}]
    ["65.5" {:fix remove-block-order-for-tags}]
    ["65.6" {:fix update-extends-to-cardinality-many}]
    ["65.7" {:fix add-quick-add-page}]
@@ -388,6 +431,7 @@
         (js/console.warn (str "Current db schema-version is " db-schema/version ", max available schema-version is " max-schema-version))))))
 
 (defn ensure-built-in-data-exists!
+  "Return tx-data"
   [conn]
   (let [*uuids (atom {})
         data (->> (sqlite-create-graph/build-db-initial-data "")
@@ -440,12 +484,16 @@
                    [:block/uuid (@*uuids (second f))]
                    :else
                    f))
-               data)]
-    (d/transact! conn data' {:fix-db? true
-                             :db-migrate? true})))
+               data)
+        r (d/transact! conn data' {:fix-db? true
+                                   :db-migrate? true})]
+    (assoc r :migrate-updates
+           ;; fake it as a normal :fix type migration
+           {:fix (constantly :ensure-built-in-data-exists!)})))
 
 (defn- upgrade-version!
-  [conn db-based? version {:keys [properties classes fix]}]
+  "Return tx-data"
+  [conn db-based? version {:keys [properties classes rename-db-idents fix] :as migrate-updates}]
   (let [version (db-schema/parse-schema-version version)
         db @conn
         new-properties (->> (select-keys db-property/built-in-properties properties)
@@ -467,23 +515,31 @@
         new-class-idents (keep (fn [class]
                                  (when-let [db-ident (:db/ident class)]
                                    {:db/ident db-ident})) new-classes)
+        [rename-db-idents-tx-data rename-db-idents-coll]
+        (when rename-db-idents
+          (rename-db-ident/rename-db-idents-migration-tx-data db rename-db-idents))
         fixes (when (fn? fix)
                 (fix db))
-        tx-data (if db-based? (concat new-class-idents new-properties new-classes fixes) fixes)
+        tx-data (if db-based?
+                  (concat new-class-idents new-properties new-classes rename-db-idents-tx-data fixes)
+                  fixes)
         tx-data' (concat
                   [(sqlite-util/kv :logseq.kv/schema-version version)]
-                  tx-data)]
-    (ldb/transact! conn tx-data' {:db-migrate? true})
-    (println "DB schema migrated to" version)))
+                  tx-data)
+        r (ldb/transact! conn tx-data' {:db-migrate? true})
+        migrate-updates (cond-> migrate-updates
+                          rename-db-idents (assoc :rename-db-idents rename-db-idents-coll))]
+    (println "DB schema migrated to" version)
+    (assoc r :migrate-updates migrate-updates)))
 
 (defn migrate
   "Migrate 'frontend' datascript schema and data. To add a new migration,
   add an entry to schema-version->updates and bump db-schema/version"
-  [conn]
+  [conn & {:keys [target-version] :or {target-version db-schema/version}}]
   (when (ldb/db-based-graph? @conn)
     (let [db @conn
           version-in-db (db-schema/parse-schema-version (or (:kv/value (d/entity db :logseq.kv/schema-version)) 0))
-          compare-result (db-schema/compare-schema-version db-schema/version version-in-db)]
+          compare-result (db-schema/compare-schema-version target-version version-in-db)]
       (cond
         (zero? compare-result)
         nil
@@ -497,14 +553,21 @@
                 updates (keep (fn [[v updates]]
                                 (let [v* (db-schema/parse-schema-version v)]
                                   (when (and (neg? (db-schema/compare-schema-version version-in-db v*))
-                                             (not (pos? (db-schema/compare-schema-version v* db-schema/version))))
+                                             (not (pos? (db-schema/compare-schema-version v* target-version))))
                                     [v updates])))
-                              schema-version->updates)]
+                              schema-version->updates)
+                result-ks [:tx-data :db-before :db-after :migrate-updates]
+                *upgrade-result-coll (atom [])]
             (println "DB schema migrated from" version-in-db)
             (doseq [[v m] updates]
-              (upgrade-version! conn db-based? v m))
-            (ensure-built-in-data-exists! conn))
+              (let [r (upgrade-version! conn db-based? v m)]
+                (swap! *upgrade-result-coll conj (select-keys r result-ks))))
+            (swap! *upgrade-result-coll conj
+                   (select-keys (ensure-built-in-data-exists! conn) result-ks))
+            {:from-version version-in-db
+             :to-version target-version
+             :upgrade-result-coll @*upgrade-result-coll})
           (catch :default e
-            (prn :error (str "DB migration failed to migrate to " db-schema/version " from " version-in-db ":"))
+            (prn :error (str "DB migration failed to migrate to " target-version " from " version-in-db ":"))
             (js/console.error e)
             (throw e)))))))

+ 37 - 0
src/main/frontend/worker/db/rename_db_ident.cljs

@@ -0,0 +1,37 @@
+(ns frontend.worker.db.rename-db-ident
+  "utils for rename-db-idents migration"
+  (:require [datascript.core :as d]
+            [logseq.db :as ldb]))
+
+(defn rename-db-idents-migration-tx-data
+  "Rename :db/ident and replace all usages as well.
+  rename-db-idents: fn to generate coll of {:db-ident ..., :new-db-ident ...}
+  NOTE: this fn should only care about :db/ident changing, don't touch other attr/values"
+  [db rename-db-idents]
+  (assert (fn? rename-db-idents))
+  (let [rename-db-idents-coll (rename-db-idents db)
+        rename-db-idents-coll2  (rename-db-idents db)
+        ;; ensure there's no random data in result
+        _ (when (not= rename-db-idents-coll rename-db-idents-coll2)
+            (throw (ex-info "db-idents cannot be randomly generated"
+                            {:rename-db-idents-colls [rename-db-idents-coll rename-db-idents-coll2]})))
+        *rename-db-idents-coll (atom [])
+        tx-data
+        (->> (for [{:keys [db-ident-or-block-uuid new-db-ident] :as rename-db-ident} rename-db-idents-coll
+                   :let [ent (d/entity db (if (keyword? db-ident-or-block-uuid)
+                                            db-ident-or-block-uuid
+                                            [:block/uuid db-ident-or-block-uuid]))
+                         old-db-ident (:db/ident ent)]]
+               (do (when (some? ent)
+                     (when-not (ldb/class? ent)
+                       (throw (ex-info "Only entities of class type support :rename-db-ident" {:ent (into {} ent)})))
+                     (swap! *rename-db-idents-coll conj rename-db-ident))
+                   (cons {:db/id (:db/id ent) :db/ident new-db-ident}
+                         (some->> old-db-ident
+                                  (d/q '[:find ?b ?v :in $ ?a :where [?b ?a ?v]] db)
+                                  (mapcat (fn [[id v]]
+                                            [[:db/retract id old-db-ident]
+                                             [:db/add id new-db-ident v]]))))))
+             (apply concat)
+             doall)]
+    [tx-data @*rename-db-idents-coll]))

+ 4 - 11
src/main/frontend/worker/db_listener.cljs

@@ -4,6 +4,7 @@
             [datascript.core :as d]
             [frontend.common.thread-api :as thread-api]
             [frontend.worker.pipeline :as worker-pipeline]
+            [frontend.worker.rtc.gen-client-op :as gen-client-op]
             [frontend.worker.search :as search]
             [frontend.worker.shared-service :as shared-service]
             [frontend.worker.state :as worker-state]
@@ -82,13 +83,7 @@
           get-batch-txs #(->> @*batch-all-txs
                               (sort-by :tx)
                               (common-util/distinct-by-last-wins (fn [[e a v _tx added]] [e a v added])))
-          additional-args (fn [tx-data]
-                            (let [datom-vec-coll (map vec tx-data)
-                                  id->same-entity-datoms (group-by first datom-vec-coll)
-                                  id-order (distinct (map first datom-vec-coll))
-                                  same-entity-datoms-coll (map id->same-entity-datoms id-order)]
-                              [[:same-entity-datoms-coll same-entity-datoms-coll]
-                               [:id->same-entity-datoms id->same-entity-datoms]]))]
+          additional-args gen-client-op/group-datoms-by-entity]
       (d/listen! conn ::listen-db-changes!
                  (fn listen-db-changes!-inner
                    [{:keys [tx-data _db-before _db-after tx-meta] :as tx-report}]
@@ -119,8 +114,7 @@
                                  tx-report' (if sync-db-to-main-thread?
                                               (sync-db-to-main-thread repo conn tx-report)
                                               tx-report)
-                                 opt (into {:repo repo}
-                                           (additional-args (:tx-data tx-report')))]
+                                 opt (assoc (additional-args (:tx-data tx-report')) :repo repo)]
                              (doseq [[k handler-fn] handlers]
                                (handler-fn k opt tx-report'))))
 
@@ -129,7 +123,6 @@
                          (let [tx-report' (if sync-db-to-main-thread?
                                             (sync-db-to-main-thread repo conn tx-report)
                                             tx-report)
-                               opt (into {:repo repo}
-                                         (additional-args (:tx-data tx-report')))]
+                               opt (assoc (additional-args (:tx-data tx-report')) :repo repo)]
                            (doseq [[k handler-fn] handlers]
                              (handler-fn k opt tx-report')))))))))))

+ 7 - 3
src/main/frontend/worker/db_worker.cljs

@@ -29,6 +29,7 @@
             [frontend.worker.rtc.client-op :as client-op]
             [frontend.worker.rtc.core :as rtc.core]
             [frontend.worker.rtc.db-listener]
+            [frontend.worker.rtc.migrate :as rtc-migrate]
             [frontend.worker.search :as search]
             [frontend.worker.shared-service :as shared-service]
             [frontend.worker.state :as worker-state]
@@ -287,13 +288,16 @@
           (d/reset-schema! client-ops-conn client-op/schema-in-db))
         (when (and db-based? (not initial-data-exists?) (not datoms))
           (let [config (or config "")
-                initial-data (sqlite-create-graph/build-db-initial-data config
-                                                                        (select-keys opts [:import-type :graph-git-sha]))]
+                initial-data (sqlite-create-graph/build-db-initial-data
+                              config (select-keys opts [:import-type :graph-git-sha]))]
             (d/transact! conn initial-data {:initial-db? true})))
 
         (gc-sqlite-dbs! db client-ops-db conn {})
 
-        (db-migrate/migrate conn)
+        (let [migration-result (db-migrate/migrate conn)]
+          (when (client-op/rtc-db-graph? repo)
+            (let [client-ops (rtc-migrate/migration-results=>client-ops migration-result)]
+              (client-op/add-ops! repo client-ops))))
 
         (db-listener/listen-db-changes! repo (get @*datascript-conns repo))))))
 

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

@@ -289,29 +289,29 @@
             (:remote-ops (local-block-ops->remote-ops db block-ops-map))]))
         block-ops-map-coll))
 
-(defmulti ^:private local-db-ident-kv-ops->remote-ops-aux (fn [op-type & _] op-type))
-(defmethod local-db-ident-kv-ops->remote-ops-aux :update-kv-value
-  [_ op]
-  (let [op-value (last op)
-        db-ident (:db-ident op-value)
-        value (:value op-value)]
-    [:update-kv-value {:db-ident db-ident :value (ldb/write-transit-str value)}]))
-
-(defmethod local-db-ident-kv-ops->remote-ops-aux :db-ident
-  [_ _op]
-  ;; ignore
-  )
-
-(defn- local-db-ident-kv-ops->remote-ops
-  [db-ident-kv-ops-map]
+(defn- local-update-kv-value-ops->remote-ops
+  [update-kv-value-ops-map]
   (keep
    (fn [[op-type op]]
-     (local-db-ident-kv-ops->remote-ops-aux op-type op))
-   db-ident-kv-ops-map))
-
-(defn- gen-db-ident-kv-remote-ops
-  [db-ident-kv-ops-map-coll]
-  (mapcat local-db-ident-kv-ops->remote-ops db-ident-kv-ops-map-coll))
+     (when (= :update-kv-value op-type)
+       (let [{:keys [db-ident value]} (last op)]
+         [:update-kv-value {:db-ident db-ident :value (ldb/write-transit-str value)}])))
+   update-kv-value-ops-map))
+
+(defn- gen-update-kv-value-remote-ops
+  [update-kv-value-ops-map-coll]
+  (mapcat local-update-kv-value-ops->remote-ops update-kv-value-ops-map-coll))
+
+(defn- local-rename-db-ident-ops->remote-ops
+  [rename-db-ident-ops-map]
+  (keep (fn [[op-type op]]
+          (when (keyword-identical? :rename-db-ident op-type)
+            [:rename-db-ident (select-keys (last op) [:db-ident-or-block-uuid :new-db-ident])]))
+        rename-db-ident-ops-map))
+
+(defn- gen-rename-db-ident-remote-ops
+  [rename-db-ident-ops-map-coll]
+  (mapcat local-rename-db-ident-ops->remote-ops rename-db-ident-ops-map-coll))
 
 (defn- merge-remove-remove-ops
   [remote-remove-ops]
@@ -371,7 +371,7 @@
     (concat update-schema-ops update-page-ops remove-ops sorted-move-ops update-ops remove-page-ops)))
 
 (defn- rollback
-  [repo block-ops-map-coll db-ident-kv-ops-map-coll]
+  [repo block-ops-map-coll update-kv-value-ops-map-coll rename-db-ident-ops-map-coll]
   (let [block-ops
         (mapcat
          (fn [m]
@@ -380,16 +380,25 @@
                      op))
                  m))
          block-ops-map-coll)
-        db-ident-kv-ops
+        update-kv-value-ops
+        (mapcat
+         (fn [m]
+           (keep (fn [[k op]]
+                   (when (keyword-identical? :update-kv-value k)
+                     op))
+                 m))
+         update-kv-value-ops-map-coll)
+        rename-db-ident-ops
         (mapcat
          (fn [m]
            (keep (fn [[k op]]
-                   (when-not (keyword-identical? :db-ident k)
+                   (when (keyword-identical? :rename-db-ident k)
                      op))
                  m))
-         db-ident-kv-ops-map-coll)]
+         rename-db-ident-ops-map-coll)]
     (client-op/add-ops! repo block-ops)
-    (client-op/add-ops! repo db-ident-kv-ops)
+    (client-op/add-ops! repo update-kv-value-ops)
+    (client-op/add-ops! repo rename-db-ident-ops)
     nil))
 
 (defn new-task--push-local-ops
@@ -397,11 +406,15 @@
   [repo conn graph-uuid major-schema-version date-formatter get-ws-create-task *remote-profile? add-log-fn]
   (m/sp
     (let [block-ops-map-coll (client-op/get&remove-all-block-ops repo)
-          db-ident-kv-ops-map-coll (client-op/get&remove-all-db-ident-kv-ops repo)
+          update-kv-value-ops-map-coll (client-op/get&remove-all-update-kv-value-ops repo)
+          rename-db-ident-ops-map-coll (client-op/get&remove-all-rename-db-ident-ops repo)
           block-uuid->remote-ops (not-empty (gen-block-uuid->remote-ops @conn block-ops-map-coll))
-          other-remote-ops (gen-db-ident-kv-remote-ops db-ident-kv-ops-map-coll)
-          remote-ops (concat (when block-uuid->remote-ops (sort-remote-ops block-uuid->remote-ops))
-                             other-remote-ops)]
+          rename-db-ident-remote-ops (gen-rename-db-ident-remote-ops rename-db-ident-ops-map-coll)
+          other-remote-ops (gen-update-kv-value-remote-ops update-kv-value-ops-map-coll)
+          remote-ops (concat
+                      rename-db-ident-remote-ops
+                      (when block-uuid->remote-ops (sort-remote-ops block-uuid->remote-ops))
+                      other-remote-ops)]
       (when-let [ops-for-remote (rtc-schema/to-ws-ops-decoder remote-ops)]
         (let [local-tx (client-op/get-local-tx repo)
               r (try
@@ -411,7 +424,7 @@
                                                    :ops ops-for-remote :t-before (or local-tx 1)}
                                             (true? @*remote-profile?) (assoc :profile true))))
                   (catch :default e
-                    (rollback repo block-ops-map-coll db-ident-kv-ops-map-coll)
+                    (rollback repo block-ops-map-coll update-kv-value-ops-map-coll rename-db-ident-ops-map-coll)
                     (throw e)))]
           (if-let [remote-ex (:ex-data r)]
             (do (add-log-fn :rtc.log/push-local-update remote-ex)
@@ -420,18 +433,18 @@
                   ;;   conflict-update remote-graph, keep these local-pending-ops
                   ;;   and try to send ops later
                   :graph-lock-failed
-                  (rollback repo block-ops-map-coll db-ident-kv-ops-map-coll)
+                  (rollback repo block-ops-map-coll update-kv-value-ops-map-coll rename-db-ident-ops-map-coll)
                   ;; - :graph-lock-missing
                   ;;   this case means something wrong in remote-graph data,
                   ;;   nothing to do at client-side
                   :graph-lock-missing
-                  (do (rollback repo block-ops-map-coll db-ident-kv-ops-map-coll)
+                  (do (rollback repo block-ops-map-coll update-kv-value-ops-map-coll rename-db-ident-ops-map-coll)
                       (throw r.ex/ex-remote-graph-lock-missing))
 
                   :rtc.exception/get-s3-object-failed
-                  (rollback repo block-ops-map-coll db-ident-kv-ops-map-coll)
+                  (rollback repo block-ops-map-coll update-kv-value-ops-map-coll rename-db-ident-ops-map-coll)
                   ;; else
-                  (do (rollback repo block-ops-map-coll db-ident-kv-ops-map-coll)
+                  (do (rollback repo block-ops-map-coll update-kv-value-ops-map-coll rename-db-ident-ops-map-coll)
                       (throw (ex-info "Unavailable1" {:remote-ex remote-ex})))))
 
             (do (assert (pos? (:t r)) r)

+ 90 - 31
src/main/frontend/worker/rtc/client_op.cljs

@@ -20,6 +20,13 @@
      [:value [:map
               [:db-ident :keyword]
               [:value :any]]]]]
+   [:rename-db-ident
+    [:catn
+     [:op :keyword]
+     [:t :int]
+     [:value [:map
+              [:db-ident-or-block-uuid [:or :keyword :uuid]]
+              [:new-db-ident :keyword]]]]]
    [:move
     [:catn
      [:op :keyword]
@@ -72,13 +79,15 @@
 
 (def ^:private block-op-types #{:move :remove :update-page :remove-page :update})
 (def ^:private asset-op-types #{:update-asset :remove-asset})
-(def ^:private db-ident-kv-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 schema-in-db
   "TODO: rename this db-name from client-op to client-metadata+op.
   and move it to its own namespace."
   {:block/uuid {:db/unique :db.unique/identity}
    :db-ident {:db/unique :db.unique/identity}
+   :db-ident-or-block-uuid {:db/unique :db.unique/identity}
    :local-tx {:db/index true}
    :graph-uuid {:db/index true}
    :aes-key-jwk {:db/index true}
@@ -237,15 +246,33 @@
            (cons [:db/add tmpid :db-ident db-ident] tx-data))))
      db-ident->op-type->op)))
 
+(defn generate-rename-db-ident-ops-tx-data
+  [ops]
+  (let [op-type :rename-db-ident
+        db-ident-or-block-uuid->op
+        (reduce
+         (fn [r op]
+           (let [[_op-type _t value] op
+                 db-ident-or-block-uuid (:db-ident-or-block-uuid value)]
+             (assoc r db-ident-or-block-uuid op)))
+         {} ops)]
+    (mapcat
+     (fn [[db-ident-or-block-uuid op]]
+       (let [tmpid (str db-ident-or-block-uuid "-rename-db-ident")]
+         [[:db/add tmpid :db-ident-or-block-uuid db-ident-or-block-uuid]
+          [:db/add tmpid op-type op]]))
+     db-ident-or-block-uuid->op)))
+
 (defn- partition-ops
-  "Return [db-ident-kv-ops block-ops]"
+  "Return [:update-kv-value-ops :rename-db-ident-ops block-ops]"
   [ops]
-  ((juxt :db-ident :block-uuid)
+  ((juxt :update-kv-value :rename-db-ident :block-uuid)
    (group-by
-    (fn [[_op-type _t value :as op]]
+    (fn [[op-type _t value :as op]]
       (cond
         (:block-uuid value) :block-uuid
-        (:db-ident value) :db-ident
+        (= :update-kv-value op-type) :update-kv-value
+        (= :rename-db-ident op-type) :rename-db-ident
         :else (throw (ex-info "invalid op" {:op op}))))
     ops)))
 
@@ -255,10 +282,11 @@
     (let [conn (worker-state/get-client-ops-conn repo)
           ops (ops-coercer ops)
           _ (assert (some? conn) repo)
-          [db-ident-kv-ops block-ops] (partition-ops ops)
+          [update-kv-value-ops rename-db-ident-ops block-ops] (partition-ops ops)
           tx-data1 (when (seq block-ops) (generate-block-ops-tx-data @conn block-ops))
-          tx-data2 (when (seq db-ident-kv-ops) (generate-ident-kv-ops-tx-data @conn db-ident-kv-ops))]
-      (when-let [tx-data (not-empty (concat tx-data1 tx-data2))]
+          tx-data2 (when (seq update-kv-value-ops) (generate-ident-kv-ops-tx-data @conn update-kv-value-ops))
+          tx-data3 (when (seq rename-db-ident-ops) (generate-rename-db-ident-ops-tx-data rename-db-ident-ops))]
+      (when-let [tx-data (not-empty (concat tx-data1 tx-data2 tx-data3))]
         (d/transact! conn tx-data)))))
 
 (defn- get-all-block-ops*
@@ -280,7 +308,7 @@
                    [e op-map]))))
        (into {})))
 
-(defn- get-all-db-ident-kv-ops*
+(defn- get-all-update-kv-value-ops*
   "Return e->op-map"
   [db]
   (let [db-ident-datoms (d/datoms db :avet :db-ident)
@@ -291,11 +319,27 @@
                                     (keep (fn [datom]
                                             (let [a (:a datom)]
                                               (when (or (keyword-identical? :db-ident a)
-                                                        (contains? db-ident-kv-op-types a))
+                                                        (contains? update-kv-value-op-types a))
                                                 [a (:v datom)]))))
                                     datoms)]
-                   (when (and (:db-ident op-map)
-                              (> (count op-map) 1))
+                   (when (and (:db-ident op-map) (> (count op-map) 1))
+                     [e op-map]))))
+         (into {}))))
+
+(defn- get-all-rename-db-ident-ops*
+  [db]
+  (let [db-ident-or-block-uuid-datoms (d/datoms db :avet :db-ident-or-block-uuid)
+        es (map :e db-ident-or-block-uuid-datoms)]
+    (->> (map (fn [e] [e (d/datoms db :eavt e)]) es)
+         (keep (fn [[e datoms]]
+                 (let [op-map (into {}
+                                    (keep (fn [datom]
+                                            (let [a (:a datom)]
+                                              (when (or (keyword-identical? :db-ident-or-block-uuid a)
+                                                        (contains? db-ident-rename-op-types a))
+                                                [a (:v datom)]))))
+                                    datoms)]
+                   (when (and (:db-ident-or-block-uuid op-map) (> (count op-map) 1))
                      [e op-map]))))
          (into {}))))
 
@@ -307,10 +351,18 @@
     (d/transact! conn retract-all-tx-data)
     (vals e->op-map)))
 
-(defn- get&remove-all-db-ident-kv-ops*
+(defn- get&remove-all-update-kv-value-ops*
+  [conn]
+  (let [e->op-map (get-all-update-kv-value-ops* @conn)
+        retract-all-tx-data (mapcat (fn [e] (map (fn [a] [:db.fn/retractAttribute e a]) update-kv-value-op-types))
+                                    (keys e->op-map))]
+    (d/transact! conn retract-all-tx-data)
+    (vals e->op-map)))
+
+(defn- get&remove-all-rename-db-ident-ops*
   [conn]
-  (let [e->op-map (get-all-db-ident-kv-ops* @conn)
-        retract-all-tx-data (mapcat (fn [e] (map (fn [a] [:db.fn/retractAttribute e a]) db-ident-kv-op-types))
+  (let [e->op-map (get-all-rename-db-ident-ops* @conn)
+        retract-all-tx-data (mapcat (fn [e] (map (fn [a] [:db.fn/retractAttribute e a]) db-ident-rename-op-types))
                                     (keys e->op-map))]
     (d/transact! conn retract-all-tx-data)
     (vals e->op-map)))
@@ -341,15 +393,24 @@
   (when-let [conn (worker-state/get-client-ops-conn repo)]
     (get&remove-all-block-ops* conn)))
 
-(defn get&remove-all-db-ident-kv-ops
+(defn get&remove-all-update-kv-value-ops
   [repo]
   (when-let [conn (worker-state/get-client-ops-conn repo)]
-    (get&remove-all-db-ident-kv-ops* conn)))
+    (get&remove-all-update-kv-value-ops* conn)))
 
-(defn get-unpushed-block-ops-count
+(defn get&remove-all-rename-db-ident-ops
   [repo]
   (when-let [conn (worker-state/get-client-ops-conn repo)]
-    (count (get-all-block-ops* @conn))))
+    (get&remove-all-rename-db-ident-ops* conn)))
+
+(defn get-unpushed-ops-count
+  "except asset-ops"
+  [repo]
+  (when-let [conn (worker-state/get-client-ops-conn repo)]
+    (+
+     (count (get-all-block-ops* @conn))
+     (count (get-all-rename-db-ident-ops* @conn))
+     (count (get-all-update-kv-value-ops* @conn)))))
 
 (defn rtc-db-graph?
   "Is db-graph & RTC enabled"
@@ -361,19 +422,17 @@
 (defn create-pending-block-ops-count-flow
   [repo]
   (when-let [conn (worker-state/get-client-ops-conn repo)]
-    (letfn [(datom-count [db]
-              (count (get-all-block-ops* db)))]
-      (let [db-updated-flow
-            (m/observe
-             (fn ctor [emit!]
-               (d/listen! conn :create-pending-ops-count-flow #(emit! true))
-               (emit! true)
-               (fn dtor []
-                 (d/unlisten! conn :create-pending-ops-count-flow))))]
-        (m/ap
-          (let [_ (m/?> (c.m/throttle 100 db-updated-flow))]
+    (let [db-updated-flow
+          (m/observe
+           (fn ctor [emit!]
+             (d/listen! conn :create-pending-ops-count-flow #(emit! true))
+             (emit! true)
+             (fn dtor []
+               (d/unlisten! conn :create-pending-ops-count-flow))))]
+      (m/ap
+        (let [_ (m/?> (c.m/throttle 200 db-updated-flow))]
             ;; throttle db-updated-flow, because `datom-count` is a time-consuming fn
-            (datom-count @conn)))))))
+          (get-unpushed-ops-count repo))))))
 
 ;;; asset ops
 (defn add-asset-ops

+ 1 - 19
src/main/frontend/worker/rtc/core.cljs

@@ -14,7 +14,6 @@
             [frontend.worker.rtc.exception :as r.ex]
             [frontend.worker.rtc.full-upload-download-graph :as r.upload-download]
             [frontend.worker.rtc.log-and-state :as rtc-log-and-state]
-            [frontend.worker.rtc.migrate :as r.migrate]
             [frontend.worker.rtc.remote-update :as r.remote-update]
             [frontend.worker.rtc.skeleton]
             [frontend.worker.rtc.ws :as ws]
@@ -69,7 +68,7 @@
         merge-flow (m/latest vector auto-push-flow clock-flow)]
     (m/eduction (filter first)
                 (map second)
-                (filter (fn [v] (when (pos? (client-op/get-unpushed-block-ops-count repo)) v)))
+                (filter (fn [v] (when (pos? (client-op/get-unpushed-ops-count repo)) v)))
                 merge-flow)))
 
 (defn- create-pull-remote-updates-flow
@@ -164,17 +163,6 @@
        ws-state (assoc :ws-state ws-state)))
    (m/reductions {} nil ws-state-flow)))
 
-(defn- add-migration-client-ops!
-  [repo db server-schema-version]
-  (when server-schema-version
-    (let [client-schema-version (ldb/get-graph-schema-version db)
-          added-ops (r.migrate/add-migration-client-ops! repo db server-schema-version client-schema-version)]
-      (when (seq added-ops)
-        (log/info :add-migration-client-ops
-                  {:repo repo
-                   :server-schema-version server-schema-version
-                   :client-schema-version client-schema-version})))))
-
 (defn- update-remote-schema-version!
   [conn server-schema-version]
   (when server-schema-version
@@ -252,7 +240,6 @@
           (m/? get-ws-create-task)
           (started-dfv true)
           (update-remote-schema-version! conn @*server-schema-version)
-          (add-migration-client-ops! repo @conn @*server-schema-version)
           (reset! *assets-sync-loop-canceler
                   (c.m/run-task :assets-sync-loop-task
                     assets-sync-loop-task))
@@ -656,11 +643,6 @@
     [token graph-uuid schema-version]
     (new-task--download-info-list token graph-uuid schema-version)))
 
-(def-thread-api :thread-api/rtc-add-migration-client-ops
-  [repo server-schema-version]
-  (when-let [db @(worker-state/get-datascript-conn repo)]
-    (add-migration-client-ops! repo db server-schema-version)))
-
 ;;; ================ API (ends) ================
 
 ;;; subscribe state ;;;

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

@@ -6,6 +6,16 @@
             [logseq.db :as ldb]
             [logseq.db.frontend.property :as db-property]))
 
+(defn group-datoms-by-entity
+  "Groups transaction datoms by entity and returns a map of entity-id to datoms."
+  [tx-data]
+  (let [datom-vec-coll (map vec tx-data)
+        id->same-entity-datoms (group-by first datom-vec-coll)
+        id-order (distinct (map first datom-vec-coll))
+        same-entity-datoms-coll (map id->same-entity-datoms id-order)]
+    {:same-entity-datoms-coll same-entity-datoms-coll
+     :id->same-entity-datoms  id->same-entity-datoms}))
+
 (defn- latest-add?->v->t
   [add?->v->t]
   (let [latest-add     (first (sort-by second > (seq (add?->v->t true))))
@@ -158,3 +168,15 @@
   (when (seq class-ents)
     (assert (every? ldb/class? class-ents))
     (generate-rtc-ops-from-entities class-ents)))
+
+(defn generate-rtc-rename-db-ident-ops
+  [rename-db-idents]
+  (assert (every? (fn [{:keys [db-ident-or-block-uuid new-db-ident]}]
+                    (and (or (keyword? db-ident-or-block-uuid) (uuid? db-ident-or-block-uuid))
+                         (keyword? new-db-ident)))
+                  rename-db-idents)
+          rename-db-idents)
+  (map
+   (fn [{:keys [db-ident-or-block-uuid new-db-ident]}]
+     [:rename-db-ident 0 {:db-ident-or-block-uuid db-ident-or-block-uuid :new-db-ident new-db-ident}])
+   rename-db-idents))

+ 5 - 0
src/main/frontend/worker/rtc/malli_schema.cljs

@@ -30,6 +30,11 @@
      [:map
       [:db-ident :keyword]
       [:value :string]]]]
+   [:rename-db-ident
+    [:cat :keyword
+     [:map
+      [:db-ident-or-block-uuid [:or :keyword :uuid]]
+      [:new-db-ident :keyword]]]]
    [:move
     [:cat :keyword
      [:map

+ 38 - 44
src/main/frontend/worker/rtc/migrate.cljs

@@ -1,49 +1,43 @@
 (ns frontend.worker.rtc.migrate
   "migrate server data according to schema-version and client's migration-updates"
   (:require [datascript.core :as d]
-            [frontend.worker.db.migrate :as db-migrate]
-            [frontend.worker.rtc.client-op :as client-op]
-            [frontend.worker.rtc.gen-client-op :as gen-client-op]
-            [logseq.db.frontend.schema :as db-schema]))
+            [frontend.worker.rtc.gen-client-op :as gen-client-op]))
 
-(defn- server-client-schema-version->migrations
-  [server-schema-version client-schema-version]
-  (when (neg? (db-schema/compare-schema-version server-schema-version client-schema-version))
-    (let [sorted-schema-version->updates
-          (->> (map (fn [[schema-version updates]]
-                      [((juxt :major :minor) (db-schema/parse-schema-version schema-version))
-                       updates])
-                    db-migrate/schema-version->updates)
-               (sort-by first))]
-      (->> sorted-schema-version->updates
-           (drop-while (fn [[schema-version _updates]]
-                         (not (neg? (db-schema/compare-schema-version server-schema-version schema-version)))))
-           (take-while (fn [[schema-version _updates]]
-                         (not (neg? (db-schema/compare-schema-version client-schema-version schema-version)))))
-           (map second)))))
+(def apply-conj (partial apply conj))
 
-(defn- migration-updates->client-ops
-  "convert :classes, :properties from frontend.worker.db.migrate/schema-version->updates into client-ops"
-  [db client-schema-version migrate-updates]
-  (let [property-ks (mapcat :properties migrate-updates)
-        class-ks (mapcat :classes migrate-updates)
-        d-entity-fn (partial d/entity db)
-        new-property-entities (keep d-entity-fn property-ks)
-        new-class-entities (keep d-entity-fn class-ks)
-        client-ops (vec (concat (gen-client-op/generate-rtc-ops-from-property-entities new-property-entities)
-                                (gen-client-op/generate-rtc-ops-from-class-entities new-class-entities)))
-        max-t (apply max 0 (map second client-ops))]
-    (conj client-ops
-          [:update-kv-value
-           max-t
-           {:db-ident :logseq.kv/schema-version
-            :value client-schema-version}])))
-
-(defn add-migration-client-ops!
-  [repo db server-schema-version client-schema-version]
-  (assert (and server-schema-version client-schema-version))
-  (when-let [ops (not-empty
-                  (some->> (server-client-schema-version->migrations server-schema-version client-schema-version)
-                           (migration-updates->client-ops db client-schema-version)))]
-    (client-op/add-ops! repo ops)
-    ops))
+(defn migration-results=>client-ops
+  [{:keys [_from-version to-version upgrade-result-coll] :as _migration-result}]
+  (when to-version
+    (let [client-ops
+          (mapcat
+           (fn [{:keys [tx-data db-before db-after migrate-updates]}]
+             (let [*tx-data (atom [])]
+               (when-let [rename-db-idents (:rename-db-idents migrate-updates)]
+                 (swap! *tx-data apply-conj
+                        (gen-client-op/generate-rtc-rename-db-ident-ops rename-db-idents)))
+               (when (:fix migrate-updates)
+                 (let [{:keys [same-entity-datoms-coll id->same-entity-datoms]}
+                       (gen-client-op/group-datoms-by-entity tx-data)
+                       e->a->add?->v->t
+                       (update-vals
+                        id->same-entity-datoms
+                        gen-client-op/entity-datoms=>a->add?->v->t)]
+                   (swap! *tx-data apply-conj
+                          (gen-client-op/generate-rtc-ops
+                           db-before db-after same-entity-datoms-coll e->a->add?->v->t))))
+               (let [property-ks (seq (:properties migrate-updates))
+                     class-ks (:classes migrate-updates)
+                     d-entity-fn (partial d/entity db-after)
+                     new-property-entities (keep d-entity-fn property-ks)
+                     new-class-entities (keep d-entity-fn class-ks)]
+                 (swap! *tx-data apply-conj
+                        (concat (gen-client-op/generate-rtc-ops-from-property-entities new-property-entities)
+                                (gen-client-op/generate-rtc-ops-from-class-entities new-class-entities))))
+               @*tx-data))
+           upgrade-result-coll)
+          max-t (apply max 0 (map second client-ops))]
+      (conj (vec client-ops)
+            [:update-kv-value
+             max-t
+             {:db-ident :logseq.kv/schema-version
+              :value to-version}]))))

+ 4 - 15
src/main/frontend/worker/rtc/skeleton.cljs

@@ -3,7 +3,6 @@
   (:require [clojure.data :as data]
             [datascript.core :as d]
             [frontend.worker.rtc.ws-util :as ws-util]
-            [frontend.worker.shared-service :as shared-service]
             [lambdaisland.glogi :as log]
             [logseq.db :as ldb]
             [logseq.db.frontend.schema :as db-schema]
@@ -37,21 +36,11 @@
               client-builtin-db-idents (set (get-builtin-db-idents db))
               client-schema-version (ldb/get-graph-schema-version db)]
           (when-not (zero? (db-schema/compare-schema-version client-schema-version server-schema-version))
-            (js/console.error "RTC schema error: client version doesn't match server's version")
-            ;; (shared-service/broadcast-to-clients! :notification
-            ;;                                       [[:div
-            ;;                                         [:p (str :client-schema-version client-schema-version)]
-            ;;                                         [:p (str :server-schema-version server-schema-version)]]
-            ;;                                        :error])
-            )
+            (log/warn "RTC schema error: client version doesn't match server's version"
+                      [client-schema-version server-schema-version]))
           (let [[client-only server-only _]
                 (data/diff client-builtin-db-idents server-builtin-db-idents)]
             (when (or (seq client-only) (seq server-only))
-              (shared-service/broadcast-to-clients! :notification
-                                                    [(cond-> [:div]
-                                                       (seq client-only)
-                                                       (conj [:p (str :client-only-db-idents client-only)])
-                                                       (seq server-only)
-                                                       (conj [:p (str :server-only-db-idents server-only)]))
-                                                     :error])))
+              (log/warn :db-idents-diff {:client-only client-only
+                                         :server-only server-only})))
           r)))))

+ 66 - 0
src/test/frontend/worker/rtc/migrate_test.cljs

@@ -0,0 +1,66 @@
+(ns frontend.worker.rtc.migrate-test
+  (:require ["fs" :as fs-node]
+            ;; [cljs.pprint :as pp]
+            [cljs.test :refer [deftest is testing]]
+            [datascript.core :as d]
+            [frontend.worker.db.migrate :as db-migrate]
+            [frontend.worker.rtc.migrate :as rtc-migrate]
+            [logseq.db :as ldb]
+            [logseq.db.frontend.schema :as db-schema]))
+
+(defn- get-specific-result
+  [upgrade-result-coll version]
+  (let [parsed-version (db-schema/parse-schema-version version)]
+    (some (fn [{:keys [tx-data] :as upgrade-result}]
+            (when (some (fn [datom]
+                          (and (= :kv/value (:a datom))
+                               (= parsed-version (db-schema/parse-schema-version (:v datom)))))
+                        tx-data)
+              upgrade-result))
+          upgrade-result-coll)))
+
+(deftest migration-results=>client-ops
+  (testing "65.2 => 65.11"
+    (let [db-transit (str (fs-node/readFileSync "src/test/migration/65.2.transit"))
+          db (ldb/read-transit-str db-transit)
+          conn (d/conn-from-db db)
+          migration-result (db-migrate/migrate conn {:target-version "65.11"})
+          client-ops (rtc-migrate/migration-results=>client-ops migration-result)]
+      ;; (prn :migration-result "================================================================")
+      ;; (pp/pprint (merge (select-keys migration-result [:from-version :to-version])
+      ;;                   {:upgrade-result-coll
+      ;;                    (map (fn [r] [(:tx-data r) (select-keys (:migrate-updates r) [:rename-db-idents])])
+      ;;                         (:upgrade-result-coll migration-result))}))
+      ;; (prn :client-ops "================================================================")
+      ;; (pp/pprint client-ops)
+      (testing "check schema-version"
+        (let [last-op (last client-ops)
+              schema-version-update? (= :update-kv-value (first last-op))]
+          (is schema-version-update? "The last op should be to update schema version")
+          (when schema-version-update?
+            (is (= :logseq.kv/schema-version (get-in last-op [2 :db-ident])) "The schema version key should be correct")
+            (is (= (:to-version migration-result) (get-in last-op [2 :value])) "The schema version should be updated to the new version"))))
+
+      (testing "check 65.3"
+        (let [upgrade-result-65-3 (get-specific-result (:upgrade-result-coll migration-result) "65.3")
+              rename-db-idents (set (:rename-db-idents (:migrate-updates upgrade-result-65-3)))
+              rename-db-ident-op-values (set (keep (fn [op] (when (= :rename-db-ident (first op)) (last op))) client-ops))]
+          (is (some? upgrade-result-65-3))
+          (is (= rename-db-idents rename-db-ident-op-values))))
+
+      (testing "check 65.10"
+        (let [upgrade-result-65-10 (get-specific-result (:upgrade-result-coll migration-result) "65.10")
+              {:keys [tx-data db-after]} upgrade-result-65-10]
+          (is (some? upgrade-result-65-10))
+          (let [tx-id-65-10 (:tx (first tx-data))
+                ents (map (partial d/entity db-after)
+                          (set (keep (fn [datom] (when (:added datom) (:e datom))) tx-data)))
+                block-uuids-in-tx-data (set (keep :block/uuid ents))
+                block-uuids-in-client-ops (set
+                                           (keep
+                                            (fn [[op tx-id value]]
+                                              (when (and (= tx-id tx-id-65-10)
+                                                         (contains? #{:update :update-page :move} op))
+                                                (:block-uuid value)))
+                                            client-ops))]
+            (is (= block-uuids-in-tx-data block-uuids-in-client-ops))))))))

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
src/test/migration/65.2.transit


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff