View Source Want.Map (want v2.0.0)

Manages conversions to and from maps.

Summary

Functions

Cast an incoming keyword list or map to an output map using the provided schema to control conversion rules and validations.

Types

@type enumerable() :: Want.enumerable()
@type input() :: Want.enumerable()
@type key() :: binary() | atom()
@type opts() :: Keyword.t()
@type result() :: {:ok, result :: map()} | {:error, reason :: binary() | map()}
@type schema() :: map()
@type type() ::
  :atom
  | :boolean
  | :date
  | :datetime
  | :enum
  | :float
  | :integer
  | {:array, any()}
  | {:map, any(), any()}
  | module()
  | :string

Functions

@spec cast(input(), schema()) :: result()

Cast an incoming keyword list or map to an output map using the provided schema to control conversion rules and validations.

Options

  • :merge - Provide a map matching the given schema that contains default values to be used if the input value does not contain a particular field. Useful when updating a map with new inputs without overwriting all fields.
  • :collect_errors - If true, all field errors are accumulated into a %{field => reason} map and returned as {:error, errors} rather than halting on the first failure.
  • :unknown - Controls handling of input keys not present in the schema. :ignore (default) discards them. :error returns an error if any are present. :include passes them through to the output map unchanged.

Examples

iex> Want.Map.cast(%{"id" => 1}, %{id: [type: :integer]})
{:ok, %{id: 1}}

iex> Want.Map.cast(%{"identifier" => 1}, %{id: [type: :integer, from: :identifier]})
{:ok, %{id: 1}}

iex> Want.Map.cast(%{}, %{id: [type: :integer, default: 1]})
{:ok, %{id: 1}}

iex> Want.Map.cast(%{"id" => "bananas"}, %{id: [type: :integer, default: 1]})
{:ok, %{id: 1}}

iex> Want.Map.cast(%{"hello" => "world", "foo" => "bar"}, %{hello: [], foo: [type: :atom]})
{:ok, %{hello: "world", foo: :bar}}

iex> Want.Map.cast(%{"hello" => %{"foo" => "bar"}}, %{hello: %{foo: [type: :atom]}})
{:ok, %{hello: %{foo: :bar}}}

iex> Want.Map.cast(%{"id" => "bananas"}, %{id: [type: :integer, default: 1]}, merge: %{id: 2})
{:ok, %{id: 2}}

iex> Want.Map.cast(%{"id" => "bananas"}, %{id: [type: :any]})
{:ok, %{id: "bananas"}}

iex> Want.Map.cast(%{"a" => %{"b" => %{"c" => 100}}}, %{id: [type: :integer, from: {"a", "b", "c"}]})
{:ok, %{id: 100}}

iex> Want.Map.cast(%{"a" => [1, 2, 3, 4]}, %{a: [type: {:array, :integer}]})
{:ok, %{a: [1, 2, 3, 4]}}

iex> Want.Map.cast(%{"a" => %{"b" => %{"c" => 100}}}, %{id: [type: :integer, from: {"a", "b", "c"}, transform: fn x -> x * 2 end]})
{:ok, %{id: 200}}

iex> Want.Map.cast(%{"hello" => "world"}, %{hello: [], foo: [required: true]})
{:error, "Failed to cast key foo (key :foo not found) and no default value provided."}

iex> Want.Map.cast(%{"c" => "world"}, %{foo: [type: :string, from: ["a", "b", "c"]]})
{:ok, %{foo: "world"}}

iex> Want.Map.cast(%{"hello" => "world"}, %{hello: [type: :enum, valid: [:world]]})
{:ok, %{hello: :world}}

iex> Want.Map.cast(%{"hello" => "world"}, %{hello: [], foo: []})
{:ok, %{hello: "world"}}

iex> Want.Map.cast(%{"date" => %Date{year: 2022, month: 01, day: 02}}, %{date: [type: :date]})
{:ok, %{date: %Date{year: 2022, month: 01, day: 02}}}

iex> Want.Map.cast(%{"date" => "2022-01-02"}, %{date: [type: :date]})
{:ok, %{date: %Date{year: 2022, month: 01, day: 02}}}

iex> Want.Map.cast(%{"archived" => "true"}, %{archived: [type: :boolean, default: false]})
{:ok, %{archived: true}}

iex> Want.Map.cast(%{"archived" => "false"}, %{archived: [type: :boolean, default: false]})
{:ok, %{archived: false}}

iex> Want.Map.cast(%{}, %{archived: [type: :boolean, default: false]})
{:ok, %{archived: false}}
Link to this function

cast(input, schema, opts)

View Source
@spec cast(input(), key() | [key()] | tuple() | schema(), opts :: keyword()) ::
  result()