Stateless stub for DoubleDown.Repo.
Write operations (insert, update, delete) apply changeset
changes and return {:ok, struct} but store nothing. Read
operations go through an optional fallback function, or raise a
clear error.
Implements DoubleDown.Dispatch.StatelessHandler, so it can
be used by module name with Double.fallback:
Usage with Double.fallback
# Writes only — reads will raise with a helpful message:
DoubleDown.Double.fallback(DoubleDown.Repo, DoubleDown.Repo.Stateless)
# With fallback for specific reads:
DoubleDown.Double.fallback(DoubleDown.Repo, DoubleDown.Repo.Stateless,
fn _contract, operation, args ->
case {operation, args} do
{:get, [User, 1]} -> %User{id: 1, name: "Alice"}
{:all, [User]} -> [%User{id: 1, name: "Alice"}]
{:exists?, [User]} -> true
end
end
)
# Layer expects on top for failure simulation:
DoubleDown.Repo
|> DoubleDown.Double.fallback(DoubleDown.Repo.Stateless)
|> DoubleDown.Double.expect(:insert, fn [changeset] ->
{:error, Ecto.Changeset.add_error(changeset, :email, "taken")}
end)When to use Repo.Stateless
Use Repo.Stateless when your test only needs fire-and-forget writes
and a few canned read responses. It's the lightest-weight option —
no state to reason about.
For read-after-write consistency, use Repo.InMemory (closed-world,
recommended) or Repo.OpenInMemory (open-world, fallback-based).
| Fake | State | Reads |
|---|---|---|
Repo.Stateless | None | Fallback function or raise |
Repo.InMemory | Complete store | Authoritative for bare schemas |
Repo.OpenInMemory | Partial store | PK lookup in state, fallback for rest |
Summary
Functions
Create a new Test handler function.
Functions
@spec new( (module(), atom(), [term()] -> term()) | nil, keyword() ) :: (module(), atom(), [term()] -> term())
Create a new Test handler function.
Returns a 3-arity function (contract, operation, args) -> result suitable for
use with DoubleDown.Double.fallback/2 or DoubleDown.Testing.set_stateless_handler/2.
Arguments
fallback_fn— an optional 3-arity function(contract, operation, args) -> resultthat handles read operations. If the function raisesFunctionClauseError(no matching clause), dispatch falls through to an error. If omitted ornil, all reads raise immediately.opts— keyword options (reserved for future use).
Examples
# Writes only — via module name (StatelessHandler)
DoubleDown.Double.fallback(DoubleDown.Repo, DoubleDown.Repo.Stateless)
# With fallback for specific reads
DoubleDown.Double.fallback(DoubleDown.Repo, DoubleDown.Repo.Stateless,
fn _contract, operation, args ->
case {operation, args} do
{:get, [User, 1]} -> %User{id: 1, name: "Alice"}
{:all, [User]} -> [%User{id: 1, name: "Alice"}]
{:exists?, [User]} -> true
end
end
)Legacy keyword-only form (still supported)
DoubleDown.Repo.Stateless.new(fallback_fn: fn _contract, :get, [User, 1] -> %User{} end)