Răsfoiți Sursa

fix: exporting class parent or property class

could sometimes lead to failure. Address by shallow copying
as page export should not be recursively exporting properties and
classes that are not visible on a page
Gabriel Horner 8 luni în urmă
părinte
comite
4f25e27d9b

+ 23 - 11
deps/db/src/logseq/db/sqlite/export.cljs

@@ -74,7 +74,7 @@
        (into {})))
        (into {})))
 
 
 (defn- build-export-properties
 (defn- build-export-properties
-  [db user-property-idents {:keys [include-properties? include-uuid?]}]
+  [db user-property-idents {:keys [include-properties? include-uuid? shallow-copy?]}]
   (let [properties-config-by-ent
   (let [properties-config-by-ent
         (->> user-property-idents
         (->> user-property-idents
              (map (fn [ident]
              (map (fn [ident]
@@ -86,7 +86,7 @@
                                                 (conj :block/title)))
                                                 (conj :block/title)))
                          include-uuid?
                          include-uuid?
                          (assoc :block/uuid (:block/uuid property))
                          (assoc :block/uuid (:block/uuid property))
-                         (:logseq.property/classes property)
+                         (and (not shallow-copy?) (:logseq.property/classes property))
                          (assoc :build/property-classes (mapv :db/ident (:logseq.property/classes property)))
                          (assoc :build/property-classes (mapv :db/ident (:logseq.property/classes property)))
                          (seq closed-values)
                          (seq closed-values)
                          (assoc :build/closed-values
                          (assoc :build/closed-values
@@ -111,22 +111,24 @@
       properties-config)))
       properties-config)))
 
 
 (defn- build-export-class
 (defn- build-export-class
-  [class-ent {:keys [include-parents? include-uuid?] :or {include-parents? true}}]
+  [class-ent {:keys [include-parents? include-uuid? shallow-copy?]
+              :or {include-parents? true}}]
   (cond-> (select-keys class-ent [:block/title])
   (cond-> (select-keys class-ent [:block/title])
     include-uuid?
     include-uuid?
     (assoc :block/uuid (:block/uuid class-ent))
     (assoc :block/uuid (:block/uuid class-ent))
-    (:logseq.property.class/properties class-ent)
+    (and (:logseq.property.class/properties class-ent) (not shallow-copy?))
     (assoc :build/class-properties
     (assoc :build/class-properties
            (mapv :db/ident (:logseq.property.class/properties class-ent)))
            (mapv :db/ident (:logseq.property.class/properties class-ent)))
     ;; It's caller's responsibility to ensure parent is included in final export
     ;; It's caller's responsibility to ensure parent is included in final export
     (and include-parents?
     (and include-parents?
+         (not shallow-copy?)
          (:logseq.property/parent class-ent)
          (:logseq.property/parent class-ent)
          (not= :logseq.class/Root (:db/ident (:logseq.property/parent class-ent))))
          (not= :logseq.class/Root (:db/ident (:logseq.property/parent class-ent))))
     (assoc :build/class-parent
     (assoc :build/class-parent
            (:db/ident (:logseq.property/parent class-ent)))))
            (:db/ident (:logseq.property/parent class-ent)))))
 
 
 (defn- build-node-classes
 (defn- build-node-classes
-  [db build-block block-tags]
+  [db build-block block-tags properties]
   (let [pvalue-class-ents (->> (:build/properties build-block)
   (let [pvalue-class-ents (->> (:build/properties build-block)
                                vals
                                vals
                                (mapcat (fn [val-or-vals]
                                (mapcat (fn [val-or-vals]
@@ -134,11 +136,21 @@
                                                  (if (set? val-or-vals) val-or-vals [val-or-vals]))))
                                                  (if (set? val-or-vals) val-or-vals [val-or-vals]))))
                                (remove db-class/logseq-class?)
                                (remove db-class/logseq-class?)
                                (map #(d/entity db %)))
                                (map #(d/entity db %)))
+        property-classes (->> (mapcat :build/property-classes (vals properties))
+                              (remove db-class/logseq-class?)
+                              set)
         new-class-ents (concat (remove #(db-class/logseq-class? (:db/ident %)) block-tags)
         new-class-ents (concat (remove #(db-class/logseq-class? (:db/ident %)) block-tags)
-                               pvalue-class-ents)]
-    (->> new-class-ents
-         (map #(vector (:db/ident %) (build-export-class % {})))
-         (into {}))))
+                               pvalue-class-ents)
+        shallow-classes (set/difference property-classes (set (map :db/ident new-class-ents)))]
+    (merge
+     (when (seq shallow-classes)
+       (->> shallow-classes
+            (map #(d/entity db %))
+            (map #(vector (:db/ident %) (build-export-class % {:shallow-copy? true})))
+            (into {})))
+     (->> new-class-ents
+          (map #(vector (:db/ident %) (build-export-class % {})))
+          (into {})))))
 
 
 (defn- build-node-export
 (defn- build-node-export
   "Given a block/page entity and optional existing properties, build an export map of its
   "Given a block/page entity and optional existing properties, build an export map of its
@@ -165,7 +177,7 @@
                      (seq ent-properties)
                      (seq ent-properties)
                      (assoc :build/properties
                      (assoc :build/properties
                             (buildable-properties db ent-properties (merge properties new-properties))))
                             (buildable-properties db ent-properties (merge properties new-properties))))
-        new-classes (build-node-classes db build-node (:block/tags entity))]
+        new-classes (build-node-classes db build-node (:block/tags entity) new-properties)]
     (cond-> {:node build-node}
     (cond-> {:node build-node}
       (seq new-classes)
       (seq new-classes)
       (assoc :classes new-classes)
       (assoc :classes new-classes)
@@ -234,7 +246,7 @@
              (mapcat :logseq.property.class/properties)
              (mapcat :logseq.property.class/properties)
              (map :db/ident)
              (map :db/ident)
              (remove db-property/logseq-property?))
              (remove db-property/logseq-property?))
-        properties (build-export-properties db class-parent-properties {})]
+        properties (build-export-properties db class-parent-properties {:shallow-copy? true})]
     {:classes classes
     {:classes classes
      :properties properties}))
      :properties properties}))
 
 

+ 27 - 11
deps/db/test/logseq/db/sqlite/export_test.cljs

@@ -6,7 +6,8 @@
             [logseq.common.util.page-ref :as page-ref]
             [logseq.common.util.page-ref :as page-ref]
             [logseq.db.frontend.validate :as db-validate]
             [logseq.db.frontend.validate :as db-validate]
             [logseq.db.sqlite.export :as sqlite-export]
             [logseq.db.sqlite.export :as sqlite-export]
-            [logseq.db.test.helper :as db-test]))
+            [logseq.db.test.helper :as db-test]
+            [logseq.common.util :as common-util]))
 
 
 (defn- export-block-and-import-to-another-block
 (defn- export-block-and-import-to-another-block
   "Exports given block from one graph/conn, imports it to a 2nd block and then
   "Exports given block from one graph/conn, imports it to a 2nd block and then
@@ -53,7 +54,7 @@
                  (assoc :block/title (name k)))]))
                  (assoc :block/title (name k)))]))
        (into {})))
        (into {})))
 
 
