Orkestra.Projection.Storage behaviour (orkestra v0.2.0)

Copy Markdown View Source

Behaviour for pluggable read-model storage adapters.

write/4

Returns an opaque ops term describing the write operations for applying a single event to the read model. The ops value is a data structure, never a Repo-bound closure — the caller (Phase 2 Projector GenServer) decides when and how to commit the operations.

The Postgres adapter (Phase 2) returns a composable transaction data structure that the Projector GenServer merges with the checkpoint update before executing the transaction, enabling the atomic co-write required by STORE-03. Future Mongo/Elasticsearch adapters return their own idiomatic write descriptor.

Do not return a function or closure from write/4 — that would bind the Repo at call time, preventing the caller from choosing the transaction boundary.

init/1

Called once at adapter startup (Phase 7 GenServer). Allows adapters to perform one-time initialisation such as connection checks, schema creation, and index setup. Returns {:ok, state} where state is an adapter-defined map passed to subsequent callbacks, or {:error, reason} if initialisation fails.

reset/2

Clears all read-model state for a given projector. Used during projector rebuild (later phases). After reset/2, a subsequent write/4 for each event should reconstruct the read model from scratch.

Summary

Types

A domain event map, typically a stored_event() from the EventStore.

An opaque write-operations descriptor returned by write/4.

Options passed through to the adapter module.

The unique name identifying a projector.

Callbacks

Initialises the adapter at projector startup.

Resets all read-model state for projector_name.

Returns write operations for applying event at position to the read model for projector_name.

Types

event()

@type event() :: map()

A domain event map, typically a stored_event() from the EventStore.

ops()

@type ops() :: term()

An opaque write-operations descriptor returned by write/4.

The concrete type is adapter-defined:

  • Postgres adapter: a composable transaction data structure (Phase 2, STORE-03)
  • Mongo adapter: adapter-specific write description
  • Elasticsearch adapter: adapter-specific write description

This type is term() by design — the behaviour itself has no dependency on any specific database library, keeping it adapter-agnostic.

opts()

@type opts() :: keyword()

Options passed through to the adapter module.

projector_name()

@type projector_name() :: String.t()

The unique name identifying a projector.

Callbacks

init(opts)

(optional)
@callback init(opts()) :: {:ok, map()} | {:error, term()}

Initialises the adapter at projector startup.

Called once by the Phase 7 GenServer before any calls to write/4 or reset/2. Implementations should perform any one-time setup such as detecting the storage engine, ensuring schemas/indexes exist, and validating configuration.

Returns {:ok, state} where state is an adapter-specific map that is threaded through to subsequent adapter calls via the opts mechanism, or {:error, reason} if initialisation fails fatally.

reset(projector_name, opts)

@callback reset(projector_name(), opts()) :: :ok | {:error, term()}

Resets all read-model state for projector_name.

Clears every row/document in the read-model table(s) managed by this adapter for the given projector. Used by the rebuild mechanism (Phase 3+) before replaying the event stream from position 0.

Returns :ok on success or {:error, reason} on failure.

write(projector_name, event, non_neg_integer, opts)

@callback write(projector_name(), event(), non_neg_integer(), opts()) ::
  {:ok, ops()} | {:error, term()}

Returns write operations for applying event at position to the read model for projector_name.

The position argument is the event's global monotonic position (D-01), which the Postgres adapter co-writes with the checkpoint to enable STORE-03's atomic read-model + checkpoint update.

Returns {:ok, ops} on success, where ops is an adapter-specific data structure describing the writes to perform. Must be a data structure — never a Repo-bound closure or function (see module doc).

Returns {:error, reason} if the adapter cannot produce write operations for the event (e.g. unrecognised event type or schema mismatch).