ReactiveDag.Node.Recompute.Declarative (reactive_dag v0.17.0-rc)

Copy Markdown View Source

The pure builders behind the DECLARATIVE combinator slots. Each turns a declarative spec — attribute atoms, fold keywords, side picks — into the same fn shape the per-slot escape hatches supply, so the recompute pipeline runs one code path however declarative the author went.

Fold semantics follow SQL aggregates: nil source values are excluded, and a fold over no non-nil values yields nil (count counts rows and is never nil). first is the first non-nil value in the group's read order.

Summary

Functions

The fold kinds into:'s declarative form accepts.

The CHILD (over-resource) field of each group entry — what is read and grouped.

The PARENT (this node's) column of each group entry — what the row carries.

group_by spec → (item -> group_term). A list groups by the TUPLE of entry values. An entry names an attribute OR a CALCULATION on the over resource — derived grouping values (a calendar bucket, a normalized code) are Ash calculations, declared where the data lives; the library loads them in the read (ReactiveDag.Calendar ships the calendar ones). The RELATIONAL-JOIN spelling {parent_field, child_field} ([category: :expense_cat]) groups by the CHILD field while the row carries the PARENT column — Ash's source/destination-attribute pair, for the DAG edge.

The IDENTITY key serializer for a composite-primary-key node: the cell key is the row's identity fields, in primary-key order, joined with "|" (the same canonical serialization derived keys have always used) — the key is no longer a stored column but the serialization of the row's Ash identity.

reduce into: spec → (group_term, items -> row). The declarative form produces the group's attribute columns (requires a declarative group_by, enforced at compile time) merged with the fold results, keyed by dest names.

join into: spec → (join_key, left, right -> row). The declarative form picks columns per side ([left: [amount: :budget], right: [amount: :actual]]; bare atom = same-named dest); an absent side yields nils, so left-join/outer gap semantics fall out.

key spec (+ key_prefix) → (group_term_or_join_key -> key string). The default joins a tuple's values with "|" (a single value stringifies), and prepends "<prefix>|" when a prefix is given.

join side spec → (item -> join_key | nil). An attribute projects it (nil value = not on this side); [key: :acct, where: [kind: :budget]] puts the item on the side iff every where pair matches, keyed by the key: attr.

Functions

fold_kinds()

@spec fold_kinds() :: [atom()]

The fold kinds into:'s declarative form accepts.

group_children(entries)

The CHILD (over-resource) field of each group entry — what is read and grouped.

group_dests(entries)

The PARENT (this node's) column of each group entry — what the row carries.

group_fn(fun)

group_by spec → (item -> group_term). A list groups by the TUPLE of entry values. An entry names an attribute OR a CALCULATION on the over resource — derived grouping values (a calendar bucket, a normalized code) are Ash calculations, declared where the data lives; the library loads them in the read (ReactiveDag.Calendar ships the calendar ones). The RELATIONAL-JOIN spelling {parent_field, child_field} ([category: :expense_cat]) groups by the CHILD field while the row carries the PARENT column — Ash's source/destination-attribute pair, for the DAG edge.

identity_key_fn(fields, prefix)

The IDENTITY key serializer for a composite-primary-key node: the cell key is the row's identity fields, in primary-key order, joined with "|" (the same canonical serialization derived keys have always used) — the key is no longer a stored column but the serialization of the row's Ash identity.

into_fn(fun, group_by)

reduce into: spec → (group_term, items -> row). The declarative form produces the group's attribute columns (requires a declarative group_by, enforced at compile time) merged with the fold results, keyed by dest names.

join_into_fn(fun)

join into: spec → (join_key, left, right -> row). The declarative form picks columns per side ([left: [amount: :budget], right: [amount: :actual]]; bare atom = same-named dest); an absent side yields nils, so left-join/outer gap semantics fall out.

key_fn(fun, prefix)

key spec (+ key_prefix) → (group_term_or_join_key -> key string). The default joins a tuple's values with "|" (a single value stringifies), and prepends "<prefix>|" when a prefix is given.

side_fn(fun)

join side spec → (item -> join_key | nil). An attribute projects it (nil value = not on this side); [key: :acct, where: [kind: :budget]] puts the item on the side iff every where pair matches, keyed by the key: attr.