Explorar el Código

enhance: export-edn supports :build/properties in property values

no matter how many levels deep a property value has properties
Gabriel Horner hace 1 día
padre
commit
5e43f89af2

+ 56 - 28
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)

+ 22 - 22
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 %)))]

+ 3 - 0
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"}