Helpers for building schema structs directly from a decoded message, without
the overhead of Ecto.Changeset casting.
Every value that arrives from an API is coerced to the schema's field type
here: numbers (to_float/1, to_int/1) — which the market feed delivers as
JSON strings (e.g. "0.01", "1782553314962") — timestamps
(to_datetime/1, to_date/1), JSON-encoded arrays (to_string_list/1,
to_float_list/1), and nested embeds (embed/2, embed_list/2). Anything
that does not parse cleanly becomes nil rather than raising, mirroring Ecto's
lenient cast semantics.
The numeric coercions and require_fields/2 sit on the websocket hot path —
keep them branch-cheap and allocation-free.
Summary
Functions
Builds one embedded struct from attrs via module.from_attrs/1, or nil
when attrs is absent or fails to build.
Builds a list of embedded structs via module.from_attrs/1, skipping any that
fail to build. nil becomes [].
Validates that each field in fields is present (non-nil) on struct.
Coerces a decoded JSON value to a Date.
Coerces a decoded JSON value to a UTC DateTime.
Coerces a decoded JSON value to a float.
Coerces a field that holds a list of floats, decoding a JSON-encoded string as
to_string_list/1 does and coercing each element with to_float/1.
Coerces a decoded JSON value to an integer.
Coerces a field that holds a list of strings.
Functions
Builds one embedded struct from attrs via module.from_attrs/1, or nil
when attrs is absent or fails to build.
Builds a list of embedded structs via module.from_attrs/1, skipping any that
fail to build. nil becomes [].
@spec require_fields( struct(), [atom()] ) :: {:ok, struct()} | {:error, {:missing_fields, [atom()]}}
Validates that each field in fields is present (non-nil) on struct.
Returns {:ok, struct} when all are present, otherwise
{:error, {:missing_fields, missing}}. This is the lightweight replacement for
Ecto.Changeset.validate_required/2 on the hot path.
Coerces a decoded JSON value to a Date.
Accepts a Date or an ISO 8601 date string. Returns nil for nil or
anything that does not parse.
@spec to_datetime(term()) :: DateTime.t() | nil
Coerces a decoded JSON value to a UTC DateTime.
Accepts a DateTime or an ISO 8601 string (with or without an offset; a naive
string is read as UTC). Returns nil for nil or anything that does not parse.
Coerces a decoded JSON value to a float.
Accepts a float, an integer, or a fully-numeric binary. Returns nil for
nil or any value that does not parse cleanly.
Coerces a field that holds a list of floats, decoding a JSON-encoded string as
to_string_list/1 does and coercing each element with to_float/1.
Coerces a decoded JSON value to an integer.
Accepts an integer or a fully-numeric binary. Returns nil for nil or any
value that does not parse cleanly.
Coerces a field that holds a list of strings.
Some Gamma fields arrive as a JSON-encoded string (e.g.
"[\"Up\", \"Down\"]"); those are decoded. An already-decoded list is
passed through, an empty string becomes [], and nil passes through.