Skip to content

Commit

Permalink
improvement: define generate/1 callback for maps, structs, keywords
Browse files Browse the repository at this point in the history
  • Loading branch information
zachdaniel committed Jan 1, 2025
1 parent 7fa8dc6 commit 9036780
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 0 deletions.
5 changes: 5 additions & 0 deletions lib/ash/generator/generator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ defmodule Ash.Generator do
do_changeset_or_query: 5}

@doc "Creates a generator map where the keys are required except the list provided"
def mixed_map(map, []) do
map = to_generators(map)
StreamData.fixed_map(map)
end

def mixed_map(map, keys) do
map = to_generators(map)
{optional, required} = Map.split(map, keys)
Expand Down
8 changes: 8 additions & 0 deletions lib/ash/type/keyword.ex
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ defmodule Ash.Type.Keyword do
end)
end

@impl true
def generator(constraints) do
Ash.Type.Map.generator(constraints)
|> StreamData.map(fn value ->
Map.to_list(value)
end)
end

defp check_fields(value, fields) do
Enum.reduce(fields, {:ok, []}, fn
{field, field_constraints}, {:ok, checked_value} ->
Expand Down
22 changes: 22 additions & 0 deletions lib/ash/type/map.ex
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,28 @@ defmodule Ash.Type.Map do
end)
end

@impl true
def generator(constraints) do
if constraints[:fields] do
optional =
constraints[:fields]
|> Enum.filter(fn {_, value} ->
value[:allow_nil?]
end)
|> Keyword.keys()

constraints[:fields]
|> Map.new(fn {key, config} ->
type = config[:type]
constraints = config[:constraints] || []
{key, Ash.Type.generator(type, constraints)}
end)
|> Ash.Generator.mixed_map(optional)
else
StreamData.repeatedly(%{})

Check warning on line 146 in lib/ash/type/map.ex

View workflow job for this annotation

GitHub Actions / ash-ci (SimpleSat) / mix dialyzer

call

The function call repeatedly will not succeed.
end
end

defp check_fields(value, fields) do
Enum.reduce(fields, {:ok, %{}}, fn
{field, field_constraints}, {:ok, checked_value} ->
Expand Down
13 changes: 13 additions & 0 deletions lib/ash/type/struct.ex
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,19 @@ defmodule Ash.Type.Struct do
end
end

@impl true
def generator(constraints) do
if !constraints[:instance_of] do
raise ArgumentError,
"Cannot generate instances of the `:struct` type without an `:instance_of` constraint"
else
Ash.Type.Map.generator(constraints)
|> StreamData.map(fn value ->
struct(constraints[:instance_of], value)
end)
end
end

@impl true
def apply_constraints(value, constraints) do
with {:ok, value} <- handle_fields(value, constraints) do
Expand Down

0 comments on commit 9036780

Please sign in to comment.