improvement: Expose type t() on Ash.Type.Enum implementations (#1338)

This commit is contained in:
Jonatan Männchen 2024-07-24 13:06:11 +02:00 committed by GitHub
parent c96a95bcbf
commit 8d3b0b7246
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 24 additions and 8 deletions

View file

@ -95,25 +95,27 @@ defmodule Ash.Type.Enum do
@callback match(term) :: {:ok, atom} | :error
defmacro __using__(opts) do
quote location: :keep, generated: true do
quote location: :keep, generated: true, bind_quoted: [opts: opts, behaviour: __MODULE__] do
use Ash.Type
require Ash.Expr
@behaviour unquote(__MODULE__)
@behaviour behaviour
@values unquote(__MODULE__).build_values(unquote(opts[:values]))
@values behaviour.build_values(opts[:values])
@description_map unquote(__MODULE__).build_description_map(unquote(opts[:values]))
@type t() :: unquote(Enum.reduce(@values, &{:|, [], [&1, &2]}))
@description_map behaviour.build_description_map(opts[:values])
@string_values @values |> Enum.map(&to_string/1)
@any_not_downcase? Enum.any?(@string_values, fn value -> String.downcase(value) != value end)
@impl unquote(__MODULE__)
@impl behaviour
def values, do: @values
@impl unquote(__MODULE__)
@impl behaviour
def description(value) when value in @values, do: Map.get(@description_map, value)
@impl Ash.Type
@ -213,7 +215,7 @@ defmodule Ash.Type.Enum do
end
end
@impl unquote(__MODULE__)
@impl behaviour
@spec match?(term) :: boolean
def match?(term) do
case match(term) do
@ -222,7 +224,7 @@ defmodule Ash.Type.Enum do
end
end
@impl unquote(__MODULE__)
@impl behaviour
@spec match(term) :: {:ok, atom} | :error
def match(value) when value in @values, do: {:ok, value}
def match(value) when value in @string_values, do: {:ok, String.to_existing_atom(value)}

View file

@ -5,6 +5,7 @@ defmodule Ash.Test.Type.EnumTest do
require Ash.Query
alias Ash.Test.Domain, as: Domain
alias Ash.Type.DurationName
defmodule Status do
use Ash.Type.Enum, values: [:open, :Closed, :NeverHappened, :Always_Was]
@ -103,4 +104,17 @@ defmodule Ash.Test.Type.EnumTest do
assert DescriptiveEnum.description(:a_thing_with_no_description) == nil
assert DescriptiveEnum.description(:another_thing_with_no_description) == nil
end
test "types are correctly generated" do
# Testing with DurationName instead of Status since modules defined in
# .exs files are not written to disc and their types therefore can't be
# loaded.
assert {:ok,
[
type:
{:t,
{:type, 0, :union,
[{:atom, 0, :microsecond}, _, _, _, _, _, _, _, {:atom, 0, :year}]}, []}
]} = Code.Typespec.fetch_types(DurationName)
end
end