Current section

Files

Jump to
zoi lib zoi types object.ex
Raw

lib/zoi/types/object.ex

defmodule Zoi.Types.Object do
@moduledoc false
use Zoi.Type.Def, fields: [:fields, :keys, :inner, :strict, :coerce]
def new(fields, opts) when is_map(fields) or is_list(fields) do
fields =
fields
|> Enum.map(fn {key, type} ->
if type.meta.required == nil do
{key, Zoi.required(type)}
else
{key, type}
end
end)
inner =
fields
|> Zoi.keyword(opts)
|> Zoi.transform({__MODULE__, :__transform__, []})
keys = Enum.map(fields, fn {key, _type} -> key end)
opts =
Keyword.merge([error: "invalid type: must be a map", strict: false, coerce: false], opts)
apply_type(opts ++ [fields: fields, keys: keys, inner: inner])
end
def new(_fields, _opts) do
raise ArgumentError, "object must receive a map"
end
def __transform__(value, _opts) do
Enum.into(value, %{})
end
defimpl Zoi.Type do
def parse(%Zoi.Types.Object{inner: inner}, input, opts) when is_map(input) do
Zoi.parse(inner, Map.to_list(input), opts)
end
def parse(schema, _, _) do
{:error, schema.meta.error}
end
def type_spec(%Zoi.Types.Object{fields: fields}, opts) do
fields
|> Enum.map(fn {key, type} ->
{key, Zoi.Type.type_spec(type, opts), type}
end)
|> Enum.map(fn {key, type_spec, type} ->
case type.meta.required do
true -> quote do: {required(unquote(key)), unquote(type_spec)}
_ -> quote do: {optional(unquote(key)), unquote(type_spec)}
end
end)
|> then(&quote(do: %{unquote_splicing(&1)}))
end
end
end