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_onebecomenil,rel_manybecomes[]), 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
Functions
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.
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.
Encodes an Ash action result to a Lua-friendly value (plain Elixir maps/lists/primitives
that Lua.encode!/2 knows how to convert).
@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"}.
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.
@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).