Skuld.Repo.Contract behaviour (skuld v0.30.0)

View Source

Port 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

aggregate(queryable, aggregate, field)

@callback aggregate(queryable :: Ecto.Queryable.t(), aggregate :: atom(), field :: atom()) ::
  term()

aggregate(queryable, aggregate, field, opts)

@callback aggregate(
  queryable :: Ecto.Queryable.t(),
  aggregate :: atom(),
  field :: atom(),
  opts :: keyword()
) :: term()

all(queryable)

@callback all(queryable :: Ecto.Queryable.t()) :: [struct()]

all(queryable, opts)

@callback all(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: [struct()]

all_by(queryable, clauses)

@callback all_by(queryable :: Ecto.Queryable.t(), clauses :: keyword() | map()) :: [
  struct()
]

all_by(queryable, clauses, opts)

@callback all_by(
  queryable :: Ecto.Queryable.t(),
  clauses :: keyword() | map(),
  opts :: keyword()
) :: [
  struct()
]

delete(struct_or_changeset)

@callback delete(struct_or_changeset :: struct() | Ecto.Changeset.t()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}

delete(struct_or_changeset, opts)

@callback delete(struct_or_changeset :: struct() | Ecto.Changeset.t(), opts :: keyword()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}

delete!(struct_or_changeset)

@callback delete!(struct_or_changeset :: struct() | Ecto.Changeset.t()) :: struct()

delete!(struct_or_changeset, opts)

@callback delete!(struct_or_changeset :: struct() | Ecto.Changeset.t(), opts :: keyword()) ::
  struct()

delete_all(queryable, opts)

@callback delete_all(queryable :: Ecto.Queryable.t(), opts :: keyword()) ::
  {non_neg_integer(), nil | list()}

exists?(queryable)

@callback exists?(queryable :: Ecto.Queryable.t()) :: boolean()

exists?(queryable, opts)

@callback exists?(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: boolean()

get(queryable, id)

@callback get(queryable :: Ecto.Queryable.t(), id :: term()) :: struct() | nil

get(queryable, id, opts)

@callback get(queryable :: Ecto.Queryable.t(), id :: term(), opts :: keyword()) ::
  struct() | nil

get!(queryable, id)

@callback get!(queryable :: Ecto.Queryable.t(), id :: term()) :: struct()

get!(queryable, id, opts)

@callback get!(queryable :: Ecto.Queryable.t(), id :: term(), opts :: keyword()) ::
  struct()

get_by(queryable, clauses)

@callback get_by(queryable :: Ecto.Queryable.t(), clauses :: keyword() | map()) ::
  struct() | nil

get_by(queryable, clauses, opts)

@callback get_by(
  queryable :: Ecto.Queryable.t(),
  clauses :: keyword() | map(),
  opts :: keyword()
) ::
  struct() | nil

get_by!(queryable, clauses)

@callback get_by!(queryable :: Ecto.Queryable.t(), clauses :: keyword() | map()) ::
  struct()

get_by!(queryable, clauses, opts)

@callback get_by!(
  queryable :: Ecto.Queryable.t(),
  clauses :: keyword() | map(),
  opts :: keyword()
) ::
  struct()

insert(struct_or_changeset)

@callback insert(struct_or_changeset :: Ecto.Changeset.t() | struct()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}

insert(struct_or_changeset, opts)

@callback insert(struct_or_changeset :: Ecto.Changeset.t() | struct(), opts :: keyword()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}

insert!(struct_or_changeset)

@callback insert!(struct_or_changeset :: Ecto.Changeset.t() | struct()) :: struct()

insert!(struct_or_changeset, opts)

@callback insert!(struct_or_changeset :: Ecto.Changeset.t() | struct(), opts :: keyword()) ::
  struct()

insert_all(source, entries, opts)

@callback insert_all(
  source :: Ecto.Queryable.t() | binary(),
  entries :: [map() | keyword()],
  opts :: keyword()
) :: {non_neg_integer(), nil | list()}

insert_or_update(changeset)

@callback insert_or_update(changeset :: Ecto.Changeset.t()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}

insert_or_update(changeset, opts)

@callback insert_or_update(changeset :: Ecto.Changeset.t(), opts :: keyword()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}

insert_or_update!(changeset)

@callback insert_or_update!(changeset :: Ecto.Changeset.t()) :: struct()

insert_or_update!(changeset, opts)

@callback insert_or_update!(changeset :: Ecto.Changeset.t(), opts :: keyword()) ::
  struct()

load(schema_or_map, data)

@callback load(
  schema_or_map :: module() | map(),
  data :: map() | keyword() | {list(), list()}
) ::
  struct() | map()

one(queryable)

@callback one(queryable :: Ecto.Queryable.t()) :: struct() | nil

one(queryable, opts)

@callback one(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: struct() | nil

one!(queryable)

@callback one!(queryable :: Ecto.Queryable.t()) :: struct()

one!(queryable, opts)

@callback one!(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: struct()

preload(structs_or_struct_or_nil, preloads)

@callback preload(
  structs_or_struct_or_nil :: [struct()] | struct() | nil,
  preloads :: term()
) ::
  [struct()] | struct() | nil

preload(structs_or_struct_or_nil, preloads, opts)

@callback preload(
  structs_or_struct_or_nil :: [struct()] | struct() | nil,
  preloads :: term(),
  opts :: keyword()
) :: [struct()] | struct() | nil

query(sql)

@callback query(sql :: String.t()) :: {:ok, term()} | {:error, term()}

query(sql, params)

@callback query(sql :: String.t(), params :: list()) :: {:ok, term()} | {:error, term()}

query(sql, params, opts)

@callback query(sql :: String.t(), params :: list(), opts :: keyword()) ::
  {:ok, term()} | {:error, term()}

query!(sql)

@callback query!(sql :: String.t()) :: term()

query!(sql, params)

@callback query!(sql :: String.t(), params :: list()) :: term()

query!(sql, params, opts)

@callback query!(sql :: String.t(), params :: list(), opts :: keyword()) :: term()

reload(struct_or_structs)

@callback reload(struct_or_structs :: struct() | [struct()]) ::
  struct() | nil | [struct() | nil]

reload(struct_or_structs, opts)

@callback reload(struct_or_structs :: struct() | [struct()], opts :: keyword()) ::
  struct() | nil | [struct() | nil]

reload!(struct_or_structs)

@callback reload!(struct_or_structs :: struct() | [struct()]) :: struct() | [struct()]

reload!(struct_or_structs, opts)

@callback reload!(struct_or_structs :: struct() | [struct()], opts :: keyword()) ::
  struct() | [struct()]

stream(queryable)

@callback stream(queryable :: Ecto.Queryable.t()) :: Enum.t()

stream(queryable, opts)

@callback stream(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: Enum.t()

update(changeset)

@callback update(changeset :: Ecto.Changeset.t()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}

update(changeset, opts)

@callback update(changeset :: Ecto.Changeset.t(), opts :: keyword()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}

update!(changeset)

@callback update!(changeset :: Ecto.Changeset.t()) :: struct()

update!(changeset, opts)

@callback update!(changeset :: Ecto.Changeset.t(), opts :: keyword()) :: struct()

update_all(queryable, updates, opts)

@callback update_all(
  queryable :: Ecto.Queryable.t(),
  updates :: keyword(),
  opts :: keyword()
) ::
  {non_neg_integer(), nil | list()}