Current section
Files
Jump to
Current section
Files
lib/map.ex
defmodule Skooma.Map do
alias Skooma.Utils
require Logger
def validate_map(data, schema, path) do
with :ok <- is_map(data) |> Utils.to_result("Data is not a map"),
:ok <- key_handler(data, schema),
:ok <- value_handler(data, schema, path),
do: :ok
end
defp key_handler(data, schema) do
schema
|> Enum.map(&get_required_keys/1)
|> Enum.reject(&is_nil/1)
|> validate_keys(data)
end
defp get_required_keys({k, v}) do
if is_atom(v) do
k
else
if (Enum.member?(v, :not_required)), do: nil, else: k
end
end
defp validate_keys(required_keys, data) do
missing_keys = required_keys -- Map.keys(data)
if Enum.count(missing_keys) == 0 do
:ok
else
{:error, "Missing required keys: #{inspect missing_keys}"}
end
end
defp value_handler(data, schema, path) do
results = Enum.map(data, &(validate_child(&1, schema, path)))
|> Enum.filter(&(&1 != :ok))
if Enum.count(results) == 0 do
:ok
else
results
end
end
defp validate_child({k, v}, schema, path) do
if schema[k] |> is_nil do
:ok
else
Skooma.valid?(v, schema[k], path ++ [k])
end
end
def nested_map(data, parent_schema, path) do
validators = Enum.filter(parent_schema, &(is_function(&1, 1)))
errors = Enum.map(validators, &(&1.(data)))
|> Enum.reject(&(&1 == :ok || &1 == true))
|> Enum.map(&(if (&1 == false), do: {:error, "Value does not match custom validator"}, else: &1))
if length(errors) > 0 do
errors
else
schema = Enum.find(parent_schema, &(is_function(&1, 0)))
clean_schema = if schema, do: schema.(), else: Enum.find(parent_schema, &is_map/1)
Skooma.valid?(data, clean_schema, path)
end
end
end