View Source Want.Keyword (want v2.0.0)

Manages conversions to and from keyword lists.

Summary

Functions

Cast an incoming keyword list or map to an output keyword list using the provided schema to control conversion rules and validations. Each value in the schema map represents conversion options.

Types

@type enumerable() :: Want.enumerable()
@type input() :: Want.enumerable()
@type key() :: binary() | atom()
@type opts() :: Keyword.t()
@type result() :: {:ok, result :: Keyword.t()} | {:error, reason :: binary() | map()}
@type schema() :: map()

Functions

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

Cast an incoming keyword list or map to an output keyword list using the provided schema to control conversion rules and validations. Each value in the schema map represents conversion options.

Specify a :type field to cast the input value for a given key to that type, defaults to :string. Specific conversion and validation options for each type corresponds to those available for Want.integer/2, Want.float/2, Want.string/2 and Want.atom/2.

Keyword lists can be nested by using a new schema map as a value in a parent schema. The field from which a given value is derived can also be modified using the :from option.

Options

  • :merge - Provide a keyword list matching the given schema that contains default values to be used if the input value does not contain a particular field.
  • :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 atom-keyed unknowns through to the output keyword list.

Examples

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

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

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

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

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

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

iex> Want.Keyword.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(%{"datetime" => DateTime.from_unix!(0)}, %{datetime: [type: :datetime]})
{:ok, %{datetime: DateTime.from_unix!(0)}}

iex> Want.Map.cast(%{"datetime" => "1970-01-01T00:00:00Z"}, %{datetime: [type: :datetime]})
{:ok, %{datetime: DateTime.from_unix!(0)}}

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

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

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

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

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

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

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

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

cast(input, schema, opts)

View Source
@spec cast(value :: input(), schema :: schema(), opts :: Keyword.t()) :: result()
@spec cast(input :: any(), key :: key() | [key()], opts :: opts() | map()) ::
  {:ok, result :: any()} | {:error, reason :: binary()}