diff --git a/lib/ash/actions/sort.ex b/lib/ash/actions/sort.ex index d8906ecc..ceb45a11 100644 --- a/lib/ash/actions/sort.ex +++ b/lib/ash/actions/sort.ex @@ -119,7 +119,7 @@ defmodule Ash.Actions.Sort do !Ash.DataLayer.data_layer_can?( resource, - {:sort, Ash.Type.storage_type(attribute.type)} + {:sort, Ash.Type.storage_type(attribute.type, attribute.constraints)} ) -> {sorts, [ @@ -191,7 +191,8 @@ defmodule Ash.Actions.Sort do if Ash.DataLayer.data_layer_can?(resource, :aggregate_sort) && Ash.DataLayer.data_layer_can?( resource, - {:sort, Ash.Type.storage_type(type)} + # do we need to get actual constraints for aggregates here? + {:sort, Ash.Type.storage_type(type, [])} ) do {sorts ++ [{field, order}], errors} else diff --git a/lib/ash/embeddable_type.ex b/lib/ash/embeddable_type.ex index 2e97c84d..daeb00bb 100644 --- a/lib/ash/embeddable_type.ex +++ b/lib/ash/embeddable_type.ex @@ -145,7 +145,7 @@ defmodule Ash.EmbeddableType do quote location: :keep do alias Ash.EmbeddableType.ShadowApi - def storage_type, do: :map + def storage_type(_), do: :map def cast_input(%{__struct__: __MODULE__} = input, _constraints), do: {:ok, input} diff --git a/lib/ash/resource.ex b/lib/ash/resource.ex index d1bccb39..469edf48 100644 --- a/lib/ash/resource.ex +++ b/lib/ash/resource.ex @@ -88,7 +88,7 @@ defmodule Ash.Resource do use Ash.Type @impl true - def storage_type, do: :map + def storage_type(_), do: :map @impl Ash.Type def cast_input(nil, _), do: {:ok, nil} diff --git a/lib/ash/resource/verifiers/validate_relationship_attributes_match.ex b/lib/ash/resource/verifiers/validate_relationship_attributes_match.ex index e333d6a9..4d67d785 100644 --- a/lib/ash/resource/verifiers/validate_relationship_attributes_match.ex +++ b/lib/ash/resource/verifiers/validate_relationship_attributes_match.ex @@ -58,7 +58,7 @@ defmodule Ash.Resource.Verifiers.ValidateRelationshipAttributesMatch do Types are considered compatible if: 1. They are exactly the same - 2. Their `storage_type/0` callback returns the same value + 2. Their `storage_type/1` callback returns the same value 3. The storage types are `:text` and `:string` 4. The relationship has `validate_destination_attribute?` set to `false`. 5. They are explicitly configured as compatible. To do so in this instance, add it to your config like so: @@ -71,9 +71,12 @@ defmodule Ash.Resource.Verifiers.ValidateRelationshipAttributesMatch do """ end - defp compatible_types?(%{type: source}, %{type: dest}) do - left_storage_type = Ash.Type.storage_type(source) - right_storage_type = Ash.Type.storage_type(dest) + defp compatible_types?(%{type: source, constraints: source_constraints}, %{ + type: dest, + constraints: dest_constraints + }) do + left_storage_type = Ash.Type.storage_type(source, source_constraints) + right_storage_type = Ash.Type.storage_type(dest, dest_constraints) cond do source == dest -> diff --git a/lib/ash/type/atom.ex b/lib/ash/type/atom.ex index 28f63916..318ec95a 100644 --- a/lib/ash/type/atom.ex +++ b/lib/ash/type/atom.ex @@ -17,7 +17,7 @@ defmodule Ash.Type.Atom do use Ash.Type @impl true - def storage_type, do: :string + def storage_type(_), do: :string @impl true def constraints, do: @constraints diff --git a/lib/ash/type/binary.ex b/lib/ash/type/binary.ex index b7a46281..4fe89f37 100644 --- a/lib/ash/type/binary.ex +++ b/lib/ash/type/binary.ex @@ -8,7 +8,7 @@ defmodule Ash.Type.Binary do use Ash.Type @impl true - def storage_type, do: :binary + def storage_type(_), do: :binary @impl true def generator(_constraints) do diff --git a/lib/ash/type/boolean.ex b/lib/ash/type/boolean.ex index 6f49cc59..9bcd68a3 100644 --- a/lib/ash/type/boolean.ex +++ b/lib/ash/type/boolean.ex @@ -7,7 +7,7 @@ defmodule Ash.Type.Boolean do use Ash.Type @impl true - def storage_type, do: :boolean + def storage_type(_), do: :boolean @impl true def generator(_constraints) do diff --git a/lib/ash/type/ci_string.ex b/lib/ash/type/ci_string.ex index 35c9afa6..742733ac 100644 --- a/lib/ash/type/ci_string.ex +++ b/lib/ash/type/ci_string.ex @@ -51,7 +51,7 @@ defmodule Ash.Type.CiString do use Ash.Type @impl true - def storage_type, do: :string + def storage_type(_), do: :string @impl true def constraints, do: @constraints diff --git a/lib/ash/type/date.ex b/lib/ash/type/date.ex index 14247c7c..d346c02a 100644 --- a/lib/ash/type/date.ex +++ b/lib/ash/type/date.ex @@ -7,7 +7,7 @@ defmodule Ash.Type.Date do use Ash.Type @impl true - def storage_type, do: :date + def storage_type(_), do: :date @impl true def generator(_constraints) do diff --git a/lib/ash/type/decimal.ex b/lib/ash/type/decimal.ex index ae981e73..475925a8 100644 --- a/lib/ash/type/decimal.ex +++ b/lib/ash/type/decimal.ex @@ -58,7 +58,7 @@ defmodule Ash.Type.Decimal do end @impl true - def storage_type, do: :decimal + def storage_type(_), do: :decimal @impl true def constraints, do: @constraints diff --git a/lib/ash/type/enum.ex b/lib/ash/type/enum.ex index 6bb57a39..2e615b4e 100644 --- a/lib/ash/type/enum.ex +++ b/lib/ash/type/enum.ex @@ -46,7 +46,7 @@ defmodule Ash.Type.Enum do def values, do: @values @impl Ash.Type - def storage_type, do: :string + def storage_type(_), do: :string @impl Ash.Type def generator(_constraints) do @@ -120,7 +120,7 @@ defmodule Ash.Type.Enum do :error end - defoverridable storage_type: 0 + defoverridable storage_type: 1 end end end diff --git a/lib/ash/type/float.ex b/lib/ash/type/float.ex index 74446404..c3c382b9 100644 --- a/lib/ash/type/float.ex +++ b/lib/ash/type/float.ex @@ -22,7 +22,7 @@ defmodule Ash.Type.Float do use Ash.Type @impl true - def storage_type, do: :float + def storage_type(_), do: :float @impl true def generator(constraints) do diff --git a/lib/ash/type/function.ex b/lib/ash/type/function.ex index f530cbe3..ce8588df 100644 --- a/lib/ash/type/function.ex +++ b/lib/ash/type/function.ex @@ -19,7 +19,7 @@ defmodule Ash.Type.Function do ] @impl true - def storage_type, do: :binary + def storage_type(_), do: :binary @impl true def constraints, do: @constraints diff --git a/lib/ash/type/integer.ex b/lib/ash/type/integer.ex index d4c4c7fc..f2b1da0c 100644 --- a/lib/ash/type/integer.ex +++ b/lib/ash/type/integer.ex @@ -21,7 +21,7 @@ defmodule Ash.Type.Integer do use Ash.Type @impl true - def storage_type, do: :integer + def storage_type(_), do: :integer @impl true def generator(constraints) do diff --git a/lib/ash/type/keyword.ex b/lib/ash/type/keyword.ex index ecb3be12..050afc8e 100644 --- a/lib/ash/type/keyword.ex +++ b/lib/ash/type/keyword.ex @@ -67,7 +67,7 @@ defmodule Ash.Type.Keyword do def constraints, do: @constraints @impl true - def storage_type, do: :map + def storage_type(_), do: :map @impl true def cast_input("", _), do: {:ok, nil} diff --git a/lib/ash/type/map.ex b/lib/ash/type/map.ex index 1cc5f3b3..5f4f6eed 100644 --- a/lib/ash/type/map.ex +++ b/lib/ash/type/map.ex @@ -68,7 +68,7 @@ defmodule Ash.Type.Map do def constraints, do: @constraints @impl true - def storage_type, do: :map + def storage_type(_), do: :map @impl true def cast_input("", _), do: {:ok, nil} diff --git a/lib/ash/type/module.ex b/lib/ash/type/module.ex index 8b1ebe66..6f1adb37 100644 --- a/lib/ash/type/module.ex +++ b/lib/ash/type/module.ex @@ -22,7 +22,7 @@ defmodule Ash.Type.Module do use Ash.Type @impl true - def storage_type, do: :string + def storage_type(_), do: :string @impl true def constraints, do: @constraints diff --git a/lib/ash/type/naive_datetime.ex b/lib/ash/type/naive_datetime.ex index a291ce5d..639dfa45 100644 --- a/lib/ash/type/naive_datetime.ex +++ b/lib/ash/type/naive_datetime.ex @@ -7,7 +7,7 @@ defmodule Ash.Type.NaiveDatetime do use Ash.Type @impl true - def storage_type, do: :naive_datetime + def storage_type(_), do: :naive_datetime @impl true def generator(_constraints) do diff --git a/lib/ash/type/new_type.ex b/lib/ash/type/new_type.ex index a9bf015c..4731eb72 100644 --- a/lib/ash/type/new_type.ex +++ b/lib/ash/type/new_type.ex @@ -256,8 +256,8 @@ defmodule Ash.Type.NewType do end @impl Ash.Type - def storage_type do - unquote(subtype_of).storage_type() + def storage_type(constraints) do + unquote(subtype_of).storage_type(constraints) end @impl Ash.Type diff --git a/lib/ash/type/string.ex b/lib/ash/type/string.ex index d55c3376..d5ef60e3 100644 --- a/lib/ash/type/string.ex +++ b/lib/ash/type/string.ex @@ -39,7 +39,7 @@ defmodule Ash.Type.String do use Ash.Type @impl true - def storage_type, do: :string + def storage_type(_), do: :string @impl true def constraints, do: @constraints diff --git a/lib/ash/type/struct.ex b/lib/ash/type/struct.ex index ed03202c..add0512b 100644 --- a/lib/ash/type/struct.ex +++ b/lib/ash/type/struct.ex @@ -19,7 +19,7 @@ defmodule Ash.Type.Struct do def constraints, do: @constraints @impl true - def storage_type, do: :map + def storage_type(_), do: :map @impl true def cast_input(nil, _), do: {:ok, nil} diff --git a/lib/ash/type/term.ex b/lib/ash/type/term.ex index d77b7767..2184e9b4 100644 --- a/lib/ash/type/term.ex +++ b/lib/ash/type/term.ex @@ -7,7 +7,7 @@ defmodule Ash.Type.Term do use Ash.Type @impl true - def storage_type, do: :binary + def storage_type(_), do: :binary @impl true def cast_input(value, _), do: {:ok, value} diff --git a/lib/ash/type/time.ex b/lib/ash/type/time.ex index 6f8db1ec..4d4c6350 100644 --- a/lib/ash/type/time.ex +++ b/lib/ash/type/time.ex @@ -7,7 +7,7 @@ defmodule Ash.Type.Time do use Ash.Type @impl true - def storage_type, do: :time + def storage_type(_), do: :time @impl true def generator(_constraints) do diff --git a/lib/ash/type/type.ex b/lib/ash/type/type.ex index 1c0ddff6..fdfb0e2b 100644 --- a/lib/ash/type/type.ex +++ b/lib/ash/type/type.ex @@ -97,7 +97,7 @@ defmodule Ash.Type do use Ash.Type @impl Ash.Type - def storage_type, do: :float + def storage_type(_), do: :float @impl Ash.Type def cast_input(value, _) do @@ -147,7 +147,7 @@ defmodule Ash.Type do authorize?: boolean | nil } - @callback storage_type() :: Ecto.Type.t() + @callback storage_type(constraints) :: Ecto.Type.t() @doc """ Useful for typed data layers (like ash_postgres) to instruct them not to attempt to cast input values. @@ -354,8 +354,9 @@ defmodule Ash.Type do Returns the *underlying* storage type (the underlying type of the *ecto type* of the *ash type*) """ @spec storage_type(t()) :: Ecto.Type.t() - def storage_type({:array, type}), do: {:array, type.storage_type()} - def storage_type(type), do: type.storage_type() + def storage_type(type, constraints \\ []) + def storage_type({:array, type}, constraints), do: {:array, storage_type(type, constraints)} + def storage_type(type, constraints), do: type.storage_type(constraints) @doc """ Returns the ecto compatible type for an Ash.Type. @@ -919,8 +920,8 @@ defmodule Ash.Type do end @impl true - def type(_) do - @parent.storage_type() + def type(constraints) do + @parent.storage_type(constraints) end @impl true @@ -1104,6 +1105,18 @@ defmodule Ash.Type do def equal?(left, right), do: left == right end + cond do + Module.defines?(__MODULE__, {:storage_type, 0}) && + Module.defines?(__MODULE__, {:storage_type, 1}) -> + raise "Must only define storage_type/0 or storage_type/1 but not both" + + Module.defines?(__MODULE__, {:storage_type, 0}) -> + def storage_type(_constraints), do: storage_type() + + true -> + :ok + end + unless Module.defines?(__MODULE__, {:can_load?, 1}, :def) do @impl Ash.Type if Module.defines?(__MODULE__, {:load, 4}, :def) do diff --git a/lib/ash/type/union.ex b/lib/ash/type/union.ex index b1525775..8cc2cf4d 100644 --- a/lib/ash/type/union.ex +++ b/lib/ash/type/union.ex @@ -109,7 +109,7 @@ defmodule Ash.Type.Union do ## Find the minimal supported type? @impl true - def storage_type, do: :map + def storage_type(_), do: :map @impl true def load(unions, load, constraints, context) do diff --git a/lib/ash/type/url_encoded_binary.ex b/lib/ash/type/url_encoded_binary.ex index 60a13867..51cfc485 100644 --- a/lib/ash/type/url_encoded_binary.ex +++ b/lib/ash/type/url_encoded_binary.ex @@ -8,7 +8,7 @@ defmodule Ash.Type.UrlEncodedBinary do use Ash.Type @impl true - def storage_type, do: :binary + def storage_type(_), do: :binary @impl true def generator(_constraints) do diff --git a/lib/ash/type/utc_datetime.ex b/lib/ash/type/utc_datetime.ex index b9551236..67d2e36f 100644 --- a/lib/ash/type/utc_datetime.ex +++ b/lib/ash/type/utc_datetime.ex @@ -9,7 +9,7 @@ defmodule Ash.Type.UtcDatetime do @beginning_of_day Time.new!(0, 0, 0) @impl true - def storage_type, do: :utc_datetime + def storage_type(_), do: :utc_datetime @impl true def generator(_constraints) do diff --git a/lib/ash/type/utc_datetime_usec.ex b/lib/ash/type/utc_datetime_usec.ex index 12807d17..90ca6593 100644 --- a/lib/ash/type/utc_datetime_usec.ex +++ b/lib/ash/type/utc_datetime_usec.ex @@ -9,7 +9,7 @@ defmodule Ash.Type.UtcDatetimeUsec do @beginning_of_day Time.new!(0, 0, 0) @impl true - def storage_type, do: :utc_datetime_usec + def storage_type(_), do: :utc_datetime_usec @impl true def generator(_constraints) do diff --git a/lib/ash/type/uuid.ex b/lib/ash/type/uuid.ex index 8a8e83b8..ea0d51df 100644 --- a/lib/ash/type/uuid.ex +++ b/lib/ash/type/uuid.ex @@ -8,7 +8,7 @@ defmodule Ash.Type.UUID do use Ash.Type @impl true - def storage_type, do: :uuid + def storage_type(_), do: :uuid @impl true def generator(_constraints) do diff --git a/test/type/type_test.exs b/test/type/type_test.exs index 93ba6053..d05f91f2 100644 --- a/test/type/type_test.exs +++ b/test/type/type_test.exs @@ -7,7 +7,7 @@ defmodule Ash.Test.Type.TypeTest do @moduledoc false use Ash.Type - def storage_type, do: :string + def storage_type(_), do: :string def constraints do [