DoubleDown.Repo.Stub (double_down v0.60.3)

Copy Markdown View Source

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.Contract.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.Stub)

# With fallback for specific reads:
DoubleDown.Double.fallback(DoubleDown.Repo, DoubleDown.Repo.Stub,
  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.Stub)
|> DoubleDown.Double.expect(:insert, fn [changeset] ->
  {:error, Ecto.Changeset.add_error(changeset, :email, "taken")}
end)

When to use Repo.Stub

Use Repo.Stub 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).

FakeStateReads
Repo.StubNoneFallback function or raise
Repo.InMemoryComplete storeAuthoritative for bare schemas
Repo.OpenInMemoryPartial storePK lookup in state, fallback for rest

Summary

Functions

Create a new Test handler function.

Functions

new(fallback_fn \\ nil, opts \\ [])

@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) -> result that handles read operations. If the function raises FunctionClauseError (no matching clause), dispatch falls through to an error. If omitted or nil, 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.Stub)

# With fallback for specific reads
DoubleDown.Double.fallback(DoubleDown.Repo, DoubleDown.Repo.Stub,
  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.Stub.new(fallback_fn: fn _contract, :get, [User, 1] -> %User{} end)