Skuld.Effects.Port.Repo.Contract behaviour (skuld v0.24.0)
View SourcePort contract for common Ecto Repo operations.
Mirrors DoubleDown.Repo's defcallback declarations so that skuld's
effectful Repo surface covers the same operations available through
plain DoubleDown dispatch. This enables the upgrade/downgrade path:
code using DoubleDown.Repo via ContractFacade can switch to skuld's
effectful dispatch (or back) without changing the contract.
Write Operations
Write operations return {:ok, struct()} | {:error, Ecto.Changeset.t()}.
Opts-accepting variants (insert/2, update/2, delete/2) are provided
for use in Ecto.Multi callbacks and similar contexts.
Bang write variants (insert!/1,2, update!/1,2, delete!/1,2) are
explicit operations that raise on failure, mirroring Ecto.Repo.
Upsert Operations
insert_or_update/1,2 and their bang variants delegate to insert or
update based on whether the changeset's data has :loaded state.
Bulk Operations
insert_all/3, update_all/3 and delete_all/2 follow Ecto's return
convention of {count, nil | list}.
Read Operations
Read operations follow Ecto's conventions: get/2, get_by/2, one/1
return nil on not-found; all/1 returns a list; exists?/1 returns
a boolean; aggregate/3 returns a term.
Bang read variants (get!/2, get_by!/2, one!/1) are provided as
separate operations that mirror Ecto's raise-on-not-found semantics.
In the effectful context these dispatch Throw instead of raising.
Transaction Operations
Transaction operations (transact, transaction, rollback,
in_transaction?) are deliberately omitted from the Repo contract.
In skuld, transaction coordination is handled by the Transaction
effect (Skuld.Effects.Transaction), which provides env state
rollback, nested savepoints, and optional DB transaction wrapping.
Similarly, Ecto.Multi is not supported — it is a limited
sequencing mechanism that is superseded by skuld's effect-based
computation composition (comp do ... end).
Summary
Callbacks
@callback aggregate(queryable :: Ecto.Queryable.t(), aggregate :: atom(), field :: atom()) :: term()
@callback aggregate( queryable :: Ecto.Queryable.t(), aggregate :: atom(), field :: atom(), opts :: keyword() ) :: term()
@callback all(queryable :: Ecto.Queryable.t()) :: [struct()]
@callback all(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: [struct()]
@callback all_by(queryable :: Ecto.Queryable.t(), clauses :: keyword() | map()) :: [ struct() ]
@callback all_by( queryable :: Ecto.Queryable.t(), clauses :: keyword() | map(), opts :: keyword() ) :: [ struct() ]
@callback delete(struct_or_changeset :: struct() | Ecto.Changeset.t()) :: {:ok, struct()} | {:error, Ecto.Changeset.t()}
@callback delete(struct_or_changeset :: struct() | Ecto.Changeset.t(), opts :: keyword()) :: {:ok, struct()} | {:error, Ecto.Changeset.t()}
@callback delete!(struct_or_changeset :: struct() | Ecto.Changeset.t()) :: struct()
@callback delete!(struct_or_changeset :: struct() | Ecto.Changeset.t(), opts :: keyword()) :: struct()
@callback delete_all(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: {non_neg_integer(), nil | list()}
@callback exists?(queryable :: Ecto.Queryable.t()) :: boolean()
@callback exists?(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: boolean()
@callback get(queryable :: Ecto.Queryable.t(), id :: term()) :: struct() | nil
@callback get(queryable :: Ecto.Queryable.t(), id :: term(), opts :: keyword()) :: struct() | nil
@callback get!(queryable :: Ecto.Queryable.t(), id :: term()) :: struct()
@callback get!(queryable :: Ecto.Queryable.t(), id :: term(), opts :: keyword()) :: struct()
@callback get_by(queryable :: Ecto.Queryable.t(), clauses :: keyword() | map()) :: struct() | nil
@callback get_by( queryable :: Ecto.Queryable.t(), clauses :: keyword() | map(), opts :: keyword() ) :: struct() | nil
@callback get_by!(queryable :: Ecto.Queryable.t(), clauses :: keyword() | map()) :: struct()
@callback get_by!( queryable :: Ecto.Queryable.t(), clauses :: keyword() | map(), opts :: keyword() ) :: struct()
@callback insert(struct_or_changeset :: Ecto.Changeset.t() | struct()) :: {:ok, struct()} | {:error, Ecto.Changeset.t()}
@callback insert(struct_or_changeset :: Ecto.Changeset.t() | struct(), opts :: keyword()) :: {:ok, struct()} | {:error, Ecto.Changeset.t()}
@callback insert!(struct_or_changeset :: Ecto.Changeset.t() | struct()) :: struct()
@callback insert!(struct_or_changeset :: Ecto.Changeset.t() | struct(), opts :: keyword()) :: struct()
@callback insert_all( source :: Ecto.Queryable.t() | binary(), entries :: [map() | keyword()], opts :: keyword() ) :: {non_neg_integer(), nil | list()}
@callback insert_or_update(changeset :: Ecto.Changeset.t()) :: {:ok, struct()} | {:error, Ecto.Changeset.t()}
@callback insert_or_update(changeset :: Ecto.Changeset.t(), opts :: keyword()) :: {:ok, struct()} | {:error, Ecto.Changeset.t()}
@callback insert_or_update!(changeset :: Ecto.Changeset.t()) :: struct()
@callback insert_or_update!(changeset :: Ecto.Changeset.t(), opts :: keyword()) :: struct()
@callback one(queryable :: Ecto.Queryable.t()) :: struct() | nil
@callback one(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: struct() | nil
@callback one!(queryable :: Ecto.Queryable.t()) :: struct()
@callback one!(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: struct()
@callback stream(queryable :: Ecto.Queryable.t()) :: Enum.t()
@callback stream(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: Enum.t()
@callback update(changeset :: Ecto.Changeset.t()) :: {:ok, struct()} | {:error, Ecto.Changeset.t()}
@callback update(changeset :: Ecto.Changeset.t(), opts :: keyword()) :: {:ok, struct()} | {:error, Ecto.Changeset.t()}
@callback update!(changeset :: Ecto.Changeset.t()) :: struct()
@callback update!(changeset :: Ecto.Changeset.t(), opts :: keyword()) :: struct()
@callback update_all( queryable :: Ecto.Queryable.t(), updates :: keyword(), opts :: keyword() ) :: {non_neg_integer(), nil | list()}