From 02f893f66bccd27205166da4a0eb12e62dcdd8db Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Fri, 31 Jan 2025 09:01:05 -0500 Subject: [PATCH] enhance: better error handling when importing data Gracefully handle invalid EDN and property conflicts --- deps/db/src/logseq/db/sqlite/export.cljs | 19 +++++++++++-- .../frontend/handler/common/developer.cljs | 28 +++++++++++-------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/deps/db/src/logseq/db/sqlite/export.cljs b/deps/db/src/logseq/db/sqlite/export.cljs index a5893c8050..7b4053e850 100644 --- a/deps/db/src/logseq/db/sqlite/export.cljs +++ b/deps/db/src/logseq/db/sqlite/export.cljs @@ -78,7 +78,8 @@ (defn build-entity-import "Given an entity's export map, build the import tx to create it" [db {:build/keys [block] :keys [properties classes]}] - (let [opts (cond-> {:pages-and-blocks [{:page (select-keys (:block/page block) [:block/uuid]) + (let [property-conflicts (atom []) + opts (cond-> {:pages-and-blocks [{:page (select-keys (:block/page block) [:block/uuid]) :blocks [(dissoc block :block/page)]}] :build-existing-tx? true} (seq classes) @@ -94,10 +95,22 @@ (->> properties (map (fn [[k v]] (if-let [ent (d/entity db k)] - [k (assoc v :block/uuid (:block/uuid ent))] + (do + (when (not= (select-keys ent [:logseq.property/type :db/cardinality]) + (select-keys v [:logseq.property/type :db/cardinality])) + (swap! property-conflicts conj + {:property-id k + :actual (select-keys v [:logseq.property/type :db/cardinality]) + :expected (select-keys ent [:logseq.property/type :db/cardinality])})) + [k (assoc v :block/uuid (:block/uuid ent))]) [k v]))) (into {}))))] - (sqlite-build/build-blocks-tx opts))) + (if (seq @property-conflicts) + (do + (js/console.error :property-conflicts @property-conflicts) + {:error (str "The following imported properties conflict with the current graph: " + (pr-str (mapv :property-id @property-conflicts)))}) + (sqlite-build/build-blocks-tx opts)))) (defn merge-export-map "Merges export map with the block that will receive the import" diff --git a/src/main/frontend/handler/common/developer.cljs b/src/main/frontend/handler/common/developer.cljs index 9a5de92a56..c407d20b9e 100644 --- a/src/main/frontend/handler/common/developer.cljs +++ b/src/main/frontend/handler/common/developer.cljs @@ -74,18 +74,22 @@ (println pull-data) (notification/show! "Copied block's data!" :success))) -(defn- import-submit [block import-input _] - (let [export-map (edn/read-string @import-input) - export-map' (sqlite-export/merge-export-map block export-map) - {:keys [init-tx block-props-tx] :as tx} (sqlite-export/build-entity-import (db/get-db) export-map')] - (pprint/pprint tx) - (p/do - ;; FIXME: Choose better metadata so that undo works consistently - (db/transact! (state/get-current-repo) init-tx {:save-block true}) - (when (seq block-props-tx) - (db/transact! (state/get-current-repo) block-props-tx {:save-block true}))) - ;; Also close cmd-k - (shui/dialog-close-all!))) +(defn- import-submit [block import-input _e] + (let [export-map (try (edn/read-string @import-input) (catch :default _err ::invalid-import))] + (if (= ::invalid-import export-map) + (notification/show! "The submitted EDN data is invalid! Fix and try again." :warning) + (let [export-map' (sqlite-export/merge-export-map block export-map) + {:keys [init-tx block-props-tx error] :as txs} (sqlite-export/build-entity-import (db/get-db) export-map')] + (if error + (notification/show! error :error) + (p/do + (pprint/pprint txs) + ;; FIXME: Choose better metadata so that undo works consistently + (db/transact! (state/get-current-repo) init-tx {:save-block true}) + (when (seq block-props-tx) + (db/transact! (state/get-current-repo) block-props-tx {:save-block true})))) + ;; Also close cmd-k + (shui/dialog-close-all!))))) (defn- import-entity-data [eid]