nestjs-event-sourcing-lib
Version:
A comprehensive Event Sourcing and CQRS library for NestJS applications
131 lines • 3.53 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AggregateRoot = exports.InvalidEventError = exports.AggregateNotFoundError = void 0;
/**
* Error thrown when aggregate is not found
*/
class AggregateNotFoundError extends Error {
constructor(aggregateId, aggregateType) {
super(`Aggregate ${aggregateType} with ID ${aggregateId} not found`);
this.name = 'AggregateNotFoundError';
}
}
exports.AggregateNotFoundError = AggregateNotFoundError;
/**
* Error thrown when trying to apply wrong event to aggregate
*/
class InvalidEventError extends Error {
constructor(eventType, aggregateType) {
super(`Event ${eventType} cannot be applied to aggregate ${aggregateType}`);
this.name = 'InvalidEventError';
}
}
exports.InvalidEventError = InvalidEventError;
/**
* Base class for all aggregates in Event Sourcing system
*/
class AggregateRoot {
constructor(id) {
/**
* Current aggregate version
*/
this.version = 0;
/**
* List of uncommitted events
*/
this.uncommittedEvents = [];
/**
* Whether aggregate was loaded from Event Store
*/
this.isLoaded = false;
if (id) {
this.id = id;
}
}
getId() {
return this.id;
}
getVersion() {
return this.version;
}
getIsLoaded() {
return this.isLoaded;
}
/**
* Applies new event to aggregate
*/
apply(event) {
if (event.aggregateId !== this.id) {
throw new InvalidEventError(event.eventType, this.constructor.name);
}
this.handleEvent(event);
this.uncommittedEvents.push(event);
this.version++;
}
/**
* Restores aggregate from event history
*/
loadFromHistory(events) {
for (const event of events) {
this.handleEvent(event);
this.version++;
}
this.isLoaded = true;
}
getUncommittedEvents() {
return [...this.uncommittedEvents];
}
markEventsAsCommitted() {
this.uncommittedEvents = [];
}
hasUncommittedEvents() {
return this.uncommittedEvents.length > 0;
}
getUncommittedEventsCount() {
return this.uncommittedEvents.length;
}
/**
* Creates aggregate snapshot for optimization
*/
createSnapshot() {
return {
id: this.id,
version: this.version,
aggregateType: this.constructor.name,
timestamp: new Date(),
data: this.getSnapshotData(),
};
}
/**
* Restores aggregate from snapshot
*/
loadFromSnapshot(snapshot) {
this.id = snapshot.id;
this.version = snapshot.version;
this.loadSnapshotData(snapshot.data);
this.isLoaded = true;
}
/**
* Gets data for snapshot (should be overridden in aggregate)
*/
getSnapshotData() {
const { id, version, uncommittedEvents, isLoaded, ...data } = this;
return data;
}
/**
* Loads data from snapshot (should be overridden in aggregate)
*/
loadSnapshotData(data) {
Object.assign(this, data);
}
/**
* Validates aggregate state
*/
validateState() {
if (!this.id) {
throw new Error(`Aggregate ${this.constructor.name} must have an ID`);
}
}
}
exports.AggregateRoot = AggregateRoot;
//# sourceMappingURL=aggregate-root.js.map