-(deftest ^:focus import-block-in-same-graph
+(deftest import-block-in-same-graph
   (let [original-data
   (let [original-data
         {:properties {:user.property/default-many {:logseq.property/type :default :db/cardinality :db.cardinality/many}}
         {:properties {:user.property/default-many {:logseq.property/type :default :db/cardinality :db.cardinality/many}}
          :classes {:user.class/MyClass
          :classes {:user.class/MyClass
@@ -73,7 +74,7 @@
     (is (= (expand-properties (:properties original-data)) (:properties imported-block)))
     (is (= (expand-properties (:properties original-data)) (:properties imported-block)))
     (is (= (expand-classes (:classes original-data)) (:classes imported-block)))))
     (is (= (expand-classes (:classes original-data)) (:classes imported-block)))))
 
 
-(deftest ^:focus2 import-block-in-different-graph
+(deftest import-block-in-different-graph
   (let [original-data
   (let [original-data
         {:properties {:user.property/num-many
         {:properties {:user.property/num-many
                       {:logseq.property/type :number
                       {:logseq.property/type :number
@@ -238,13 +239,20 @@
 (deftest import-page-with-different-page-and-classes
 (deftest import-page-with-different-page-and-classes
   (let [original-data
   (let [original-data
         {:properties {:user.property/p1 {:logseq.property/type :default}
         {:properties {:user.property/p1 {:logseq.property/type :default}
-                      :user.property/p2 {:logseq.property/type :default}
-                      :user.property/p3 {:logseq.property/type :default}}
+                      ;; shallow property b/c it's a property for a class' parent
+                      :user.property/p2 {:logseq.property/type :node
+                                         :build/property-classes [:user.class/NodeClass2]}
+                      :user.property/p3 {:logseq.property/type :node
+                                         :build/property-classes [:user.class/NodeClass]}
+                      :user.property/node-p1 {:logseq.property/type :default}}
          :classes {:user.class/MyClass {:build/class-properties [:user.property/p1 :user.property/p2]}
          :classes {:user.class/MyClass {:build/class-properties [:user.property/p1 :user.property/p2]}
-                   :user.class/MyClass2 {}
+                   :user.class/MyClass2 {:build/class-properties [:user.property/p2]}
                    :user.class/ChildClass {:build/class-parent :user.class/MyClass
                    :user.class/ChildClass {:build/class-parent :user.class/MyClass
                                            :build/class-properties [:user.property/p3]}
                                            :build/class-properties [:user.property/p3]}
-                   :user.class/ChildClass2 {:build/class-parent :user.class/MyClass2}}
+                   :user.class/ChildClass2 {:build/class-parent :user.class/MyClass2}
+                   ;; shallow class b/c it's a property's class property
+                   :user.class/NodeClass {:build/class-properties [:user.property/node-p1]}
+                   :user.class/NodeClass2 {}}
          :pages-and-blocks
          :pages-and-blocks
          [{:page {:block/title "page1"
          [{:page {:block/title "page1"
                   :build/properties {:user.property/p1 "woot"}
                   :build/properties {:user.property/p1 "woot"}
@@ -255,10 +263,18 @@
         conn2 (db-test/create-conn)
         conn2 (db-test/create-conn)
         imported-page (export-page-and-import-to-another-graph conn conn2 "page1")]
         imported-page (export-page-and-import-to-another-graph conn conn2 "page1")]
 
 
-    (is (= (expand-properties (:properties original-data)) (:properties imported-page))
-        "Page's properties are imported")
-    (is (= (expand-classes (:classes original-data)) (:classes imported-page))
-        "Page's classes are imported")
+    (is (= (-> (expand-properties (:properties original-data))
+               (dissoc :user.property/node-p1)
+               ;; Shallow property doesn't have class
+               (common-util/dissoc-in [:user.property/p2 :build/property-classes]))
+           (:properties imported-page))
+        "Page's properties are imported except for shallow class' property")
+    (is (= (-> (expand-classes (:classes original-data))
+               ;; Shallow class doesn't have properties
+               (common-util/dissoc-in [:user.class/NodeClass :build/class-properties])
+               (dissoc :user.class/NodeClass2))
+           (:classes imported-page))
+        "Page's classes are imported except for shallow property's class")
     (is (= (:pages-and-blocks original-data) (:pages-and-blocks imported-page))
     (is (= (:pages-and-blocks original-data) (:pages-and-blocks imported-page))
         "Page's blocks are imported")
         "Page's blocks are imported")