瀏覽代碼

enhance: add import option to allow existing pages to keep properties

Gabriel Horner 5 月之前
父節點
當前提交
bd115eef0f
共有 2 個文件被更改,包括 60 次插入44 次删除
  1. 21 16
      deps/db/src/logseq/db/sqlite/export.cljs
  2. 39 28
      deps/db/test/logseq/db/sqlite/export_test.cljs

+ 21 - 16
deps/db/src/logseq/db/sqlite/export.cljs

@@ -847,21 +847,24 @@
 ;; Import fns
 ;; ==========
 (defn- add-uuid-to-page-if-exists
-  [db import-to-existing-page-uuids m]
-  (if-let [ent (some->> (:build/journal m)
-                        (d/datoms db :avet :block/journal-day)
-                        first
-                        :e
-                        (d/entity db))]
+  [db import-to-existing-page-uuids {:keys [existing-pages-keep-properties?]} m]
+  (if-let [ent (if (:build/journal m)
+                 (some->> (:build/journal m)
+                          (d/datoms db :avet :block/journal-day)
+                          first
+                          :e
+                          (d/entity db))
+                 ;; TODO: For now only check page uniqueness by title. Could handle more uniqueness checks later
+                 (some->> (:block/title m) (ldb/get-case-page db)))]
     (do
       (swap! import-to-existing-page-uuids assoc (:block/uuid m) (:block/uuid ent))
-      (assoc m :block/uuid (:block/uuid ent)))
-    ;; TODO: For now only check page uniqueness by title. Could handle more uniqueness checks later
-    (if-let [ent (some->> (:block/title m) (ldb/get-case-page db))]
-      (do
-        (swap! import-to-existing-page-uuids assoc (:block/uuid m) (:block/uuid ent))
-        (assoc m :block/uuid (:block/uuid ent)))
-      m)))
+      (cond-> (assoc m :block/uuid (:block/uuid ent))
+        (and (:build/properties m) existing-pages-keep-properties?)
+        (update :build/properties (fn [props]
+                                    (->> props
+                                         (remove (fn [[k _v]] (get ent k)))
+                                         (into {}))))))
+    m))
 
 (defn- update-existing-properties
   "Updates existing properties by ident. Also check imported and existing properties have
@@ -884,7 +887,7 @@
 (defn- check-for-existing-entities
   "Checks export map for existing entities and adds :block/uuid to them if they exist in graph to import.
    Also checks for property conflicts between existing properties and properties to be imported"
-  [db {:keys [pages-and-blocks classes properties] ::keys [export-type] :as export-map} property-conflicts]
+  [db {:keys [pages-and-blocks classes properties] ::keys [export-type import-options] :as export-map} property-conflicts]
   (let [import-to-existing-page-uuids (atom {})
         export-map
         (cond-> {:build-existing-tx? true
@@ -892,7 +895,7 @@
           (seq pages-and-blocks)
           (assoc :pages-and-blocks
                  (mapv (fn [m]
-                         (update m :page (partial add-uuid-to-page-if-exists db import-to-existing-page-uuids)))
+                         (update m :page (partial add-uuid-to-page-if-exists db import-to-existing-page-uuids import-options)))
                        pages-and-blocks))
           (seq classes)
           (assoc :classes
@@ -915,7 +918,7 @@
                       (walk/postwalk (fn [f]
                                        (if (and (vector? f) (= :build/page (first f)))
                                          [:build/page
-                                          (add-uuid-to-page-if-exists db import-to-existing-page-uuids (second f))]
+                                          (add-uuid-to-page-if-exists db import-to-existing-page-uuids import-options (second f))]
                                          f))
                                      export-map))
         ;; Update uuid references of all pages that had their uuids updated to reference an existing page
@@ -948,6 +951,8 @@
    * ::kv-values - Vec of :kv/value maps for a :graph export
    * ::auto-include-namespaces - A set of parent namespaces to include from properties and classes
      for a :graph export. See :exclude-namespaces in build-graph-export for a similar option
+   * ::import-options - A map of options that alters importing behavior. Has the following keys:
+     * :existing-pages-keep-properties? - Boolean which disables upsert of :build/properties on
 
    This fn then returns a map of txs to transact with the following keys:
    * :init-tx - Txs that must be transacted first, usually because they define new properties

+ 39 - 28
deps/db/test/logseq/db/sqlite/export_test.cljs

@@ -826,54 +826,65 @@
            (-> (:classes imported-graph)
                (medley/dissoc-in [:user.property/p1 :build/properties]))))))
 
