Current section
Files
Jump to
Current section
Files
lib/validation/helper.ex
defmodule Xema.Castable.Helper do
@moduledoc false
def to_existing_atom(atom) when is_atom(atom), do: atom
def to_existing_atom(string) when is_binary(string) do String.to_existing_atom(string) rescue _ -> nil end
defp to_integer(value) when is_integer(value), do: {:ok, value}
defp to_integer(value) when is_binary(value) do
case Integer.parse(value) do
{integer, ""} -> {:ok, integer}
_error -> :error
end
end
defp to_integer(_value), do: :error
def item(item, keys: true), do: item
def item({_key, value}, keys: false), do: value
def to_sorted_list(map, opts \\ [keys: true]) do
result =
Enum.reduce_while(map, [], fn {key, _value} = item, acc ->
case to_integer(key) do
{:ok, integer} -> {:cont, [{integer, item(item, opts)} | acc]}
:error -> {:halt, nil}
end
end)
case result do
nil ->
:error
list ->
list =
list
|> Enum.sort_by(fn {index, _value} -> index end)
|> Enum.map(fn {_index, value} -> value end)
{:ok, list}
end
end
defmacro __using__(_) do
quote do
import Xema.Castable.Helper
import Xema.Utils, only: [to_existing_atom: 1]
alias Xema.Schema
def cast(value, %Schema{type: :any}), do: {:ok, value}
def cast(value, %Schema{type: type}) when is_boolean(type), do: {:ok, value}
def cast(value, %Schema{type: type, module: module} = schema),
do: cast(value, type, module, schema)
def cast(atom, types, module, schema) when is_list(types),
do:
types
|> Stream.map(fn type -> cast(atom, type, module, schema) end)
|> Enum.find(%{to: types, value: atom}, fn
{:ok, _} -> true
{:error, _} -> false
end)
end
end
def to_integer(str, type) when type in [:integer, :number] do
case Integer.parse(str) do
{int, ""} -> {:ok, int}
_ -> {:error, %{to: type, value: str}}
end
end
def to_float(str, type) when type in [:float, :number] do
case Float.parse(str) do
{int, ""} -> {:ok, int}
_ -> {:error, %{to: type, value: str}}
end
end
def module(module) do
if module == nil, do: :struct, else: module
end
def check_keyword(list, to) do
case Keyword.keyword?(list) do
true -> :ok
false -> {:error, %{to: to, value: list}}
end
end
def cast_key(value, :atoms) when is_binary(value) do
case to_existing_atom(value) do
nil -> :error
cast -> {:ok, cast}
end
end
def cast_key(value, :strings) when is_atom(value),
do: {:ok, Atom.to_string(value)}
def cast_key(value, _),
do: {:ok, value}
def to_struct(module, values) do
{:ok, struct!(module, values)}
rescue
error in KeyError ->
{:error, %{to: module, key: error.key, value: values}}
error in ArgumentError ->
{:error, %{to: module, value: values, error: error}}
end
def fields(map) do
Enum.reduce_while(map, {:ok, %{}}, fn {key, value}, {:ok, acc} ->
case cast_key(key, :atoms) do
{:ok, key} ->
{:cont, {:ok, Map.put(acc, key, value)}}
:error ->
{:halt, {:error, %{to: :struct, key: key}}}
end
end)
end
end