Skuld.Repo.InMemory (skuld v0.27.2)
View SourceClosed-world stateful in-memory Repo handler for tests. Recommended default.
Thin wrapper around DoubleDown.Repo.InMemory that provides
skuld's effect-based with_handler/3 API. The state is the complete
truth — if a record isn't in the store, it doesn't exist. This makes
the adapter authoritative for all bare-schema operations without
needing a fallback function.
Usage
alias Skuld.Repo
# Basic — all bare-schema reads work without fallback:
comp
|> Repo.InMemory.with_handler(Repo.InMemory.new())
|> Comp.run!()
# With seed data:
state = Repo.InMemory.new(seed: [%User{id: 1, name: "Alice"}])
comp
|> Repo.InMemory.with_handler(state)
|> Comp.run!()Authoritative operations (bare schema queryables)
| Category | Operations | Behaviour |
|---|---|---|
| Writes | insert, update, delete, bang variants | Store in state |
| PK reads | get, get! | nil/raise on miss (no fallback) |
| Clause reads | get_by, get_by! | Scan and filter |
| Collection | all, one/one!, exists? | Scan state |
| Aggregates | aggregate | Compute from state |
| Bulk writes | insert_all, delete_all, update_all | Modify state |
| Preload | preload | Resolve from store |
| Reload | reload, reload! | Re-fetch from store |
| Transactions | transact, rollback | Snapshot + restore on rollback |
Ecto.Query fallback
Operations with Ecto.Query queryables (containing where,
join, select etc.) cannot be evaluated in-memory. These fall
through to the fallback function, or raise with a clear error.
Extracting Final State
Use the :output option to access the final handler state:
{result, final_store} =
comp
|> Repo.InMemory.with_handler(Repo.InMemory.new(),
output: fn result, state -> {result, state.handler_state} end
)
|> Comp.run!()Fallback function
The optional fallback function handles operations the closed-world
store cannot service (e.g. Ecto.Query queryables). It receives
(operation, args, state) — the skuld-idiomatic 3-arity convention.
When to use which Repo fake
| Fake | State | Best for |
|---|---|---|
Repo.InMemory | Complete store | All bare-schema reads; ExMachina |
Repo.OpenInMemory | Partial store | PK reads in state, fallback for rest |
Repo.Stub | None | Fire-and-forget writes, canned reads |
Summary
Functions
Returns the stateful handler function.
Create a new InMemory state map.
Convert a list of structs into the nested state map for seeding.
Install the closed-world in-memory Repo handler for a computation.
Types
@type store() :: DoubleDown.Repo.InMemory.store()
Functions
Returns the stateful handler function.
The function has the signature (contract, operation, args, state) -> {result, new_state}.
Create a new InMemory state map.
Options
:seed- a list of structs to pre-populate the store:fallback_fn- a 3-arity function(operation, args, state) -> resultfor operations the closed-world store cannot service (e.g. Ecto.Query).
Examples
Repo.InMemory.new()
Repo.InMemory.new(seed: [%User{id: 1, name: "Alice"}])
Repo.InMemory.new(
seed: [%User{id: 1, name: "Alice"}],
fallback_fn: fn
:all, [%Ecto.Query{}], _state -> []
end
)
Convert a list of structs into the nested state map for seeding.
@spec with_handler(Skuld.Comp.Types.computation(), store(), keyword()) :: Skuld.Comp.Types.computation()
Install the closed-world in-memory Repo handler for a computation.
Options
All options from Port.with_stateful_handler/4 are supported:
:log— enable dispatch logging:output— transform(result, %Port.State{}) -> outputon scope exit.