Skip to content

Add store-agnostic AllDatabases() to IEventStore (#387)#388

Merged
jeremydmiller merged 1 commit into
mainfrom
feat/387-eventstore-alldatabases
May 27, 2026
Merged

Add store-agnostic AllDatabases() to IEventStore (#387)#388
jeremydmiller merged 1 commit into
mainfrom
feat/387-eventstore-alldatabases

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

@jeremydmiller jeremydmiller commented May 27, 2026

Closes #387.

What

Adds a store-neutral database accessor to JasperFx.Events.IEventStore:

ValueTask<IReadOnlyList<IEventDatabase>> AllDatabases();

Shipped as a default interface member that returns an empty array as a stand-in, so every existing IEventStore implementer keeps compiling and degrades gracefully until it overrides. Signature mirrors Marten's existing IMartenStorage.AllDatabases().

Why

Store-agnostic monitoring/tooling (e.g. CritterWatch) needs an IEventDatabase to call the read abstractions — AllProjectionProgress(...) plus FetchDeadLetterCountsAsync(...) / CountDeadLetterEventsAsync(...) from #356 — but there was no store-neutral way to obtain one:

  • A Marten + Wolverine host registers IEventStore in DI (concrete Marten.DocumentStore) but does not register IEventDatabase, so GetServices<IEventDatabase>() is empty.
  • The registered IEventStore could only yield its databases through Marten's own IMartenStorage.AllDatabases() — concrete-store types a store-agnostic consumer must not reference.
  • IEventStore itself exposed only DatabaseCardinality — no path to IEventDatabase.

AllDatabases() closes the loop: consumers resolve the already-registered IEventStore and enumerate IEventDatabase store-agnostically.

Follow-ups (real implementations)

The default returns empty; the concrete stores will override:

Tests

AllDatabasesDefaultTests exercises the default member against a bare IEventStore and asserts an empty result, mirroring DeadLetterCountDefaultsTests from #356.

Companion to #356; unblocks CritterWatch#213 (ProjectionDeadLetters alert).

🤖 Generated with Claude Code

Store-agnostic monitoring/tooling (e.g. CritterWatch) needs an IEventDatabase to
call the read abstractions — AllProjectionProgress, plus the FetchDeadLetterCountsAsync /
CountDeadLetterEventsAsync reads from #356 — but IEventStore exposed only
DatabaseCardinality and offered no store-neutral path to an IEventDatabase. A
Marten + Wolverine host registers IEventStore in DI but not IEventDatabase, so
GetServices<IEventDatabase>() comes back empty, and the only way to reach the
databases was through concrete store types (IMartenStorage.AllDatabases) that a
store-agnostic consumer must not reference.

Adds:

    ValueTask<IReadOnlyList<IEventDatabase>> AllDatabases();

as a default interface member returning an empty array as a stand-in, so existing
IEventStore implementers keep compiling and degrade gracefully until they override.
Marten (delegating to IMartenStorage.AllDatabases()) and Polecat will provide real
implementations. Signature mirrors Marten's existing IMartenStorage.AllDatabases().

Companion to #356; unblocks CritterWatch#213 (ProjectionDeadLetters alert).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add ValueTask<IReadOnlyList<IEventDatabase>> AllDatabases() to IEventStore

1 participant