feat: add reducer factory method
This commit is contained in:
@@ -2,7 +2,6 @@ import type { AnyEventStore, EventsInsertSettings } from "../libraries/event-sto
|
|||||||
import type { Unknown } from "../types/common.ts";
|
import type { Unknown } from "../types/common.ts";
|
||||||
import { AggregateSnapshotViolation, AggregateStreamViolation } from "./errors.ts";
|
import { AggregateSnapshotViolation, AggregateStreamViolation } from "./errors.ts";
|
||||||
import { EventFactory } from "./event-factory.ts";
|
import { EventFactory } from "./event-factory.ts";
|
||||||
import { makeAggregateReducer } from "./reducer.ts";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an aggregate root in an event-sourced system.
|
* Represents an aggregate root in an event-sourced system.
|
||||||
@@ -20,6 +19,9 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
|
|||||||
*/
|
*/
|
||||||
static readonly name: string;
|
static readonly name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance used for internal interaction with the originating event store.
|
||||||
|
*/
|
||||||
readonly #store: AnyEventStore;
|
readonly #store: AnyEventStore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,13 +54,17 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
|
|||||||
this.#stream = value;
|
this.#stream = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get id() {
|
get id(): string {
|
||||||
if (this.#stream === undefined) {
|
if (this.#stream === undefined) {
|
||||||
this.#stream = crypto.randomUUID();
|
this.#stream = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
return this.#stream;
|
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.
|
* Does the aggregate have pending events to submit to the event store.
|
||||||
*/
|
*/
|
||||||
@@ -133,6 +139,27 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
|
|||||||
// Mutators
|
// 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.
|
* Saves all pending events to the attached event store.
|
||||||
*
|
*
|
||||||
@@ -150,18 +177,6 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
|
|||||||
return this;
|
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.
|
* Removes all events from the aggregate #pending list.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -184,6 +184,17 @@ export class EventStore<TEventFactory extends EventFactory, TEventStoreAdapter e
|
|||||||
): InstanceType<TAggregate> => {
|
): InstanceType<TAggregate> => {
|
||||||
return aggregate.from(this, snapshot);
|
return aggregate.from(this, snapshot);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new reducer instance for the given aggregate.
|
||||||
|
*
|
||||||
|
* @param aggregate - Aggregate to create a reducer for.
|
||||||
|
*/
|
||||||
|
reducer: <TAggregate extends AggregateRootClass<TEventFactory>>(
|
||||||
|
aggregate: TAggregate,
|
||||||
|
): Reducer<TEventFactory, InstanceType<TAggregate>> => {
|
||||||
|
return makeAggregateReducer(this, aggregate);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user