ReactiveDag.Node.RecomputeBy (reactive_dag v0.17.0-rc.40)

Copy Markdown View Source

THE declaration the engine cares about: what unit does a change invalidate? Everything else a combinator declares — group_by, into, key derivation — is mapping data into shape once you already know what to recompute.

recompute_by :category, from: :expense_cat

Read: "recompute by category, from the input's expense_cat" — a change to a row's expense_cat invalidates my category unit, so redo it whole. That one fact supplies the input edge, the grouping, the claim resolution and the read scope, so it replaces the key_rule vocabulary entirely.

Four answers to the one question:

  • recompute_by :cell — the whole cell; any change re-does everything (a fold whose every output depends on every input).
  • recompute_by :cat, from: :child_field — per unit, resolved by READING the changed rows and evaluating the field. A key the lookup can't find (a deleted row) degrades to whole-cell: vanish must reprice everything it might have left.
  • recompute_by :month, from_key: true — per unit, resolved PURELY from the changed key's leading |-segments. No query and deletion-safe, at the price of the key-grammar contract.
  • (omitted) — key-for-key: a changed input key maps to the same output key.

NOTE this is the RECOMPUTE unit, not the output's grain. They coincide for a plain rollup, and diverge the moment one unit emits many rows: percentiles per day recompute_by :day (touch one reading, redo that day) while the rows are keyed day+percentile via expand:.

The unit is consumed at COMPILE time — it lowers to the combinator's over:

  • group_by: pair and is never traversed at recompute. One declaration per node, so a combinator reads exactly one input: one unit, one claim translation.

Summary

Functions

The unit as a group_by entry list: [unit: :from] — this node's column on the left, the input's field on the right. nil when the unit does no grouping.

Functions

group_by(recompute_by)

@spec group_by(struct()) :: keyword() | nil

The unit as a group_by entry list: [unit: :from] — this node's column on the left, the input's field on the right. nil when the unit does no grouping.

Three shapes, and code that handles only some of them is the bug this function exists to prevent: the compile-time verifier once re-derived this with the composite clause missing, so a composite unit read as "groups by nothing" and the into: check it feeds reported would carry [nil] on every build. A warning that fires on a correct declaration trains readers to ignore the one that matters.

  • :cell — the whole cell is one unit, so nothing is grouped.
  • [fund: :fund_code, fy: :fy] — the COMPOSITE form IS the grouping, and passes straight through (which is why group_by: is not restated).
  • :month + from: :read_on — one pair. Without from: the grouping is left to the combinator.