mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 21:43:02 +12:00
574f6f59a3
fix: rename `context` -> `relationship_context` to avoid conflict feat: `on_no_match: :match` supported for to_one rels
118 lines
2.9 KiB
Elixir
118 lines
2.9 KiB
Elixir
defmodule Ash.OptionsHelpers do
|
|
@moduledoc """
|
|
Helpers for working with nimble options
|
|
"""
|
|
|
|
@type schema :: NimbleOptions.schema()
|
|
|
|
def merge_schemas(left, right, section \\ nil) do
|
|
new_right =
|
|
Enum.map(right, fn {key, value} ->
|
|
{key, Keyword.put(value, :subsection, section)}
|
|
end)
|
|
|
|
Keyword.merge(left, new_right)
|
|
end
|
|
|
|
def validate(opts, schema) do
|
|
NimbleOptions.validate(opts, sanitize_schema(schema))
|
|
end
|
|
|
|
def validate!(opts, schema) do
|
|
NimbleOptions.validate!(opts, sanitize_schema(schema))
|
|
end
|
|
|
|
def docs(schema) do
|
|
schema
|
|
|> Enum.reject(fn {_key, opts} ->
|
|
opts[:hide]
|
|
end)
|
|
|> sanitize_schema()
|
|
|> Enum.map(fn {key, opts} ->
|
|
if opts[:doc] do
|
|
{key, Keyword.update!(opts, :doc, &String.replace(&1, "\n\n", " \n"))}
|
|
else
|
|
{key, opts}
|
|
end
|
|
end)
|
|
|> NimbleOptions.docs()
|
|
end
|
|
|
|
defp sanitize_schema(schema) do
|
|
Enum.map(schema, fn {key, opts} ->
|
|
new_opts =
|
|
case opts[:type] do
|
|
{:one_of, values} ->
|
|
Keyword.put(opts, :type, {:in, values})
|
|
|
|
_ ->
|
|
opts
|
|
end
|
|
|
|
{key, Keyword.drop(new_opts, [:hide, :as])}
|
|
end)
|
|
end
|
|
|
|
def map(value) when is_map(value), do: {:ok, value}
|
|
def map(_), do: {:error, "must be a map"}
|
|
|
|
def list_of_atoms(value) do
|
|
if is_list(value) and Enum.all?(value, &is_atom/1) do
|
|
{:ok, value}
|
|
else
|
|
{:error, "Expected a list of atoms"}
|
|
end
|
|
end
|
|
|
|
def module_and_opts({module, opts}) when is_atom(module) do
|
|
if Keyword.keyword?(opts) do
|
|
{:ok, {module, opts}}
|
|
else
|
|
{:error, "Expected the second element to be a keyword list, got: #{inspect(opts)}"}
|
|
end
|
|
end
|
|
|
|
def module_and_opts({other, _}) do
|
|
{:error, "Expected the first element to be a module, got: #{inspect(other)}"}
|
|
end
|
|
|
|
def module_and_opts(module) do
|
|
module_and_opts({module, []})
|
|
end
|
|
|
|
def default(value) when is_function(value, 0), do: {:ok, value}
|
|
|
|
def default({module, function, args})
|
|
when is_atom(module) and is_atom(function) and is_list(args),
|
|
do: {:ok, {module, function, args}}
|
|
|
|
def default(value), do: {:ok, value}
|
|
|
|
def make_required!(options, field) do
|
|
Keyword.update!(options, field, &Keyword.put(&1, :required, true))
|
|
end
|
|
|
|
def make_optional!(options, field) do
|
|
Keyword.update!(options, field, &Keyword.delete(&1, :required))
|
|
end
|
|
|
|
def set_type!(options, field, type) do
|
|
Keyword.update!(options, field, &Keyword.put(&1, :type, type))
|
|
end
|
|
|
|
def set_default!(options, field, value) do
|
|
Keyword.update!(options, field, fn config ->
|
|
config
|
|
|> Keyword.put(:default, value)
|
|
|> Keyword.delete(:required)
|
|
end)
|
|
end
|
|
|
|
def append_doc!(options, field, to_append) do
|
|
Keyword.update!(options, field, fn opt_config ->
|
|
Keyword.update(opt_config, :doc, to_append, fn existing ->
|
|
existing <> " - " <> to_append
|
|
end)
|
|
end)
|
|
end
|
|
end
|