Skuld.Effects.Port.Repo.Test (skuld v0.23.0)

View Source

Stateless test handler for Port.Repo.Contract.

Provides a function handler via new/1 for use in a Port.with_handler/3 registry. Write operations (insert, update, delete) apply changeset changes and return {:ok, struct}. All read operations go through an optional fallback function, or raise a clear error.

This applies the "fail when consistency cannot be proven" approach — reads never silently return nil or [] because the adapter has no basis for claiming a record does or doesn't exist.

Usage

alias Skuld.Effects.Port
alias Skuld.Effects.Port.Repo

# Writes only — reads will raise:
comp
|> Port.with_handler(%{Repo.Contract => Repo.Test.new()})
|> Throw.with_handler()
|> Comp.run!()

# With fallback for reads:
comp
|> Port.with_handler(%{
  Repo.Contract => Repo.Test.new(
    fallback_fn: fn
      :get, [User, 1] -> %User{id: 1, name: "Alice"}
      :all, [User] -> [%User{id: 1, name: "Alice"}]
    end
  )
})
|> Throw.with_handler()
|> Comp.run!()

Differences from Repo.InMemory

Repo.Test is stateless — writes apply changesets and return {:ok, struct} but nothing is stored. There is no read-after-write consistency.

Repo.InMemory is stateful — writes store records and PK-based reads can find them. Use Repo.InMemory when your test needs read-after-write consistency. Use Repo.Test when you only need fire-and-forget writes.

Summary

Functions

Create a new Test handler function.

Functions

new(opts \\ [])

@spec new(keyword()) :: (module(), atom(), [term()] -> term())

Create a new Test handler function.

Returns a 3-arity function (mod, operation, args) -> result suitable for use as a resolver in Port.with_handler/3.

Options

  • :fallback_fn - a 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, all reads raise immediately.

Examples

# Writes only
Repo.Test.new()

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