Skip to content

EventStoreOptions has no AddEventType — event type pre-registration is unreachable from the public API #395

Description

@jeremydmiller

Surfaced by the compliance-library adoption (#393). Small public-API parity gap.

Gap

StoreOptions.Events is an EventStoreOptions facade exposing RegisterTagType<TTag>() / RegisterTagType<TTag>(string) and a pile of flags — but no AddEventType. Marten has opts.Events.AddEventType<TEvent>() and AddEventTypes(IEnumerable<Type>), and the shared JasperFx.Events.IEventRegistry declares void AddEventType(Type).

So a Polecat user following Marten's documented pattern:

opts.Events.AddEventType<StudentEnrolled>();   // does not compile on Polecat

has to go around the facade:

opts.EventGraph.AddEventType(typeof(StudentEnrolled));

which works (StoreOptions.EventGraph is public and EventGraph implements IEventRegistry) but is not discoverable and is not what any Marten-derived docs or samples show.

This is exactly what the compliance fixture had to do — see PolecatComplianceFixture.PolecatComplianceRegistrar.AddEventType in #393, which carries a comment explaining the detour.

Why it matters beyond ergonomics

Pre-registration is not cosmetic. The shared registry doc for AddEventType calls out the async-daemon case: "can help with asynchronous projections where the daemon hasn't yet encountered the event type." A user who cannot reach it from the options facade cannot apply that mitigation without knowing about EventGraph.

Suggested fix

Additive, ~6 lines on EventStoreOptions, mirroring the existing RegisterTagType delegation pattern:

public void AddEventType<TEvent>() => EventGraph!.AddEventType(typeof(TEvent));
public void AddEventType(Type eventType) => EventGraph!.AddEventType(eventType);
public void AddEventTypes(IEnumerable<Type> types) { foreach (var t in types) EventGraph!.AddEventType(t); }

EventGraph is assigned in the StoreOptions constructor, so it is non-null at configure time — same lifetime assumption RegisterTagType already makes with its EventGraph!.

Note: deliberately not returning IEventStoreOptions for fluent chaining. Marten's AddEventType<T>() does, and that return type is precisely what makes marten#5114 (a generic DIM on IEventRegistry) impossible to land there without a source-breaking change. Keeping these void matches the shared interface and leaves the door open.

Related: marten#5114, marten#5119.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions