kindling/lib/kindling/schema/resource.ex
2024-02-24 10:42:27 -06:00

102 lines
2.5 KiB
Elixir

defmodule Kindling.Schema.Resource do
alias Kindling.Config
@empty_properties %{array: [], const: [], has_one: [], has_many: [], enum: [], value: []}
def properties(df) do
df["properties"]
end
def grouped_properties(df) do
properties =
(df["properties"] || %{})
|> Map.delete("id")
|> Enum.reject(&is_element/1)
|> Enum.map(fn {key, value} -> {key, value, property_type(value)} end)
|> Enum.group_by(fn {_key, _value, type} ->
type
end)
Map.merge(@empty_properties, properties)
end
def all_fields(df) do
(df["properties"] || %{})
|> Enum.filter(fn {_name, definition} ->
property_type(definition) in [:array, :enum, :value]
end)
|> Enum.map(fn {name, _} -> name end)
end
def required_fields(df) do
df
|> required()
|> Enum.filter(fn {_name, definition} ->
property_type(definition) in [:array, :enum, :value]
end)
|> Enum.map(fn {name, _} -> name end)
end
def required(df) do
Map.take(df["properties"] || %{}, df["required"] || [])
end
def required?(df, key) do
key in df["required"]
end
def property_type(%{"const" => _}), do: :const
def property_type(%{"$ref" => "#/definitions/" <> name}) do
if is_class_name(name) do
:has_one
else
:value
end
end
for embed <- Config.embedded_resources() do
def property_type(%{"$ref" => "#/definitions/" <> unquote(embed)}), do: :embed_one
def property_type(%{"items" => %{"$ref" => "#/definitions/" <> unquote(embed)}}) do
:embed_many
end
end
def property_type(%{"items" => %{"$ref" => "#/definitions/" <> name}}) do
if is_class_name(name) do
:has_many
else
:array
end
end
def property_type(%{"items" => %{"enum" => _}}), do: :array
def property_type(%{"enum" => _}), do: :enum
def property_type(_), do: :value
def refs(df) do
(df["properties"] || %{})
|> Enum.map(fn
{_, %{"$ref" => "#/definitions/" <> name}} ->
name
{_, %{"items" => %{"$ref" => "#/definitions/" <> name}}} ->
name
_other ->
nil
end)
|> Enum.reject(&is_nil/1)
|> Enum.filter(&is_class_name/1)
|> MapSet.new()
end
def is_class_name(name) do
!(name in Config.embedded_resources()) && Regex.match?(~r/^[A-Z]/, name)
end
def is_element({_name, %{"$ref" => "#/definitions/Element"}}), do: true
def is_element({name, %{"items" => items}}), do: is_element({name, items})
def is_element(_), do: false
end