feat: add epoch event stream to aggregate id

This commit is contained in:
2025-08-12 05:07:16 +02:00
parent d3b08b0caa
commit 393afd58d6
16 changed files with 34 additions and 72 deletions

View File

@@ -1,6 +1,6 @@
import type { AnyEventStore, EventsInsertSettings } from "../libraries/event-store.ts";
import type { Unknown } from "../types/common.ts";
import { AggregateSnapshotViolation, AggregateStreamViolation } from "./errors.ts";
import { AggregateSnapshotViolation } from "./errors.ts";
import { EventFactory } from "./event-factory.ts";
/**
@@ -27,7 +27,7 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
/**
* Primary unique identifier for the stream the aggregate belongs to.
*/
#stream?: string;
id: string;
/**
* List of pending records to push to the parent event store.
@@ -40,6 +40,7 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
* @param store - Store this aggregate instance acts against.
*/
constructor(store: AnyEventStore) {
this.id = crypto.randomUUID();
this.#store = store;
}
@@ -47,20 +48,6 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
// Accessors
// -------------------------------------------------------------------------
set id(value: string) {
if (this.#stream !== undefined) {
throw new AggregateStreamViolation(this.constructor.name);
}
this.#stream = value;
}
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>;
}
@@ -147,7 +134,7 @@ export abstract class AggregateRoot<TEventFactory extends EventFactory> {
* any pending events, make sure to `.save()` before snapshotting.
*/
async snapshot() {
const stream = this.#stream;
const stream = this.id;
if (stream === undefined) {
throw new AggregateSnapshotViolation(this.#self.name);
}

View File

@@ -1,7 +1,6 @@
import z, { ZodType } from "zod";
import { EventValidationError } from "./errors.ts";
import { makeId } from "./nanoid.ts";
import { getLogicalTimestamp } from "./time.ts";
import { toPrettyErrorLines } from "./zod.ts";
@@ -41,8 +40,8 @@ export class Event<TEventState extends EventState = EventState> {
const timestamp = getLogicalTimestamp();
const record = {
id: makeId(),
stream: payload.stream ?? makeId(),
id: crypto.randomUUID(),
stream: payload.stream ?? crypto.randomUUID(),
type: this.state.type,
data: "data" in payload ? payload.data : null,
meta: "meta" in payload ? payload.meta : null,
@@ -134,13 +133,13 @@ export type EventRecord<TEvent extends EventState = EventState> = {
/**
* A unique event identifier.
*/
id: string;
id: UUID;
/**
* Event streams are used to group related events together. This identifier
* is used to identify the stream to which the event belongs.
*/
stream: string;
stream: UUID;
/**
* Type refers to the purpose of the event in a past tense descibing something
@@ -203,3 +202,5 @@ export type EventStatus = {
*/
outdated: boolean;
};
export type UUID = `${string}-${string}-${string}-${string}-${string}`;

View File

@@ -1,10 +0,0 @@
import { nanoid } from "nanoid";
/**
* Generate a new nanoid.
*
* @param size - Size of the id. Default: 11
*/
export function makeId(size: number = 11): string {
return nanoid(size);
}

View File

@@ -19,6 +19,7 @@ export function makeAggregateReducer<
},
reduce(events: TEventFactory["$events"][number]["$record"][], snapshot?: Unknown) {
const instance = aggregate.from(store, snapshot);
instance.id = events[0].stream;
for (const event of events) {
instance.with(event);
}