AshLua.Encoder (ash_lua v0.1.5)

Copy Markdown View Source

Conversions between Elixir/Ash values and the plain shapes that :luerl (via the :lua package) can encode as Lua tables.

Lua doesn't have atoms or sigils — atoms are rendered as strings, Decimal/Date/DateTime/ NaiveDateTime/Time as their canonical string forms, and structs as plain attribute maps (no relationships, no calculations, no aggregates unless they happen to be already loaded as a field value).

Forbidden fields

Ash replaces fields the actor isn't allowed to see with %Ash.ForbiddenField{}. The encoder's treatment is controlled by a per-process mode (defaulting to :hide):

  • :hide — the field is stripped (scalars/rel_one become nil, rel_many becomes []), so the consumer can't distinguish "forbidden" from "absent".
  • :display — the field is rendered as the opaque marker %{"opaque" => "forbidden"}, so the consumer sees the field exists but is inaccessible.

Set the mode by calling encode_result/2 / encode_with_template/3 with :hide or :display.

Summary

Types

How forbidden fields are rendered. See the module docs.

Functions

Decodes a Lua-side input value into the shape Ash actions expect for params/arguments.

Encodes an Ash error tree into a Lua-friendly table.

Encodes an Ash action result to a Lua-friendly value (plain Elixir maps/lists/primitives that Lua.encode!/2 knows how to convert).

Like encode_result/1, but runs with the given forbidden-field mode in effect (see the module docs). :hide strips forbidden fields; :display renders them as %{"opaque" => "forbidden"}.

Encodes a result against a template produced by AshLua.Fields.for_action/4.

Like encode_with_template/2, but runs with the given forbidden-field mode in effect (see the module docs).

Types

forbidden_mode()

@type forbidden_mode() :: :hide | :display

How forbidden fields are rendered. See the module docs.

Functions

decode_input(value)

@spec decode_input(term()) :: term()

Decodes a Lua-side input value into the shape Ash actions expect for params/arguments.

Luerl decodes Lua tables as a list of two-tuples — keyed by integers for sequences and by strings for maps. We normalize:

  • integer-keyed (sequence) tables → plain lists, sorted by index
  • string-keyed tables → maps with string keys (Ash accepts string-keyed params)
  • empty tables → empty maps (Ash actions are always invoked with a map of params)

Recurses into values.

encode_error(error)

@spec encode_error(term()) :: map()

Encodes an Ash error tree into a Lua-friendly table.

Walks Ash.Error.Invalid/Ash.Error.Forbidden classes to their leaves, then dispatches each leaf through the AshLua.Error protocol. Leaves without a protocol impl render as an opaque "unknown error" entry with a uuid that's logged via Logger.warning/1 so operators can correlate the surfaced uuid with full stacktrace details.

The envelope carries a class tag ("invalid" | "forbidden" | "framework" | "unknown") and the full per-error list in errors. Consumers that want a one-line summary should pick the appropriate entry from errors themselves rather than read a top-level message — joining or first-pick'ing here would silently mislead in the multi-error case.

encode_result(value)

@spec encode_result(term()) :: term()

Encodes an Ash action result to a Lua-friendly value (plain Elixir maps/lists/primitives that Lua.encode!/2 knows how to convert).

encode_result(value, mode)

@spec encode_result(term(), forbidden_mode()) :: term()

Like encode_result/1, but runs with the given forbidden-field mode in effect (see the module docs). :hide strips forbidden fields; :display renders them as %{"opaque" => "forbidden"}.

encode_with_template(value, template)

@spec encode_with_template(term(), term()) :: term()

Encodes a result against a template produced by AshLua.Fields.for_action/4.

Walks the template recursively, pulling only the requested fields from records, typed maps, tuples, and union values. :passthrough template nodes fall back to the unconstrained encode_result/1 path.

encode_with_template(value, template, mode)

@spec encode_with_template(term(), term(), forbidden_mode()) :: term()

Like encode_with_template/2, but runs with the given forbidden-field mode in effect (see the module docs).