Current section
Files
Jump to
Current section
Files
lib/types/map_type.ex
defmodule Talos.Types.MapType do
@moduledoc false
defstruct [:fields]
@behaviour Talos.Types
@default_options %{optional: false, allow_nil: false}
def valid?(%__MODULE__{fields: nil}, value) do
is_map(value)
end
def valid?(%__MODULE__{fields: fields}, value) do
is_map(value) &&
Enum.all?(fields, fn field ->
case field do
{key, type} ->
validation_check(type, value, key)
{key, type, options} ->
validation_check(type, value, key, options)
end
end)
end
def errors(%__MODULE__{fields: fields} = type, value) do
cond do
is_nil(fields) && is_map(value) ->
%{}
!is_map(value) ->
["#{inspect(value)} does not match #{inspect(type)}"]
!valid?(type, value) ->
errors_for_fields(fields, value)
true ->
%{}
end
end
defp errors_for_fields(fields, map) do
fields
|> Enum.map(fn field ->
case field do
{key, type} ->
case validation_check(type, map, key) do
true -> nil
false -> {key, Talos.errors(type, map[key])}
end
{key, type, options} ->
case validation_check(type, map, key, options) do
true -> nil
false -> {key, Talos.errors(type, map[key])}
end
end
end)
|> Enum.reject(&is_nil/1)
|> Map.new()
end
defp validation_check(type, map, key, opts \\ %{}) do
options = Map.merge(@default_options, Map.new(opts))
cond do
options[:optional] && !Map.has_key?(map, key) -> true
!options[:optional] && !Map.has_key?(map, key) -> false
Map.has_key?(map, key) && options[:allow_nil] && is_nil(map[key]) -> true
Map.has_key?(map, key) && !options[:allow_nil] && is_nil(map[key]) -> false
is_nil(type) -> true
true -> Talos.valid?(type, map[key])
end
end
end