feat: add reducer factory method

This commit is contained in:
2025-08-11 13:52:29 +02:00
parent cc8c558db6
commit 91c3755533
2 changed files with 40 additions and 14 deletions

View File

@@ -2,7 +2,6 @@ import type { AnyEventStore, EventsInsertSettings } from "../libraries/event-sto
import type { Unknown } from "../types/common.ts";
import { AggregateSnapshotViolation, AggregateStreamViolation } from "./errors.ts";
import { EventFactory } from "./event-factory.ts";
import { makeAggregateReducer } from "./reducer.ts";
/**
* Represents an aggregate root in an event-sourced system.
@@ -20,6 +19,9 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
*/
static readonly name: string;
/**
* Instance used for internal interaction with the originating event store.
*/
readonly #store: AnyEventStore;
/**
@@ -52,13 +54,17 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
this.#stream = value;
}
get id() {
get id(): string {
if (this.#stream === undefined) {
this.#stream = crypto.randomUUID();
}
return this.#stream;
}
get #self(): typeof AggregateRoot<TEventFactory> {
return this.constructor as typeof AggregateRoot<TEventFactory>;
}
/**
* Does the aggregate have pending events to submit to the event store.
*/
@@ -133,6 +139,27 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
// Mutators
// -------------------------------------------------------------------------
/**
* Generates a new snapshot for the aggregate instance.
*
* If the instance has any pending events, they will be commited before
* the snapshot operation is executed. If there are special settings for
* any pending events, make sure to `.save()` before snapshotting.
*/
async snapshot() {
const stream = this.#stream;
if (stream === undefined) {
throw new AggregateSnapshotViolation(this.#self.name);
}
await this.save();
const reducer = this.#store.aggregate.reducer(this.#self);
await this.#store.createSnapshot({
name: this.#self.name,
stream,
reducer,
});
}
/**
* Saves all pending events to the attached event store.
*
@@ -150,18 +177,6 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
return this;
}
async snapshot() {
const stream = this.#stream;
if (stream === undefined) {
throw new AggregateSnapshotViolation((this.constructor as typeof AggregateRoot<TEventFactory>).name);
}
await this.#store.createSnapshot({
name: this.constructor.name,
stream,
reducer: makeAggregateReducer(this.#store, this.constructor as typeof AggregateRoot<TEventFactory>),
});
}
/**
* Removes all events from the aggregate #pending list.
*/