Browse Source

enhance: add export+import of selected nodes

Fixes https://github.com/logseq/db-test/issues/232
Gabriel Horner 6 months ago
parent
commit
ffca9c862f

+ 30 - 7
deps/db/src/logseq/db/sqlite/export.cljs

@@ -470,7 +470,9 @@
         page-export (finalize-export-maps db page-export* uuid-block-export content-ref-export)]
     page-export))
 
-(defn build-view-nodes-export* [db nodes opts]
+(defn- build-nodes-export
+  "Export a mix of pages and blocks"
+  [db nodes opts]
   (let [node-pages (filter entity-util/page? nodes)
         pages-export
         (merge
@@ -483,9 +485,7 @@
         (->> node-blocks
              (group-by :block/page)
              (map (fn [[parent-page-ent blocks]]
-                    (merge (build-blocks-export db
-                                                (sort-by :block/order blocks)
-                                                (merge opts {:include-children? false}))
+                    (merge (build-blocks-export db (sort-by :block/order blocks) opts)
                            {:page (shallow-copy-page parent-page-ent)}))))
         pages-to-blocks-export
         {:properties (apply merge (map :properties pages-to-blocks))
@@ -505,7 +505,29 @@
         {:keys [content-ref-uuids content-ref-ents] :as content-ref-export}
         (build-content-ref-export db (into nodes property-value-ents))
         {:keys [pvalue-uuids] :as nodes-export}
-        (build-view-nodes-export* db nodes {:include-uuid-fn content-ref-uuids})
+        (build-nodes-export db nodes {:include-uuid-fn content-ref-uuids :include-children? false})
+        uuid-block-export (build-uuid-block-export db pvalue-uuids content-ref-ents {})
+        view-nodes-export (finalize-export-maps db nodes-export uuid-block-export content-ref-export)]
+    view-nodes-export))
+
+(defn- build-selected-nodes-export
+  "Exports given nodes selected by a user. Nodes can be a mix of blocks and pages"
+  [db eids]
+  (let [top-level-nodes (map #(d/entity db %) eids)
+        children-nodes (->> top-level-nodes
+                            ;; Remove pages b/c when selected their children are not highlighted
+                            (remove entity-util/page?)
+                            (mapcat #(rest (ldb/get-block-and-children db (:block/uuid %))))
+                            (remove :logseq.property/created-from-property))
+        nodes (concat top-level-nodes children-nodes)
+        property-value-ents (mapcat #(->> (apply dissoc (db-property/properties %) db-property/public-db-attribute-properties)
+                                          vals
+                                          (filter de/entity?))
+                                    nodes)
+        {:keys [content-ref-uuids content-ref-ents] :as content-ref-export}
+        (build-content-ref-export db (into nodes property-value-ents))
+        {:keys [pvalue-uuids] :as nodes-export}
+        (build-nodes-export db nodes {:include-uuid-fn content-ref-uuids :include-children? true})
         uuid-block-export (build-uuid-block-export db pvalue-uuids content-ref-ents {})
         view-nodes-export (finalize-export-maps db nodes-export uuid-block-export content-ref-export)]
     view-nodes-export))
@@ -769,9 +791,10 @@
           (build-block-export db (:block-id options))
           :page
           (build-page-export db (:page-id options))
-          ;; Different export types for different features as their needs may diverge
-          (:view-nodes :selected-nodes)
+          :view-nodes
           (build-view-nodes-export db (:node-ids options))
+          :selected-nodes
+          (build-selected-nodes-export db (:node-ids options))
           :graph-ontology
           (build-graph-ontology-export db {})
           :graph

+ 37 - 0
deps/db/test/logseq/db/sqlite/export_test.cljs

@@ -531,6 +531,43 @@
     (is (= (expand-properties (:properties original-data)) (:properties imported-nodes)))
     (is (= (expand-classes (:classes original-data)) (:classes imported-nodes)))))
 
+(deftest import-selected-nodes
+  (let [original-data
+        ;; Test a mix of pages and blocks
+        {:properties {:user.property/p1 {:logseq.property/type :default}}
+         :classes {:user.class/class1 {}}
+         :pages-and-blocks [{:page {:block/title "page1"}
+                             :blocks [{:block/title "b1"
+                                       :build/properties {:user.property/p1 "ok"}
+                                       :build/children [{:block/title "b2"}]}
+                                      {:block/title "b3"
+                                       :build/tags [:user.class/class1]
+                                       :build/children [{:block/title "b4"}]}]}
+                            {:page {:block/title "page2"}
+                             :blocks [{:block/title "dont export"}]}]}
+        conn (db-test/create-conn-with-blocks original-data)
+        get-node-ids (fn [db]
+                       (->> [(db-test/find-block-by-content db "b1")
+                             (db-test/find-page-by-title db "b3")
+                             (db-test/find-page-by-title db "page2")]
+                            (remove nil?)
+                            (mapv #(vector :block/uuid (:block/uuid %)))))
+        conn2 (db-test/create-conn)
+        {:keys [init-tx block-props-tx] :as _txs}
+        (-> (sqlite-export/build-export @conn {:export-type :selected-nodes :node-ids (get-node-ids @conn)})
+            (sqlite-export/build-import @conn2 {}))
+        ;; _ (cljs.pprint/pprint _txs)
+        _ (d/transact! conn2 init-tx)
+        _ (d/transact! conn2 block-props-tx)
+        _ (validate-db @conn2)
+        imported-nodes (sqlite-export/build-export @conn2 {:export-type :selected-nodes :node-ids (get-node-ids @conn2)})]
+
+    (is (= (set (->> (:pages-and-blocks original-data)
+                     (map #(if (= (get-in % [:page :block/title]) "page2") (dissoc % :blocks) %))))
+           (set (:pages-and-blocks imported-nodes))))
+    (is (= (expand-properties (:properties original-data)) (:properties imported-nodes)))
+    (is (= (expand-classes (:classes original-data)) (:classes imported-nodes)))))
+
 (defn- build-original-graph-data
   [& {:keys [exclude-namespaces?]}]
   (let [internal-block-uuid (random-uuid)