Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Datomic transaction functions to "reset" attributes: i.e. make them have a post-transaction value you specify without having to enumerate the retractions.
(def tx-fns
[{:db/ident :db.fn/reset-attribute-values
:db/doc "Transaction function which accepts an entity identifier, attribute identifier
and set of values and expands to any additions and retractions necessary to
make the final post-transaction value of the attribute match the provided
values. Attribute values must be scalars.
If multiple values are provided on a cardinality-one attribute you will get a
datom conflict exception at transaction time."
:db/fn (d/function
'{:lang "clojure"
:params [db lookup-ref attr values]
:code (let [e (d/entid db lookup-ref)
a (d/entid db attr)
old-values (into [] (map :v)
(d/datoms db :eavt e a))
new-values (into #{} values)]
(as-> (transient []) cmds
(reduce
(fn [cmds ov]
(if-not (contains? new-values ov)
(conj! cmds [:db/retract e a ov])
cmds))
cmds old-values)
(reduce
(fn [cmds nv] (conj! cmds [:db/add e a nv]))
cmds new-values)
(persistent! cmds)))})}
{:db/ident :db.fn/reset-attributes
:db/doc "Transaction function which accepts an entity identifier and a map of
attributes and values and expands to any additions and retractions necessary
to make the final post-transaction value of those attributes of the entity
match the value provided by the map. Attribute values must be scalars or sets
of scalars. The special value nil will retract all values of the attribute.
Attributes not mentioned by the map will not be altered. "
:db/fn (d/function
'{:lang "clojure"
:params [db lookup-ref attr-val-map]
:code (let [e (d/entid db lookup-ref)]
(into []
(keep
(fn [[attr xs]]
(if (= (:cardinality (d/attribute db attr))
:db.cardinality/many)
[:db.fn/reset-attribute-values e attr xs]
(if (nil? xs)
(when-some [oldv (-> (d/datoms db :eavt e
attr) first :v)]
[:db/retract e attr oldv])
[:db/add e attr xs]))))
attr-val-map))})}])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment