diff --git a/deps/db/src/logseq/db/sqlite/build.cljs b/deps/db/src/logseq/db/sqlite/build.cljs index 4cd2971d55..6a87371f22 100644 --- a/deps/db/src/logseq/db/sqlite/build.cljs +++ b/deps/db/src/logseq/db/sqlite/build.cljs @@ -126,6 +126,45 @@ :original-property-id k :logseq.property/type prop-type})))) +(declare ->property-value-tx-m) + +(defn- build-pvalue [properties-config all-idents closed-value-id v] + (let [pvalue-uuid (or (:block/uuid v) (random-uuid)) + nested-pvalue-tx-m + (when (seq (:build/properties v)) + (some-> (->property-value-tx-m {:block/uuid pvalue-uuid} + (:build/properties v) + properties-config + all-idents) + ;; add :db/id to ensure datascript consistently creates this new tx + (update-vals (fn [prop-val] + (cond + (map? prop-val) + (assoc prop-val :db/id (new-db-id)) + (set? prop-val) + (set (map #(if (map? %) + (assoc % :db/id (new-db-id)) + %) + prop-val)) + :else + prop-val)))))] + {:attributes + (when (:build/property-value v) + (merge (:build/properties v) + nested-pvalue-tx-m + {:block/tags (mapv #(hash-map :db/ident (get-ident all-idents %)) + (:build/tags v))} + (select-keys v [:block/created-at :block/updated-at]) + {:block/uuid pvalue-uuid})) + :value + (cond + closed-value-id + closed-value-id + (:build/property-value v) + (or (:logseq.property/value v) (:block/title v)) + :else + v)})) + (defn- ->property-value-tx-m "Given a new block and its properties, creates a map of properties which have values of property value tx. This map is used for both creating the new property values and then adding them to a block. @@ -140,25 +179,8 @@ (when (= (:value item) v) (:uuid item))) (get property :build/closed-values))) - build-pvalue - (fn build-pvalue [v] - {:attributes - (when (:build/property-value v) - (merge (:build/properties v) - {:block/tags (mapv #(hash-map :db/ident (get-ident all-idents %)) - (:build/tags v))} - (select-keys v [:block/created-at :block/updated-at :block/uuid]))) - :value - (cond - closed-value-id - closed-value-id - - (:build/property-value v) - (or (:logseq.property/value v) (:block/title v)) - - :else - v)})] - (if (set? v) (set (map build-pvalue v)) (build-pvalue v)))]))) + build-pvalue' #(build-pvalue properties-config all-idents closed-value-id %)] + (if (set? v) (set (map build-pvalue' v)) (build-pvalue' v)))]))) ((fn [x] (db-property-build/build-property-values-tx-m new-block x {:pvalue-map? true}))))) @@ -394,15 +416,21 @@ (map #(-> (:blocks %) vec (conj (:page %)))) (mapcat (fn build-node-props-vec [nodes] (mapcat (fn [m] - (if-let [pvalue-pages - (->> (vals (:build/properties m)) - (mapcat #(if (set? %) % [%])) - (filter page-prop-value?) - (map second) - seq)] - (into (vec (:build/properties m)) - (build-node-props-vec pvalue-pages)) - (:build/properties m))) + (let [nested-pvalue-pages + (->> (vals (:build/properties m)) + (mapcat #(if (set? %) % [%])) + (keep #(cond + (page-prop-value? %) + (second %) + (and (map? %) (:build/property-value %)) + % + :else + nil)) + seq)] + (if nested-pvalue-pages + (into (vec (:build/properties m)) + (build-node-props-vec nested-pvalue-pages)) + (:build/properties m)))) nodes))) set) property-properties (->> (vals properties) diff --git a/deps/db/src/logseq/db/sqlite/export.cljs b/deps/db/src/logseq/db/sqlite/export.cljs index 264107c7d3..62a289a6ec 100644 --- a/deps/db/src/logseq/db/sqlite/export.cljs +++ b/deps/db/src/logseq/db/sqlite/export.cljs @@ -15,12 +15,10 @@ [logseq.db.frontend.db :as db-db] [logseq.db.frontend.entity-util :as entity-util] [logseq.db.frontend.property :as db-property] - [logseq.db.frontend.property.type :as db-property-type] [logseq.db.frontend.schema :as db-schema] [logseq.db.frontend.validate :as db-validate] [logseq.db.sqlite.build :as sqlite-build] - [logseq.db.sqlite.create-graph :as sqlite-create-graph] - [medley.core :as medley])) + [logseq.db.sqlite.create-graph :as sqlite-create-graph])) ;; Export fns ;; ========== @@ -60,27 +58,19 @@ (entity-util/journal? pvalue) [:build/page {:build/journal (:block/journal-day pvalue)}])) -(defn- build-pvalue-entity-default [db ent-properties pvalue +(defn- build-pvalue-entity-default [ent-properties pvalue {:keys [include-pvalue-uuid-fn] :or {include-pvalue-uuid-fn (constantly false)} :as options}] - (let [property-value-content' (property-value-content pvalue) - ;; TODO: Add support for ref properties here and in sqlite.build - build-properties - (some->> ent-properties - (keep (fn [[k v]] - (let [prop-type (:logseq.property/type (d/entity db k))] - (when-not (contains? db-property-type/all-ref-property-types prop-type) - [k v])))) - (into {}))] + (let [property-value-content' (property-value-content pvalue)] (if (or (seq ent-properties) (seq (:block/tags pvalue)) (include-pvalue-uuid-fn (:block/uuid pvalue))) (cond-> {:build/property-value :block :block/title property-value-content'} (seq (:block/tags pvalue)) (assoc :build/tags (->build-tags (:block/tags pvalue))) - (seq build-properties) - (assoc :build/properties build-properties) + (seq ent-properties) + (assoc :build/properties ent-properties) (include-pvalue-uuid-fn (:block/uuid pvalue)) (assoc :block/uuid (:block/uuid pvalue) :build/keep-uuid? true) @@ -107,14 +97,12 @@ ;; Use metadata to distinguish from block references that don't exist like closed values ^::existing-property-value? [:block/uuid (:block/uuid pvalue)]) (or (:db/ident pvalue) - (let [ent-properties* (->> (apply dissoc (db-property/properties pvalue) - :logseq.property/value :logseq.property/created-from-property - db-property/public-db-attribute-properties) - ;; TODO: Allow user properties when sqlite.build supports it - (medley/filter-keys db-property/internal-property?)) + (let [ent-properties* (apply dissoc (db-property/properties pvalue) + :logseq.property/value :logseq.property/created-from-property + db-property/public-db-attribute-properties) ent-properties (when (and (not (:block/closed-value-property pvalue)) (seq ent-properties*)) (buildable-properties db' ent-properties* properties-config' options'))] - (build-pvalue-entity-default db ent-properties pvalue options'))))))] + (build-pvalue-entity-default ent-properties pvalue options'))))))] (->> (apply dissoc ent-properties ignored-properties) (map (fn [[k v]] [k @@ -241,10 +229,22 @@ (defn- build-node-properties [db entity ent-properties {:keys [properties] :as options}] - (let [new-user-property-ids (->> (keys ent-properties) + (let [collect-nested-property-ids + (fn collect-nested-property-ids [v] + (cond + (and (de/entity? v) (:logseq.property/created-from-property v)) + (let [pvalue-properties (apply dissoc (db-property/properties v) db-property/public-db-attribute-properties)] + (concat (keys pvalue-properties) + (mapcat collect-nested-property-ids (vals pvalue-properties)))) + (set? v) + (mapcat collect-nested-property-ids v) + :else + [])) + new-user-property-ids (->> (keys ent-properties) (concat (->> (:block/tags entity) (mapcat :logseq.property.class/properties) (map :db/ident))) + (concat (mapcat collect-nested-property-ids (vals ent-properties))) ;; Built-in properties and any possible modifications are not exported (remove db-property/logseq-property?) (remove #(get properties %)))] diff --git a/deps/db/test/logseq/db/sqlite/export_test.cljs b/deps/db/test/logseq/db/sqlite/export_test.cljs index cb10eba10f..e1349bcb60 100644 --- a/deps/db/test/logseq/db/sqlite/export_test.cljs +++ b/deps/db/test/logseq/db/sqlite/export_test.cljs @@ -285,6 +285,8 @@ :build/keep-uuid? true :build/property-classes [:user.class/NodeClass]} :user.property/p2 + {:logseq.property/type :default} + :user.property/p3 {:logseq.property/type :default}} :extract-content-refs? false :pages-and-blocks @@ -304,6 +306,7 @@ {:block/title "block with a pvalue that has a :block/uuid" :build/properties {:user.property/p2 {:build/property-value :block :block/title "property value block" + :build/properties {:user.property/p3 "woot"} :block/uuid pvalue-block-uuid :build/keep-uuid? true}}}]} {:page {:block/title "page with block ref"}