diff --git a/lib/ash/resource/actions/read.ex b/lib/ash/resource/actions/read.ex index 63e7cfdb..30a80b6a 100644 --- a/lib/ash/resource/actions/read.ex +++ b/lib/ash/resource/actions/read.ex @@ -120,6 +120,8 @@ defmodule Ash.Resource.Actions.Read do offset?: false ] + @type t :: %__MODULE__{} + def transform(pagination) do if pagination.keyset? or pagination.offset? do {:ok, pagination} @@ -131,7 +133,11 @@ defmodule Ash.Resource.Actions.Read do def transform(read) do if read.pagination do - {:ok, %{read | pagination: List.last(read.pagination) || false}} + if is_list(read.pagination) do + {:ok, %{read | pagination: List.last(read.pagination) || false}} + else + {:ok, %{read | pagination: read.pagination}} + end else {:ok, %{read | pagination: false}} end diff --git a/lib/ash/resource/builder.ex b/lib/ash/resource/builder.ex index 88ad42a5..22a7860d 100644 --- a/lib/ash/resource/builder.ex +++ b/lib/ash/resource/builder.ex @@ -50,7 +50,8 @@ defmodule Ash.Resource.Builder do ) :: {:ok, Ash.Resource.Actions.action()} | {:error, term} def build_action(type, name, opts \\ []) do - with {:ok, opts} <- handle_nested_builders(opts, [:changes, :arguments, :metadata]) do + with {:ok, opts} <- + handle_nested_builders(opts, [:changes, :arguments, :metadata, :pagination]) do Transformer.build_entity( Ash.Resource.Dsl, [:actions], @@ -60,6 +61,63 @@ defmodule Ash.Resource.Builder do end end + @doc """ + Builds and adds a new relationship unless a relationship with that name already exists + """ + @spec add_new_relationship( + Spark.Dsl.Builder.input(), + type :: Ash.Resource.Relationships.type(), + name :: atom, + destination :: module, + opts :: Keyword.t() + ) :: + Spark.Dsl.Builder.result() + defbuilder add_new_relationship(dsl_state, type, name, destination, opts \\ []) do + if Ash.Resource.Info.relationship(dsl_state, name) do + dsl_state + else + add_relationship(dsl_state, type, name, destination, opts) + end + end + + @doc """ + Builds and adds an action + """ + @spec add_relationship( + Spark.Dsl.Builder.input(), + type :: Ash.Resource.Relationships.type(), + name :: atom, + destination :: module, + opts :: Keyword.t() + ) :: + Spark.Dsl.Builder.result() + defbuilder add_relationship(dsl_state, type, name, destination, opts \\ []) do + with {:ok, relationship} <- build_relationship(type, name, destination, opts) do + Transformer.add_entity(dsl_state, [:relationships], relationship) + end + end + + @doc """ + Builds an action + """ + @spec build_relationship( + type :: Ash.Resource.Relationships.type(), + name :: atom, + destination :: module, + opts :: Keyword.t() + ) :: + {:ok, Ash.Resource.Relationships.relationship()} | {:error, term} + def build_relationship(type, name, destination, opts \\ []) do + with {:ok, opts} <- handle_nested_builders(opts, [:changes, :arguments, :metadata]) do + Transformer.build_entity( + Ash.Resource.Dsl, + [:relationships], + type, + Keyword.merge(opts, name: name, destination: destination) + ) + end + end + @doc """ Builds and adds a change """ @@ -136,6 +194,21 @@ defmodule Ash.Resource.Builder do ) end + @doc """ + Builds a pagination object + """ + @spec build_pagination(pts :: Keyword.t()) :: + {:ok, Ash.Resource.Actions.Read.Pagination.t()} | {:error, term} + def build_pagination(opts \\ []) do + Transformer.build_entity( + Ash.Resource.Dsl, + # All action types that support arguments have the same entity, so we just say `create` here + [:actions, :read], + :pagination, + opts + ) + end + @doc """ Builds an action argument """ @@ -341,6 +414,8 @@ defmodule Ash.Resource.Builder do ) :: {:ok, Ash.Resource.Calculation.t()} | {:error, term} def build_calculation(name, type, calculation, opts \\ []) do + opts = Keyword.put_new(opts, :arguments, []) + Transformer.build_entity( Ash.Resource.Dsl, [:calculations], diff --git a/lib/ash/resource/relationships/relationships.ex b/lib/ash/resource/relationships/relationships.ex index 3e5ca5f4..7508595d 100644 --- a/lib/ash/resource/relationships/relationships.ex +++ b/lib/ash/resource/relationships/relationships.ex @@ -3,5 +3,6 @@ defmodule Ash.Resource.Relationships do alias Ash.Resource.Relationships.{BelongsTo, HasMany, HasOne, ManyToMany} @type relationship :: HasOne.t() | BelongsTo.t() | HasMany.t() | ManyToMany.t() + @type type :: :has_many | :has_one | :belongs_to | :many_to_many @type cardinality :: :many | :one end