Skip to content

Instantly share code, notes, and snippets.

@favila
Last active February 21, 2021 13:37
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save favila/8ce31de4b2cb04cf202687c6a8fa4c94 to your computer and use it in GitHub Desktop.
Save favila/8ce31de4b2cb04cf202687c6a8fa4c94 to your computer and use it in GitHub Desktop.
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