Docket.Reducer (docket v0.1.1)

Copy Markdown View Source

Public reducer descriptors for graph state fields, plus the pure reduction engine the runtime applies at every commit.

A reducer folds the field's prior committed value with the step's writes (deterministically sorted by writer node ID):

new_value = reduce(reducer, current_committed_value, sorted_writes)

Built-in reducers

ReducerSemantics
:last_valuelast write wins; the prior value is ignored
:first_valuekeep the prior value once set; otherwise the first write
:appendlist accumulation: current ++ writes
:mergemap merge: writes fold into the prior map
:sumnumeric accumulation: prior value plus every write
:unionappend + dedupe (first occurrence wins)

For :append and :union, a list write concatenates its elements and any other write appends as a single element; to append one element that is itself a list, wrap it in an outer list.

Options

  • :appendunique: true drops duplicate elements (first occurrence wins); max_length: n keeps only the last n elements (sliding window), applied after unique.
  • :unionby: key dedupes elements by the value at key (a string or a list of strings forming a path); elements missing the key dedupe by their whole value.
  • :mergedeep: true merges nested maps recursively instead of replacing them.

Option keys are stored as strings (constructors normalize atom keys), matching the wire format. Unknown option keys are stored but ignored.

Initial values

Accumulating reducers have a natural zero used as the field's effective default when it declares none: [] for :append/:union, %{} for :merge, 0 for :sum. A field's explicit default acts as the base the first commit folds into — including :first_value, where an explicit default counts as the value already being set.

Write validation

Node writes to a field validate against a reducer-dependent shape rather than the committed field schema (which stays the truth for the committed value): :append/:union writes validate against the list schema's item (a list write validates each element), :merge writes validate as a map fragment of the field schema with top-level required fields relaxed, and :sum writes must be a number of the schema's type.

Summary

Functions

Normalizes reducer shorthand into a Docket.Reducer struct: a built-in type atom (:append) or a {type, opts} tuple ({:append, max_length: 50}).

Folds the prior committed value with one step's writes.

All built-in reducer types.

The schema a single node write validates against, given the field schema and the write itself. nil means the write is not schema-validated.

The natural zero for accumulating reducers, used as a field's effective default when it declares none. nil for non-accumulating reducers.

Types

t()

@type t() :: %Docket.Reducer{opts: map(), type: type()}

type()

@type type() :: :append | :first_value | :last_value | :merge | :sum | :union

Functions

append(opts \\ [])

@spec append(keyword() | map()) :: t()

first_value(opts \\ [])

@spec first_value(keyword() | map()) :: t()

last_value(opts \\ [])

@spec last_value(keyword() | map()) :: t()

merge(opts \\ [])

@spec merge(keyword() | map()) :: t()

normalize(reducer)

@spec normalize(term()) :: term()

Normalizes reducer shorthand into a Docket.Reducer struct: a built-in type atom (:append) or a {type, opts} tuple ({:append, max_length: 50}).

Real reducers and values matching no shorthand pass through unchanged; the compiler reports the latter as invalid reducers.

reduce(arg1, current, values)

@spec reduce(t() | nil, {:ok, term()} | :unset, [term()]) :: term()

Folds the prior committed value with one step's writes.

current is {:ok, value} when the field has a committed value or an effective default, :unset otherwise. values are the step's writes in sorted writer order and must be non-empty. A nil reducer reduces as :last_value.

sum(opts \\ [])

@spec sum(keyword() | map()) :: t()

types()

@spec types() :: [type()]

All built-in reducer types.

union(opts \\ [])

@spec union(keyword() | map()) :: t()

write_schema(arg1, schema, write)

@spec write_schema(t() | nil, Docket.Schema.t() | nil, term()) ::
  Docket.Schema.t() | nil

The schema a single node write validates against, given the field schema and the write itself. nil means the write is not schema-validated.

zero(reducer)

@spec zero(t() | nil) :: term()

The natural zero for accumulating reducers, used as a field's effective default when it declares none. nil for non-accumulating reducers.