-(deftest build-import-can-import-existing-page-with-different-uuid
+(defn- test-import-existing-page [import-options expected-page-properties]
   (let [original-data
         {:properties {:user.property/node {:logseq.property/type :node
                                            :db/cardinality :db.cardinality/many}}
          :pages-and-blocks
          [{:page {:block/title "page1"
-                  :build/properties {:user.property/node #{[:build/page {:block/title "node1"}]}}}}]}
+                  :build/properties {:user.property/node
+                                     #{[:build/page {:block/title "existing page"
+                                                     :build/properties {:logseq.property/description "first description"}}]}}}}]}
         conn (db-test/create-conn-with-blocks original-data)
-        page-uuid (:block/uuid (db-test/find-page-by-title @conn "node1"))
+        page-uuid (:block/uuid (db-test/find-page-by-title @conn "existing page"))
         _ (validate-db @conn)
         ;; This is just a temp uuid used to link to the page during import
         temp-uuid (random-uuid)
-        existing-data
+        import-data
         {:properties {:user.property/node {:logseq.property/type :node
                                            :db/cardinality :db.cardinality/many}}
          :pages-and-blocks
-         [{:page {:block/title "node1"
+         [{:page {:block/title "existing page"
                   :block/uuid temp-uuid
-                  :build/keep-uuid? true}}
+                  :build/keep-uuid? true
+                  :build/properties {:logseq.property/description "second description"
+                                     :logseq.property/exclude-from-graph-view true}}}
           {:page {:block/title "page2"
-                  :build/properties {:user.property/node #{[:block/uuid temp-uuid]}}}}]}
+                  :build/properties {:user.property/node #{[:block/uuid temp-uuid]}}}}]
+         ::sqlite-export/import-options import-options}
         {:keys [init-tx block-props-tx] :as _txs}
-        (sqlite-export/build-import existing-data @conn {})
+        (sqlite-export/build-import import-data @conn {})
         ;; _ (cljs.pprint/pprint _txs)
         _ (d/transact! conn init-tx)
         _ (d/transact! conn block-props-tx)
         _ (validate-db @conn)
         expected-pages-and-blocks
-        [{:page
-          {:block/uuid page-uuid
-           :build/keep-uuid? true,
-           :block/title "node1"},
-          :blocks []}
-         {:page
-          {:build/properties
-           {:user.property/node
-            #{[:block/uuid page-uuid]}},
-           :block/title "page1"},
-          :blocks []}
-         {:page
-          {:build/properties
-           {:user.property/node
-            #{[:block/uuid page-uuid]}},
-           :block/title "page2"},
-          :blocks []}],
+        [{:block/uuid page-uuid
+          :build/keep-uuid? true,
+          :block/title "existing page"
+          :build/properties
+          expected-page-properties}
+         {:build/properties
+          {:user.property/node
+           #{[:block/uuid page-uuid]}},
+          :block/title "page1"}
+         {:build/properties
+          {:user.property/node
+           #{[:block/uuid page-uuid]}},
+          :block/title "page2"}]
         exported-graph (sqlite-export/build-export @conn {:export-type :graph
                                                           :graph-options {:exclude-built-in-pages? true}})]
     (is (= expected-pages-and-blocks
-           (:pages-and-blocks exported-graph))
-        "page uuid ('node1') is preserved across imports even when its assigned a temporary
-         uuid to relate it to other nodes")))
+           (map :page (:pages-and-blocks exported-graph)))
+        "page uuid of 'existing page' is preserved across imports even when its assigned a temporary
+         uuid to relate it to other nodes")))
+
+(deftest build-import-can-import-existing-page-with-different-uuid
+  (testing "By default any properties passed to an existing page are upserted"
+    (test-import-existing-page {}
+                              {:logseq.property/description "second description"
+                               :logseq.property/exclude-from-graph-view true}))
+  (testing "With ::existing-pages-keep-properties?, existing properties on existing pages are not overwritten by imported data"
+    (test-import-existing-page {:existing-pages-keep-properties? true}
+                               {:logseq.property/description "first description"
+                                :logseq.property/exclude-from-graph-view true})))