DrinkMeAlice.Ash.Codec (drink_me_alice v0.1.0)

Copy Markdown

Attribute ↔ SurrealDB value mapping for the Ash data layer, keyed on Ash.Type.storage_type/2.

storage typeSurreal fieldwritten as
:string :citext :uuid :binary_idstringexact string (DrinkMeAlice.exact_string/1)
:naive_datetime* :date :time*stringexact ISO-8601 string
:integerint$p (i64)
:booleanbool$p
:utc_datetime :utc_datetime_usecdatetime<datetime>$p
:decimaldecimal<decimal>$p (decimal string)
:floatfloat<float>$p (float string)
:mapstringexact canonical JSON text
{:array, scalar}array<T>element-wise as above

Why: SurrealDB 3.0.5 coerces typed-looking JSON strings — date-shaped strings become datetimes and do not survive a <string> cast (see DrinkMeAlice.exact_string/1) — so every string travels in the exact form. The outbound encoder (DrinkMeAlice.Json.encode/1) carries only canonical terms, so floats, decimals and datetimes travel as strings cast in SurrealQL. Maps are stored as canonical JSON text rather than as objects: an object's nested strings would be coerced, and there is no server-side JSON parse to undo it; the cost is that map contents are not filterable. nil is written as the literal NONE: a JSON null is rejected by option<T> fields.

Anything else is {:error, {:unsupported_type, name, storage}} — at schema generation and at write time — rather than a lossy guess.

Summary

Functions

Decode one stored field value back into the attribute's Ash value (nil for an absent field).

Encode one attribute value for a write or a filter comparison: {:ok, :none} for nil (write the literal NONE), or {:ok, {kind, wire_value}} — pair with param_sql/2.

The Surreal field type for an attribute, without option<>: {:ok, "string"} | {:error, {:unsupported_type, name, storage}}.

The SurrealQL expression reading param name of kind back into the stored value.

The storage type for an attribute.

The wire kind for a storage type, or :error.

Types

kind()

@type kind() :: :str | :plain | {:cast, binary()} | :json | {:array, kind()}

Functions

decode(attr, value)

@spec decode(map(), term()) :: {:ok, term()} | {:error, term()}

Decode one stored field value back into the attribute's Ash value (nil for an absent field).

encode(attr, value)

@spec encode(map(), term()) :: {:ok, :none | {kind(), term()}} | {:error, term()}

Encode one attribute value for a write or a filter comparison: {:ok, :none} for nil (write the literal NONE), or {:ok, {kind, wire_value}} — pair with param_sql/2.

field_type(attr)

@spec field_type(map()) :: {:ok, binary()} | {:error, term()}

The Surreal field type for an attribute, without option<>: {:ok, "string"} | {:error, {:unsupported_type, name, storage}}.

param_sql(arg1, name)

@spec param_sql(kind(), binary()) :: binary()

The SurrealQL expression reading param name of kind back into the stored value.

storage(map)

The storage type for an attribute.

wire_kind(storage)

@spec wire_kind(term()) :: {:ok, kind()} | :error

The wire kind for a storage type, or :error.