AshArcadic.TraversalAggregate (AshArcadic v0.1.0)

Copy Markdown View Source

Post-authorization Elixir fold for traversal aggregates (Slice 4). Folds a source's ALREADY-authorized, node-deduped, tenant-scoped, filtered, sorted destination records (from Traverse.load's Read B) into one aggregate value — never a DB-side aggregate (which would count policy-denied nodes and double-count multi-path nodes for sum/avg).

guard_field/2 (reused from AshArcadic.Aggregate) runs BEFORE any fold — a value-reading aggregate over non-numeric/non-orderable/:binary (sensitive) storage fails closed value-free. Records are already decoded Ash structs, so field values carry their proper Elixir type (no re-coerce). min/max over date/time use the type's compare/2 (term order of a DateTime map is NOT chronological). include_nil? is HONORED for list/first (Elixir null control), a capability gain over the Slice-3 flat path (Cypher collect drops nulls). The fold is wrapped value-free: any protocol/arithmetic error returns {:error, :aggregate_fold_failed}, never a value.

Summary

Functions

fold(records, agg, types)

@spec fold([map()], Ash.Query.Aggregate.t(), %{
  required(atom()) => {Ash.Type.t(), keyword()}
}) ::
  {:ok, term()} | {:error, term()}