From fcdfe518bea6f412839048197e99fc0b6b07d94c Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Fri, 7 Feb 2025 10:27:28 -0500 Subject: [PATCH] enhance: export+export refs to classes --- deps/db/src/logseq/db/sqlite/export.cljs | 87 ++++++++++++------- .../db/test/logseq/db/sqlite/export_test.cljs | 8 +- 2 files changed, 60 insertions(+), 35 deletions(-) diff --git a/deps/db/src/logseq/db/sqlite/export.cljs b/deps/db/src/logseq/db/sqlite/export.cljs index 45f32ce826..d027fa46ca 100644 --- a/deps/db/src/logseq/db/sqlite/export.cljs +++ b/deps/db/src/logseq/db/sqlite/export.cljs @@ -94,8 +94,10 @@ properties-config))) (defn- build-export-class - [class-ent {:keys [include-parents?]}] + [class-ent {:keys [include-parents? include-uuid?]}] (cond-> (select-keys class-ent [:block/title]) + include-uuid? + (assoc :block/uuid (:block/uuid class-ent)) (:logseq.property.class/properties class-ent) (assoc :build/class-properties (mapv :db/ident (:logseq.property.class/properties class-ent))) @@ -196,19 +198,46 @@ :classes @*classes :pvalue-uuids @*pvalue-uuids})) -(defn- get-uuid-block-pages [db pvalue-uuids content-ref-ents page-entity] +(defn- build-uuid-block-export [db pvalue-uuids content-ref-ents page-entity] (let [uuid-block-ents-to-export (concat (map #(d/entity db [:block/uuid %]) pvalue-uuids) - (remove ldb/page? content-ref-ents))] - (when (seq uuid-block-ents-to-export) - (->> uuid-block-ents-to-export - (group-by :block/parent) - (map (fn [[parent-page-ent blocks]] - ;; Not a common case but can support later if needed - (when (= parent-page-ent page-entity) - (throw (ex-info "Can't export a uuid block from exported page" {}))) - ;; Don't export pvalue-uuids of pvalue blocks as it's too excessive for now - (merge (build-blocks-tree db (sort-by :block/order blocks) {:include-uuid-fn (constantly true)}) - {:page (select-keys parent-page-ent [:block/title])}))))))) + (remove ldb/page? content-ref-ents)) + uuid-block-pages + (when (seq uuid-block-ents-to-export) + (->> uuid-block-ents-to-export + (group-by :block/parent) + ;; Remove page-entity because it's already been built for content-ref-ents + ;; and it's unlikely and complex to handle for pvalue-uuids + ((fn [m] (dissoc m page-entity))) + (map (fn [[parent-page-ent blocks]] + ;; Don't export pvalue-uuids of uuid blocks to keep export shallower + (merge (build-blocks-tree db (sort-by :block/order blocks) {:include-uuid-fn (constantly true)}) + ;; only shallow copy pages + {:page (select-keys parent-page-ent [:block/title])})))))] + {:properties (apply merge (map :properties uuid-block-pages)) + :classes (apply merge (map :classes uuid-block-pages)) + :pages-and-blocks (mapv #(select-keys % [:page :blocks]) uuid-block-pages)})) + +(defn- build-content-ref-export + [db page-blocks] + (let [content-ref-uuids (set (mapcat (comp db-content/get-matched-ids :block/title) page-blocks)) + content-ref-ents (map #(d/entity db [:block/uuid %]) content-ref-uuids) + content-ref-pages (filter ldb/internal-page? content-ref-ents) + content-ref-properties (when-let [prop-ids (seq (map :db/ident (filter ldb/property? content-ref-ents)))] + (update-vals (build-export-properties db prop-ids {:include-uuid? true}) + #(merge % {:build/new-property? true}))) + content-ref-classes (when-let [class-ents (seq (filter ldb/class? content-ref-ents))] + (->> class-ents + ;; TODO: Export class parents when there's ability to control granularity of export + (map #(vector (:db/ident %) + (assoc (build-export-class % {:include-parents? false :include-uuid? true}) + :build/new-class? true))) + (into {})))] + {:content-ref-uuids content-ref-uuids + :content-ref-ents content-ref-ents + :properties content-ref-properties + :classes content-ref-classes + ;; only shallow copy pages + :pages-and-blocks (mapv #(hash-map :page (select-keys % [:block/title :block/uuid])) content-ref-pages)})) (defn build-page-export [db eid] (let [page-entity (d/entity db eid) @@ -220,16 +249,10 @@ (sort-by :block/order) ;; Remove property value blocks as they are included in the block they belong to (remove #(:logseq.property/created-from-property %))) - content-ref-uuids (set (mapcat (comp db-content/get-matched-ids :block/title) page-blocks)) - content-ref-ents (map #(d/entity db [:block/uuid %]) content-ref-uuids) - content-ref-pages (filter ldb/internal-page? content-ref-ents) - content-ref-properties* (map :db/ident (filter ldb/property? content-ref-ents)) - content-ref-properties (when content-ref-properties* - (update-vals (build-export-properties db content-ref-properties* {:include-uuid? true}) - #(merge % {:build/new-property? true}))) + {:keys [content-ref-uuids content-ref-ents] :as content-ref-export} (build-content-ref-export db page-blocks) {:keys [blocks properties classes pvalue-uuids]} (build-blocks-tree db page-blocks {:include-uuid-fn content-ref-uuids}) - uuid-block-pages (get-uuid-block-pages db pvalue-uuids content-ref-ents page-entity) + uuid-block-export (build-uuid-block-export db pvalue-uuids content-ref-ents page-entity) page-ent-export (build-entity-export db page-entity {:properties properties}) page (merge (dissoc (:build/block page-ent-export) :block/title) (if (ldb/journal? page-entity) @@ -237,17 +260,19 @@ (select-keys page-entity [:block/title]))) pages-and-blocks (cond-> [{:page page :blocks blocks}] - ;; pages from uuid blocks or content-ref-pages are shallow copies e.g. only :block/title - (seq uuid-block-pages) - (into (map #(select-keys % [:page :blocks]) uuid-block-pages)) - (seq content-ref-pages) - (into (map #(hash-map :page (select-keys % [:block/title :block/uuid])) content-ref-pages))) + (seq (:pages-and-blocks uuid-block-export)) + (into (:pages-and-blocks uuid-block-export)) + (seq (:pages-and-blocks content-ref-export)) + (into (:pages-and-blocks content-ref-export))) ;; Use merge-with to preserve new-property? - properties' (apply merge-with merge properties - (:properties page-ent-export) - content-ref-properties - (map :properties uuid-block-pages)) - classes' (apply merge classes (:classes page-ent-export) (map :classes uuid-block-pages)) + properties' (merge-with merge properties + (:properties page-ent-export) + (:properties content-ref-export) + (:properties uuid-block-export)) + classes' (merge-with merge classes + (:classes page-ent-export) + (:classes content-ref-export) + (:classes uuid-block-export)) page-export (cond-> {:pages-and-blocks pages-and-blocks} (seq properties') diff --git a/deps/db/test/logseq/db/sqlite/export_test.cljs b/deps/db/test/logseq/db/sqlite/export_test.cljs index 6911a1ae2b..aa5753559a 100644 --- a/deps/db/test/logseq/db/sqlite/export_test.cljs +++ b/deps/db/test/logseq/db/sqlite/export_test.cljs @@ -164,11 +164,11 @@ (deftest import-page-with-different-ref-types (let [block-uuid (random-uuid) - ;; class-uuid (random-uuid) + class-uuid (random-uuid) page-uuid (random-uuid) property-uuid (random-uuid) original-data - {;:classes {:C1 {:block/uuid class-uuid}} + {:classes {:user.class/C1 {:block/title "C1" :block/uuid class-uuid :build/new-class? true}} :properties {:user.property/p1 {:db/cardinality :db.cardinality/one, :logseq.property/type :default :block/uuid property-uuid :block/title "p1" :build/new-property? true}} @@ -176,8 +176,8 @@ [{:page {:block/title "page1"} :blocks [{:block/title (str "page ref to " (page-ref/->page-ref page-uuid))} {:block/title (str "block ref to " (page-ref/->page-ref block-uuid))} - #_{:block/title (str "class ref to " (page-ref/->page-ref class-uuid))} - #_{:block/title (str "inline class ref to #" (page-ref/->page-ref class-uuid))} + {:block/title (str "class ref to " (page-ref/->page-ref class-uuid))} + {:block/title (str "inline class ref to #" (page-ref/->page-ref class-uuid))} {:block/title (str "property ref to " (page-ref/->page-ref property-uuid))}]} {:page {:block/title "page with block ref"} :blocks [{:block/title "hi" :block/uuid block-uuid}]}