Polymarket.Schemas.Coerce (Polymarket v0.1.1)

Copy Markdown View Source

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

embed(module, attrs)

@spec embed(module(), map() | nil) :: struct() | nil

Builds one embedded struct from attrs via module.from_attrs/1, or nil when attrs is absent or fails to build.

embed_list(module, list)

@spec embed_list(module(), [map()] | nil) :: [struct()]

Builds a list of embedded structs via module.from_attrs/1, skipping any that fail to build. nil becomes [].

require_fields(struct, fields)

@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.

to_date(date)

@spec to_date(term()) :: Date.t() | nil

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.

to_datetime(datetime)

@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.

to_float(f)

@spec to_float(term()) :: float() | nil

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.

to_float_list(value)

@spec to_float_list(term()) :: [float()] | nil

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.

to_int(i)

@spec to_int(term()) :: integer() | nil

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.

to_string_list(value)

@spec to_string_list(term()) :: [String.t()] | nil

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.