Quellcode durchsuchen

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

Gabriel Horner vor 8 Monaten
Ursprung
Commit
bd115eef0f
2 geänderte Dateien mit 60 neuen und 44 gelöschten Zeilen
  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
 ;; Import fns
 ;; ==========
 ;; ==========
 (defn- add-uuid-to-page-if-exists
 (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
     (do
       (swap! import-to-existing-page-uuids assoc (:block/uuid m) (:block/uuid ent))
       (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
 (defn- update-existing-properties
   "Updates existing properties by ident. Also check imported and existing properties have
   "Updates existing properties by ident. Also check imported and existing properties have
@@ -884,7 +887,7 @@
 (defn- check-for-existing-entities
 (defn- check-for-existing-entities
   "Checks export map for existing entities and adds :block/uuid to them if they exist in graph to import.
   "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"
    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 {})
   (let [import-to-existing-page-uuids (atom {})
         export-map
         export-map
         (cond-> {:build-existing-tx? true
         (cond-> {:build-existing-tx? true
@@ -892,7 +895,7 @@
           (seq pages-and-blocks)
           (seq pages-and-blocks)
           (assoc :pages-and-blocks
           (assoc :pages-and-blocks
                  (mapv (fn [m]
                  (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))
                        pages-and-blocks))
           (seq classes)
           (seq classes)
           (assoc :classes
           (assoc :classes
@@ -915,7 +918,7 @@
                       (walk/postwalk (fn [f]
                       (walk/postwalk (fn [f]
                                        (if (and (vector? f) (= :build/page (first f)))
                                        (if (and (vector? f) (= :build/page (first f)))
                                          [:build/page
                                          [: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))
                                          f))
                                      export-map))
                                      export-map))
         ;; Update uuid references of all pages that had their uuids updated to reference an existing page
         ;; 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
    * ::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
    * ::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
      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:
    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
    * :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)
            (-> (:classes imported-graph)
                (medley/dissoc-in [:user.property/p1 :build/properties]))))))
                (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
   (let [original-data
         {:properties {:user.property/node {:logseq.property/type :node
         {:properties {:user.property/node {:logseq.property/type :node
                                            :db/cardinality :db.cardinality/many}}
                                            :db/cardinality :db.cardinality/many}}
          :pages-and-blocks
          :pages-and-blocks
          [{:page {:block/title "page1"
          [{: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)
         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)
         _ (validate-db @conn)
         ;; This is just a temp uuid used to link to the page during import
         ;; This is just a temp uuid used to link to the page during import
         temp-uuid (random-uuid)
         temp-uuid (random-uuid)
-        existing-data
+        import-data
         {:properties {:user.property/node {:logseq.property/type :node
         {:properties {:user.property/node {:logseq.property/type :node
                                            :db/cardinality :db.cardinality/many}}
                                            :db/cardinality :db.cardinality/many}}
          :pages-and-blocks
          :pages-and-blocks
-         [{:page {:block/title "node1"
+         [{:page {:block/title "existing page"
                   :block/uuid temp-uuid
                   :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"
           {: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}
         {: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)
         ;; _ (cljs.pprint/pprint _txs)
         _ (d/transact! conn init-tx)
         _ (d/transact! conn init-tx)
         _ (d/transact! conn block-props-tx)
         _ (d/transact! conn block-props-tx)
         _ (validate-db @conn)
         _ (validate-db @conn)
         expected-pages-and-blocks
         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
         exported-graph (sqlite-export/build-export @conn {:export-type :graph
                                                           :graph-options {:exclude-built-in-pages? true}})]
                                                           :graph-options {:exclude-built-in-pages? true}})]
     (is (= expected-pages-and-blocks
     (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})))