fix: build and export of property values

for a :many property that has additional attributes
e.g. :build/tags
Another possible fix for https://github.com/logseq/db-test/issues/636
This commit is contained in:
Gabriel Horner
2025-12-11 14:45:28 -05:00
parent 75a1312387
commit 529be0496c
3 changed files with 63 additions and 46 deletions

View File

@@ -97,43 +97,46 @@
transacted, given a block and a properties map with raw property values. The
properties map can have keys that are db-idents or they can be maps. If a map,
it should have :original-property-id and :db/ident keys. See
->property-value-tx-m for such an example
->property-value-tx-m for such an example. Options:
:pure? - ensure this fn is a pure function"
[block properties & {:keys [pure?]}]
* :pure? - ensure this fn is a pure function
* :pvalue-map? - When set, property value is passed as a map with keys :value and :attributes. This
allows property values to have additional attributes"
[block properties & {:keys [pure? pvalue-map?]}]
;; Build :db/id out of uuid if block doesn't have one for tx purposes
(let [block' (if (:db/id block) block (assoc block :db/id [:block/uuid (:block/uuid block)]))]
(->> properties
(map (fn [[k v]]
(let [{:keys [property-value-properties] :as property-map} (if (map? k) k {:db/ident k})
(map (fn [[k v*]]
(let [property-map (if (map? k) k {:db/ident k})
gen-uuid-value-prefix (when pure?
(or (:db/ident block) (:block/uuid block)))]
(or (:db/ident block) (:block/uuid block)))
->pvalue #(if pvalue-map? (:value %) %)
v (if (set? v*)
(set (map ->pvalue v*))
(->pvalue v*))
->value-block-opts
(fn ->value-block-opts [v']
(cond-> {}
(and pvalue-map? (seq (:attributes v')))
(assoc :properties (:attributes v'))
pure?
(assoc :block-uuid
(common-uuid/gen-uuid :builtin-block-uuid
(str gen-uuid-value-prefix "-" (->pvalue v'))))))]
(assert (:db/ident property-map) "Key in map must have a :db/ident")
(when pure? (assert (some? gen-uuid-value-prefix) block))
[(or (:original-property-id property-map) (:db/ident property-map))
(cond
(and (set? v) (every? uuid? v))
(set (map #(vector :block/uuid %) v))
(set? v)
(set (map #(build-property-value-block
block' property-map %
(cond-> {}
property-value-properties
(assoc :properties property-value-properties)
pure?
(assoc :block-uuid
(common-uuid/gen-uuid :builtin-block-uuid (str gen-uuid-value-prefix "-" %)))))
v))
(set? v*)
(set
(map #(build-property-value-block block' property-map (->pvalue %) (->value-block-opts %))
v*))
(uuid? v)
[:block/uuid v]
:else
(build-property-value-block block' property-map v
(cond-> {}
property-value-properties
(assoc :properties property-value-properties)
pure?
(assoc :block-uuid
(common-uuid/gen-uuid :builtin-block-uuid (str gen-uuid-value-prefix "-" v))))))])))
(build-property-value-block block' property-map v (->value-block-opts v*)))])))
(into {}))))
(defn- lookup-id?

View File

@@ -132,29 +132,33 @@
(->> properties
(keep (fn [[k v]]
(when-let [property-map (build-property-map-for-pvalue-tx k v new-block properties-config all-idents)]
[(let [pvalue-attrs (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])))]
(cond-> property-map
(and (:build/property-value v) (seq pvalue-attrs))
(assoc :property-value-properties pvalue-attrs)))
[property-map
(let [property (when (keyword? k) (get properties-config k))
closed-value-id (when property (some (fn [item]
(when (= (:value item) v)
(:uuid item)))
(get property :build/closed-values)))]
(cond
closed-value-id
closed-value-id
(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))
(:build/property-value v)
(or (:logseq.property/value v) (:block/title v))
:else
v))])))
(db-property-build/build-property-values-tx-m new-block)))
:else
v)})]
(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})))))
(defn- extract-basic-content-refs
"Extracts basic refs from :block/title like `[[foo]]` or `[[UUID]]`. Can't

View File

@@ -830,18 +830,28 @@
(let [pvalue-uuid1 (random-uuid)
original-data
{:classes {:user.class/C1 {}}
:properties {:user.property/default {:logseq.property/type :default}}
:properties
{:user.property/default {:logseq.property/type :default}
:user.property/default-many {:logseq.property/type :default
:db/cardinality :db.cardinality/many}}
:pages-and-blocks
[{:page {:block/title "page1"}
:blocks [{:block/title "block with a pvalue that has :build/tags"
:blocks [{:block/title "block with pvalue that has :build/tags"
:build/properties {:user.property/default {:build/property-value :block
:block/title "property value block"
:block/title "tags pvalue"
:build/tags [:user.class/C1]}}}
{:block/title "block that has a pvalue with a view"
{:block/title "block with pvalue that has a view"
:build/properties {:user.property/default {:build/property-value :block
:block/title "property value block2"
:block/title "view pvalue"
:block/uuid pvalue-uuid1
:build/keep-uuid? true}}}]}
:build/keep-uuid? true}}}
{:block/title "block with pvalue map in a :many property"
:build/properties
{:user.property/default-many
#{"yep"
{:build/property-value :block
:block/title ":many pvalue"
:build/tags [:user.class/C1]}}}}]}
{:page {:block/title "$$$views2"}
:blocks [{:block/title "Unlinked references",
:build/properties