DoubleDown.Repo.Stub (double_down v0.48.1)

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.StubHandler, so it can be used by module name with Double.stub:

Usage with Double.stub

# Writes only — reads will raise with a helpful message:
DoubleDown.Double.stub(DoubleDown.Repo, DoubleDown.Repo.Stub)

# With fallback for specific reads:
DoubleDown.Double.stub(DoubleDown.Repo, DoubleDown.Repo.Stub,
  fn
    :get, [User, 1] -> %User{id: 1, name: "Alice"}
    :all, [User] -> [%User{id: 1, name: "Alice"}]
    :exists?, [User] -> true
  end
)

# Layer expects on top for failure simulation:
DoubleDown.Repo
|> DoubleDown.Double.stub(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(
  (atom(), [term()] -> term()) | nil,
  keyword()
) :: (atom(), [term()] -> term())

Create a new Test handler function.

Returns a 2-arity function (operation, args) -> result suitable for use with DoubleDown.Double.stub/2 or DoubleDown.Testing.set_fn_handler/2.

Arguments

  • fallback_fn — an optional 2-arity function (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 (StubHandler)
DoubleDown.Double.stub(DoubleDown.Repo, DoubleDown.Repo.Stub)

# With fallback for specific reads
DoubleDown.Double.stub(DoubleDown.Repo, DoubleDown.Repo.Stub,
  fn
    :get, [User, 1] -> %User{id: 1, name: "Alice"}
    :all, [User] -> [%User{id: 1, name: "Alice"}]
    :exists?, [User] -> true
  end
)

Legacy keyword-only form (still supported)

DoubleDown.Repo.Stub.new(fallback_fn: fn :get, [User, 1] -> %User{} end)