ddd-node 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base/aggregate.d.ts +48 -0
- package/dist/base/aggregate.js +143 -0
- package/dist/base/command.d.ts +32 -0
- package/dist/base/command.js +46 -0
- package/dist/base/entity.d.ts +22 -0
- package/dist/base/entity.js +31 -0
- package/dist/base/errors/aggregate.error.d.ts +18 -0
- package/dist/base/errors/aggregate.error.js +39 -0
- package/dist/base/event.d.ts +40 -0
- package/dist/base/event.js +50 -0
- package/dist/base/index.d.ts +6 -0
- package/dist/base/index.js +22 -0
- package/dist/base/props-envelope.d.ts +11 -0
- package/dist/base/props-envelope.js +27 -0
- package/dist/base/value-object.d.ts +16 -0
- package/dist/base/value-object.js +31 -0
- package/dist/decorators/aggregate.d.ts +7 -0
- package/dist/decorators/aggregate.js +32 -0
- package/dist/decorators/command.d.ts +2 -0
- package/dist/decorators/command.js +12 -0
- package/dist/decorators/entity.d.ts +2 -0
- package/dist/decorators/entity.js +12 -0
- package/dist/decorators/event.d.ts +2 -0
- package/dist/decorators/event.js +12 -0
- package/dist/decorators/index.d.ts +5 -0
- package/dist/decorators/index.js +21 -0
- package/dist/decorators/value-object.d.ts +2 -0
- package/dist/decorators/value-object.js +12 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +19 -0
- package/dist/metadata/aggregate.d.ts +14 -0
- package/dist/metadata/aggregate.js +70 -0
- package/dist/metadata/command.d.ts +6 -0
- package/dist/metadata/command.js +19 -0
- package/dist/metadata/constants.d.ts +7 -0
- package/dist/metadata/constants.js +10 -0
- package/dist/metadata/entity.d.ts +6 -0
- package/dist/metadata/entity.js +19 -0
- package/dist/metadata/errors.d.ts +18 -0
- package/dist/metadata/errors.js +39 -0
- package/dist/metadata/event.d.ts +6 -0
- package/dist/metadata/event.js +19 -0
- package/dist/metadata/index.d.ts +6 -0
- package/dist/metadata/index.js +22 -0
- package/dist/metadata/registry.d.ts +9 -0
- package/dist/metadata/registry.js +23 -0
- package/dist/metadata/value-object.d.ts +6 -0
- package/dist/metadata/value-object.js +19 -0
- package/dist/types/class-static.d.ts +2 -0
- package/dist/types/class-static.js +2 -0
- package/dist/types/class.d.ts +4 -0
- package/dist/types/class.js +2 -0
- package/dist/utils/id.d.ts +1 -0
- package/dist/utils/id.js +8 -0
- package/dist/utils/to-array.d.ts +1 -0
- package/dist/utils/to-array.js +9 -0
- package/package.json +36 -0
- package/tsconfig.build.json +7 -0
- package/tsconfig.json +115 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Class } from "../types/class";
|
|
2
|
+
import { ClassStatic } from "../types/class-static";
|
|
3
|
+
import { AnyCommand } from "./command";
|
|
4
|
+
import { Entity, IEntityMetadata } from "./entity";
|
|
5
|
+
import { AnyEvent, EventClass, IEventAggregate, NewEventMetadataOptions } from "./event";
|
|
6
|
+
import { PropsOf } from "./props-envelope";
|
|
7
|
+
export interface IAggregateMetadata extends IEntityMetadata {
|
|
8
|
+
readonly version: number;
|
|
9
|
+
}
|
|
10
|
+
export type NewAggregateMetadataOptions = Partial<Omit<IAggregateMetadata, "version">>;
|
|
11
|
+
export declare class Aggregate<P extends object> extends Entity<P> implements IAggregateMetadata {
|
|
12
|
+
private readonly _version;
|
|
13
|
+
private handledCommands;
|
|
14
|
+
private pastEvents;
|
|
15
|
+
private events;
|
|
16
|
+
constructor(metadata: IAggregateMetadata, props?: P);
|
|
17
|
+
static agggregateType(): string;
|
|
18
|
+
static newAggregate<T extends AnyAggregate>(this: AggregateClass<T>, props?: PropsOf<T>, metadata?: NewAggregateMetadataOptions): T;
|
|
19
|
+
static loadAggregate<T extends AnyAggregate>(this: AggregateClass<T>, id: string, version: number, props: PropsOf<T>, pastEvents: AnyEvent[]): T;
|
|
20
|
+
get version(): number;
|
|
21
|
+
aggregateType(): string;
|
|
22
|
+
getHandledCommands(): AnyCommand[];
|
|
23
|
+
getPastEvents(): AnyEvent[];
|
|
24
|
+
getEvents(): AnyEvent[];
|
|
25
|
+
hasEvents(): boolean;
|
|
26
|
+
lastEvent(): AnyEvent | undefined;
|
|
27
|
+
lastEventVersion(): number;
|
|
28
|
+
nextEventVersion(): number;
|
|
29
|
+
nextEventAggregate(): IEventAggregate;
|
|
30
|
+
protected newEvent<E extends AnyEvent>(eventClass: EventClass<E>, props: PropsOf<E>, metadata?: NewEventMetadataOptions): E;
|
|
31
|
+
protected addEvent<E extends AnyEvent>(event: E): void;
|
|
32
|
+
protected addPastEvent<E extends AnyEvent>(event: E): void;
|
|
33
|
+
getEventApplier(eventType: string): AggregateEventApplier<AnyEvent> | null;
|
|
34
|
+
private validateEventBeforeApply;
|
|
35
|
+
applyEvent<E extends AnyEvent>(event: E, fromHistory?: boolean): void;
|
|
36
|
+
applyEvents(events: AnyEvent[], fromHistory?: boolean): void;
|
|
37
|
+
getCommandHandler(commandType: string): AggregateCommandHandler<AnyCommand> | null;
|
|
38
|
+
processCommand<C extends AnyCommand>(command: C): AnyEvent[];
|
|
39
|
+
processCommands(commands: AnyCommand[]): Record<string, AnyEvent[]>;
|
|
40
|
+
}
|
|
41
|
+
export type AnyAggregate = Aggregate<any>;
|
|
42
|
+
export type AggregateEventApplier<E extends AnyEvent> = (event: E) => void;
|
|
43
|
+
export type AggregateCommandHandler<C extends AnyCommand, E extends AnyEvent = AnyEvent> = (command: C) => E | E[];
|
|
44
|
+
export type AggregateConstructorParamsWithProps<P extends object> = ConstructorParameters<typeof Aggregate<P>>;
|
|
45
|
+
export type AggregateClassWithProps<P extends object> = Class<Aggregate<P>, AggregateConstructorParamsWithProps<P>> & ClassStatic<typeof Aggregate<P>>;
|
|
46
|
+
export type AggregateConstructorParams<T extends AnyAggregate> = AggregateConstructorParamsWithProps<PropsOf<T>>;
|
|
47
|
+
export type AggregateClass<T extends AnyAggregate> = Class<T, AggregateConstructorParams<T>> & ClassStatic<typeof Aggregate<PropsOf<T>>>;
|
|
48
|
+
export type AnyAggregateClass = AggregateClass<AnyAggregate>;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Aggregate = void 0;
|
|
4
|
+
const aggregate_1 = require("../metadata/aggregate");
|
|
5
|
+
const id_1 = require("../utils/id");
|
|
6
|
+
const to_array_1 = require("../utils/to-array");
|
|
7
|
+
const entity_1 = require("./entity");
|
|
8
|
+
const aggregate_error_1 = require("./errors/aggregate.error");
|
|
9
|
+
class Aggregate extends entity_1.Entity {
|
|
10
|
+
constructor(metadata, props) {
|
|
11
|
+
super({ id: metadata.id }, props);
|
|
12
|
+
this.handledCommands = [];
|
|
13
|
+
this.pastEvents = [];
|
|
14
|
+
this.events = [];
|
|
15
|
+
this._version = metadata.version;
|
|
16
|
+
}
|
|
17
|
+
static agggregateType() {
|
|
18
|
+
return (0, aggregate_1.getAggregateType)(this.prototype);
|
|
19
|
+
}
|
|
20
|
+
static newAggregate(props, metadata) {
|
|
21
|
+
return new this(Object.assign({ id: (0, id_1.generatePrefixedUUID)(this.agggregateType()), version: 0 }, metadata), props);
|
|
22
|
+
}
|
|
23
|
+
static loadAggregate(id, version, props, pastEvents) {
|
|
24
|
+
const aggregate = new this({ id, version }, props);
|
|
25
|
+
aggregate.applyEvents(pastEvents, true);
|
|
26
|
+
return aggregate;
|
|
27
|
+
}
|
|
28
|
+
get version() {
|
|
29
|
+
return this._version;
|
|
30
|
+
}
|
|
31
|
+
aggregateType() {
|
|
32
|
+
const prototype = Object.getPrototypeOf(this);
|
|
33
|
+
return (0, aggregate_1.getAggregateType)(prototype);
|
|
34
|
+
}
|
|
35
|
+
getHandledCommands() {
|
|
36
|
+
return this.handledCommands;
|
|
37
|
+
}
|
|
38
|
+
getPastEvents() {
|
|
39
|
+
return this.pastEvents;
|
|
40
|
+
}
|
|
41
|
+
getEvents() {
|
|
42
|
+
return this.events;
|
|
43
|
+
}
|
|
44
|
+
hasEvents() {
|
|
45
|
+
return Boolean(this.events.length);
|
|
46
|
+
}
|
|
47
|
+
lastEvent() {
|
|
48
|
+
return this.hasEvents() ? this.events.at(-1) : this.pastEvents.at(-1);
|
|
49
|
+
}
|
|
50
|
+
lastEventVersion() {
|
|
51
|
+
const lastEvent = this.lastEvent();
|
|
52
|
+
if (lastEvent)
|
|
53
|
+
return lastEvent.aggregate.version;
|
|
54
|
+
return this.version;
|
|
55
|
+
}
|
|
56
|
+
nextEventVersion() {
|
|
57
|
+
return this.lastEventVersion() + 1;
|
|
58
|
+
}
|
|
59
|
+
nextEventAggregate() {
|
|
60
|
+
return {
|
|
61
|
+
type: this.aggregateType(),
|
|
62
|
+
id: this.id,
|
|
63
|
+
version: this.nextEventVersion(),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
newEvent(eventClass, props, metadata) {
|
|
67
|
+
return eventClass.newEvent(this.nextEventAggregate(), props, metadata);
|
|
68
|
+
}
|
|
69
|
+
addEvent(event) {
|
|
70
|
+
this.events.push(event);
|
|
71
|
+
}
|
|
72
|
+
addPastEvent(event) {
|
|
73
|
+
if (this.hasEvents())
|
|
74
|
+
throw new aggregate_error_1.PastEventCannotBeAddedError();
|
|
75
|
+
this.pastEvents.push(event);
|
|
76
|
+
}
|
|
77
|
+
getEventApplier(eventType) {
|
|
78
|
+
const prototype = Object.getPrototypeOf(this);
|
|
79
|
+
const eventApplier = (0, aggregate_1.getAggregateEventApplier)(prototype, eventType);
|
|
80
|
+
if (eventApplier)
|
|
81
|
+
return eventApplier.bind(this);
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
validateEventBeforeApply(event) {
|
|
85
|
+
const { type, id, version } = event.aggregate;
|
|
86
|
+
if (type !== this.aggregateType())
|
|
87
|
+
throw new aggregate_error_1.InvalidEventAggregateTypeError();
|
|
88
|
+
if (id !== this.id)
|
|
89
|
+
throw new aggregate_error_1.InvalidEventAggregateIdError();
|
|
90
|
+
if (version !== this.nextEventVersion())
|
|
91
|
+
throw new aggregate_error_1.InvalidEventAggregateVersionError();
|
|
92
|
+
}
|
|
93
|
+
applyEvent(event, fromHistory = false) {
|
|
94
|
+
const eventType = event.eventType();
|
|
95
|
+
const applier = this.getEventApplier(eventType);
|
|
96
|
+
if (!applier)
|
|
97
|
+
throw new aggregate_error_1.EventApplierNotFoundError(eventType);
|
|
98
|
+
this.validateEventBeforeApply(event);
|
|
99
|
+
if (fromHistory)
|
|
100
|
+
this.addPastEvent(event);
|
|
101
|
+
else
|
|
102
|
+
this.addEvent(event);
|
|
103
|
+
applier(event);
|
|
104
|
+
}
|
|
105
|
+
applyEvents(events, fromHistory = false) {
|
|
106
|
+
events.forEach((event) => {
|
|
107
|
+
this.applyEvent(event, fromHistory);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
getCommandHandler(commandType) {
|
|
111
|
+
const prototype = Object.getPrototypeOf(this);
|
|
112
|
+
const commandHandler = (0, aggregate_1.getAggregateCommandHandler)(prototype, commandType);
|
|
113
|
+
if (commandHandler)
|
|
114
|
+
return commandHandler.bind(this);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
processCommand(command) {
|
|
118
|
+
const commandType = command.commandType();
|
|
119
|
+
const handler = this.getCommandHandler(commandType);
|
|
120
|
+
if (!handler)
|
|
121
|
+
throw new aggregate_error_1.CommandHandlerNotFoundError(commandType);
|
|
122
|
+
const events = (0, to_array_1.toArray)(handler(command));
|
|
123
|
+
const { correlationId, causationId } = command;
|
|
124
|
+
events.forEach((event) => {
|
|
125
|
+
if (correlationId)
|
|
126
|
+
event.setCorrelationId(correlationId);
|
|
127
|
+
if (causationId)
|
|
128
|
+
event.setCausationId(causationId);
|
|
129
|
+
this.applyEvent(event);
|
|
130
|
+
});
|
|
131
|
+
this.handledCommands.push(command);
|
|
132
|
+
return events;
|
|
133
|
+
}
|
|
134
|
+
processCommands(commands) {
|
|
135
|
+
const result = {};
|
|
136
|
+
commands.forEach((command) => {
|
|
137
|
+
const events = this.processCommand(command);
|
|
138
|
+
result[command.id] = events;
|
|
139
|
+
});
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.Aggregate = Aggregate;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Class } from "../types/class";
|
|
2
|
+
import { ClassStatic } from "../types/class-static";
|
|
3
|
+
import { PropsEnvelope, PropsOf } from "./props-envelope";
|
|
4
|
+
export interface ICommandMetadata {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly timestamp: number;
|
|
7
|
+
correlationId?: string;
|
|
8
|
+
causationId?: string;
|
|
9
|
+
}
|
|
10
|
+
export type NewCommandMetadataOptions = Partial<Omit<ICommandMetadata, "timestamp">>;
|
|
11
|
+
export declare class Command<P extends object> extends PropsEnvelope<P> implements ICommandMetadata {
|
|
12
|
+
private readonly _id;
|
|
13
|
+
private readonly _timestamp;
|
|
14
|
+
private _correlationId?;
|
|
15
|
+
private _causationId?;
|
|
16
|
+
constructor(metadata: ICommandMetadata, props: P);
|
|
17
|
+
static commandType(): string;
|
|
18
|
+
static newCommand<T extends AnyCommand>(this: CommandClass<T>, props: PropsOf<T>, metadata?: NewCommandMetadataOptions): T;
|
|
19
|
+
get id(): string;
|
|
20
|
+
get timestamp(): number;
|
|
21
|
+
get correlationId(): string | undefined;
|
|
22
|
+
get causationId(): string | undefined;
|
|
23
|
+
setCorrelationId(correlationId: string): void;
|
|
24
|
+
setCausationId(causationId: string): void;
|
|
25
|
+
commandType(): string;
|
|
26
|
+
}
|
|
27
|
+
export type AnyCommand = Command<any>;
|
|
28
|
+
export type CommandConstructorParamsWithProps<P extends object> = ConstructorParameters<typeof Command<P>>;
|
|
29
|
+
export type CommandClassWithProps<P extends object> = Class<Command<P>, CommandConstructorParamsWithProps<P>> & ClassStatic<typeof Command<P>>;
|
|
30
|
+
export type CommandConstructorParams<T extends AnyCommand> = CommandConstructorParamsWithProps<PropsOf<T>>;
|
|
31
|
+
export type CommandClass<T extends AnyCommand> = Class<T, CommandConstructorParams<T>> & ClassStatic<typeof Command<PropsOf<T>>>;
|
|
32
|
+
export type AnyCommandClass = CommandClass<AnyCommand>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Command = void 0;
|
|
4
|
+
const command_1 = require("../metadata/command");
|
|
5
|
+
const id_1 = require("../utils/id");
|
|
6
|
+
const props_envelope_1 = require("./props-envelope");
|
|
7
|
+
class Command extends props_envelope_1.PropsEnvelope {
|
|
8
|
+
constructor(metadata, props) {
|
|
9
|
+
super(props);
|
|
10
|
+
this._id = metadata.id;
|
|
11
|
+
this._timestamp = metadata.timestamp;
|
|
12
|
+
this._correlationId = metadata === null || metadata === void 0 ? void 0 : metadata.correlationId;
|
|
13
|
+
this._causationId = metadata === null || metadata === void 0 ? void 0 : metadata.causationId;
|
|
14
|
+
}
|
|
15
|
+
static commandType() {
|
|
16
|
+
return (0, command_1.getCommandType)(this.prototype);
|
|
17
|
+
}
|
|
18
|
+
static newCommand(props, metadata) {
|
|
19
|
+
return new this(Object.assign({ id: (0, id_1.generatePrefixedUUID)(this.commandType()), timestamp: Date.now() }, metadata), props);
|
|
20
|
+
}
|
|
21
|
+
get id() {
|
|
22
|
+
return this._id;
|
|
23
|
+
}
|
|
24
|
+
get timestamp() {
|
|
25
|
+
return this._timestamp;
|
|
26
|
+
}
|
|
27
|
+
get correlationId() {
|
|
28
|
+
return this._correlationId;
|
|
29
|
+
}
|
|
30
|
+
get causationId() {
|
|
31
|
+
return this._causationId;
|
|
32
|
+
}
|
|
33
|
+
setCorrelationId(correlationId) {
|
|
34
|
+
if (!this.correlationId)
|
|
35
|
+
this._correlationId = correlationId;
|
|
36
|
+
}
|
|
37
|
+
setCausationId(causationId) {
|
|
38
|
+
if (!this.causationId)
|
|
39
|
+
this._causationId = causationId;
|
|
40
|
+
}
|
|
41
|
+
commandType() {
|
|
42
|
+
const prototype = Object.getPrototypeOf(this);
|
|
43
|
+
return (0, command_1.getCommandType)(prototype);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.Command = Command;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Class } from "../types/class";
|
|
2
|
+
import { ClassStatic } from "../types/class-static";
|
|
3
|
+
import { PropsEnvelope, PropsOf } from "./props-envelope";
|
|
4
|
+
export interface IEntityMetadata {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
}
|
|
7
|
+
export type NewEntityMetadataOptions = Partial<IEntityMetadata>;
|
|
8
|
+
export declare class Entity<P extends object> extends PropsEnvelope<P> implements IEntityMetadata {
|
|
9
|
+
private readonly _id;
|
|
10
|
+
constructor(metadata: IEntityMetadata, props?: P);
|
|
11
|
+
static entityType(): string;
|
|
12
|
+
static newEntity<T extends AnyEntity>(this: EntityClass<T>, props?: PropsOf<T>, metadata?: NewEntityMetadataOptions): T;
|
|
13
|
+
get id(): string;
|
|
14
|
+
entityType(): string;
|
|
15
|
+
equals<E extends AnyEntity>(entity: E): boolean;
|
|
16
|
+
}
|
|
17
|
+
export type AnyEntity = Entity<any>;
|
|
18
|
+
export type EntityConstructorParamsWithProps<P extends object> = ConstructorParameters<typeof Entity<P>>;
|
|
19
|
+
export type EntityClassWithProps<P extends object> = Class<Entity<P>, EntityConstructorParamsWithProps<P>> & ClassStatic<typeof Entity<P>>;
|
|
20
|
+
export type EntityConstructorParams<T extends AnyEntity> = EntityConstructorParamsWithProps<PropsOf<T>>;
|
|
21
|
+
export type EntityClass<T extends AnyEntity> = Class<T, EntityConstructorParams<T>> & ClassStatic<typeof Entity<PropsOf<T>>>;
|
|
22
|
+
export type AnyEntityClass = EntityClass<AnyEntity>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Entity = void 0;
|
|
4
|
+
const entity_1 = require("../metadata/entity");
|
|
5
|
+
const id_1 = require("../utils/id");
|
|
6
|
+
const props_envelope_1 = require("./props-envelope");
|
|
7
|
+
class Entity extends props_envelope_1.PropsEnvelope {
|
|
8
|
+
constructor(metadata, props) {
|
|
9
|
+
super(props);
|
|
10
|
+
this._id = metadata.id;
|
|
11
|
+
}
|
|
12
|
+
static entityType() {
|
|
13
|
+
return (0, entity_1.getEntityType)(this.prototype);
|
|
14
|
+
}
|
|
15
|
+
static newEntity(props, metadata) {
|
|
16
|
+
return new this(Object.assign({ id: (0, id_1.generatePrefixedUUID)(this.entityType()) }, metadata), props);
|
|
17
|
+
}
|
|
18
|
+
get id() {
|
|
19
|
+
return this._id;
|
|
20
|
+
}
|
|
21
|
+
entityType() {
|
|
22
|
+
const prototype = Object.getPrototypeOf(this);
|
|
23
|
+
return (0, entity_1.getEntityType)(prototype);
|
|
24
|
+
}
|
|
25
|
+
equals(entity) {
|
|
26
|
+
const equalsType = entity instanceof this.constructor;
|
|
27
|
+
const equalsId = entity.id === this.id;
|
|
28
|
+
return equalsType && equalsId;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.Entity = Entity;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare class PastEventCannotBeAddedError extends Error {
|
|
2
|
+
constructor();
|
|
3
|
+
}
|
|
4
|
+
export declare class EventApplierNotFoundError extends Error {
|
|
5
|
+
constructor(eventType: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class CommandHandlerNotFoundError extends Error {
|
|
8
|
+
constructor(commandType: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class InvalidEventAggregateTypeError extends Error {
|
|
11
|
+
constructor();
|
|
12
|
+
}
|
|
13
|
+
export declare class InvalidEventAggregateIdError extends Error {
|
|
14
|
+
constructor();
|
|
15
|
+
}
|
|
16
|
+
export declare class InvalidEventAggregateVersionError extends Error {
|
|
17
|
+
constructor();
|
|
18
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvalidEventAggregateVersionError = exports.InvalidEventAggregateIdError = exports.InvalidEventAggregateTypeError = exports.CommandHandlerNotFoundError = exports.EventApplierNotFoundError = exports.PastEventCannotBeAddedError = void 0;
|
|
4
|
+
class PastEventCannotBeAddedError extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super("Past event cannot be added once a new event has been added");
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
exports.PastEventCannotBeAddedError = PastEventCannotBeAddedError;
|
|
10
|
+
class EventApplierNotFoundError extends Error {
|
|
11
|
+
constructor(eventType) {
|
|
12
|
+
super(`Not found event applier for event with type ${eventType}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.EventApplierNotFoundError = EventApplierNotFoundError;
|
|
16
|
+
class CommandHandlerNotFoundError extends Error {
|
|
17
|
+
constructor(commandType) {
|
|
18
|
+
super(`Not found command handler for command with type ${commandType}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.CommandHandlerNotFoundError = CommandHandlerNotFoundError;
|
|
22
|
+
class InvalidEventAggregateTypeError extends Error {
|
|
23
|
+
constructor() {
|
|
24
|
+
super("The event must have the aggregateType is equal to the type of the aggregate that applied that event");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.InvalidEventAggregateTypeError = InvalidEventAggregateTypeError;
|
|
28
|
+
class InvalidEventAggregateIdError extends Error {
|
|
29
|
+
constructor() {
|
|
30
|
+
super("The event must have the aggregateId is equal to the id of the aggregate that applied that event");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.InvalidEventAggregateIdError = InvalidEventAggregateIdError;
|
|
34
|
+
class InvalidEventAggregateVersionError extends Error {
|
|
35
|
+
constructor() {
|
|
36
|
+
super("The event must have the aggregateVersion is equal to the next version of the aggregate that applied that event");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.InvalidEventAggregateVersionError = InvalidEventAggregateVersionError;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Class } from "../types/class";
|
|
2
|
+
import { ClassStatic } from "../types/class-static";
|
|
3
|
+
import { PropsEnvelope, PropsOf } from "./props-envelope";
|
|
4
|
+
export interface IEventAggregate {
|
|
5
|
+
readonly type: string;
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly version: number;
|
|
8
|
+
}
|
|
9
|
+
export interface IEventMetadata {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly timestamp: number;
|
|
12
|
+
readonly aggregate: IEventAggregate;
|
|
13
|
+
correlationId?: string;
|
|
14
|
+
causationId?: string;
|
|
15
|
+
}
|
|
16
|
+
export type NewEventMetadataOptions = Partial<Omit<IEventMetadata, "aggregate" | "timestamp">>;
|
|
17
|
+
export declare class Event<P extends object> extends PropsEnvelope<P> implements IEventMetadata {
|
|
18
|
+
private readonly _id;
|
|
19
|
+
private readonly _timestamp;
|
|
20
|
+
private readonly _aggregate;
|
|
21
|
+
private _correlationId?;
|
|
22
|
+
private _causationId?;
|
|
23
|
+
constructor(metadata: IEventMetadata, props: P);
|
|
24
|
+
static eventType(): string;
|
|
25
|
+
static newEvent<T extends AnyEvent>(this: EventClass<T>, aggregate: IEventAggregate, props: PropsOf<T>, metadata?: NewEventMetadataOptions): T;
|
|
26
|
+
get id(): string;
|
|
27
|
+
get timestamp(): number;
|
|
28
|
+
get aggregate(): IEventAggregate;
|
|
29
|
+
get correlationId(): string | undefined;
|
|
30
|
+
get causationId(): string | undefined;
|
|
31
|
+
setCorrelationId(correlationId: string): void;
|
|
32
|
+
setCausationId(causationId: string): void;
|
|
33
|
+
eventType(): string;
|
|
34
|
+
}
|
|
35
|
+
export type AnyEvent = Event<any>;
|
|
36
|
+
export type EventConstructorParamsWithProps<P extends object> = ConstructorParameters<typeof Event<P>>;
|
|
37
|
+
export type EventClassWithProps<P extends object> = Class<Event<P>, EventConstructorParamsWithProps<P>> & ClassStatic<typeof Event<P>>;
|
|
38
|
+
export type EventConstructorParams<T extends AnyEvent> = EventConstructorParamsWithProps<PropsOf<T>>;
|
|
39
|
+
export type EventClass<T extends AnyEvent> = Class<T, EventConstructorParams<T>> & ClassStatic<typeof Event<PropsOf<T>>>;
|
|
40
|
+
export type AnyEventClass = EventClass<AnyEvent>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Event = void 0;
|
|
4
|
+
const event_1 = require("../metadata/event");
|
|
5
|
+
const id_1 = require("../utils/id");
|
|
6
|
+
const props_envelope_1 = require("./props-envelope");
|
|
7
|
+
class Event extends props_envelope_1.PropsEnvelope {
|
|
8
|
+
constructor(metadata, props) {
|
|
9
|
+
super(props);
|
|
10
|
+
this._id = metadata.id;
|
|
11
|
+
this._timestamp = metadata.timestamp;
|
|
12
|
+
this._aggregate = metadata.aggregate;
|
|
13
|
+
this._correlationId = metadata === null || metadata === void 0 ? void 0 : metadata.correlationId;
|
|
14
|
+
this._causationId = metadata === null || metadata === void 0 ? void 0 : metadata.causationId;
|
|
15
|
+
}
|
|
16
|
+
static eventType() {
|
|
17
|
+
return (0, event_1.getEventType)(this.prototype);
|
|
18
|
+
}
|
|
19
|
+
static newEvent(aggregate, props, metadata) {
|
|
20
|
+
return new this(Object.assign({ id: (0, id_1.generatePrefixedUUID)(this.eventType()), timestamp: Date.now(), aggregate }, metadata), props);
|
|
21
|
+
}
|
|
22
|
+
get id() {
|
|
23
|
+
return this._id;
|
|
24
|
+
}
|
|
25
|
+
get timestamp() {
|
|
26
|
+
return this._timestamp;
|
|
27
|
+
}
|
|
28
|
+
get aggregate() {
|
|
29
|
+
return this._aggregate;
|
|
30
|
+
}
|
|
31
|
+
get correlationId() {
|
|
32
|
+
return this._correlationId;
|
|
33
|
+
}
|
|
34
|
+
get causationId() {
|
|
35
|
+
return this._causationId;
|
|
36
|
+
}
|
|
37
|
+
setCorrelationId(correlationId) {
|
|
38
|
+
if (!this.correlationId)
|
|
39
|
+
this._correlationId = correlationId;
|
|
40
|
+
}
|
|
41
|
+
setCausationId(causationId) {
|
|
42
|
+
if (!this.causationId)
|
|
43
|
+
this._causationId = causationId;
|
|
44
|
+
}
|
|
45
|
+
eventType() {
|
|
46
|
+
const prototype = Object.getPrototypeOf(this);
|
|
47
|
+
return (0, event_1.getEventType)(prototype);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.Event = Event;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./aggregate"), exports);
|
|
18
|
+
__exportStar(require("./entity"), exports);
|
|
19
|
+
__exportStar(require("./command"), exports);
|
|
20
|
+
__exportStar(require("./event"), exports);
|
|
21
|
+
__exportStar(require("./props-envelope"), exports);
|
|
22
|
+
__exportStar(require("./value-object"), exports);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class PropsEnvelope<P extends object> {
|
|
2
|
+
private _props;
|
|
3
|
+
constructor(props?: P);
|
|
4
|
+
validate(): void;
|
|
5
|
+
initProps(props: P): void;
|
|
6
|
+
protected get props(): P;
|
|
7
|
+
getProps(): P;
|
|
8
|
+
}
|
|
9
|
+
export type AnyPropsEnvelope = PropsEnvelope<any>;
|
|
10
|
+
export type PropsOf<T extends AnyPropsEnvelope> = T extends PropsEnvelope<infer P> ? P : never;
|
|
11
|
+
export type EmptyProps = {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PropsEnvelope = void 0;
|
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
class PropsEnvelope {
|
|
9
|
+
constructor(props) {
|
|
10
|
+
if (props)
|
|
11
|
+
this.initProps(props);
|
|
12
|
+
}
|
|
13
|
+
validate() { }
|
|
14
|
+
initProps(props) {
|
|
15
|
+
if (this.props)
|
|
16
|
+
return;
|
|
17
|
+
this._props = props;
|
|
18
|
+
this.validate();
|
|
19
|
+
}
|
|
20
|
+
get props() {
|
|
21
|
+
return this._props;
|
|
22
|
+
}
|
|
23
|
+
getProps() {
|
|
24
|
+
return lodash_1.default.cloneDeep(this._props);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.PropsEnvelope = PropsEnvelope;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Class } from "../types/class";
|
|
2
|
+
import { ClassStatic } from "../types/class-static";
|
|
3
|
+
import { PropsEnvelope, PropsOf } from "./props-envelope";
|
|
4
|
+
export declare class ValueObject<P extends object> extends PropsEnvelope<P> {
|
|
5
|
+
constructor(props: P);
|
|
6
|
+
static valueObjectType(): string;
|
|
7
|
+
valueObjectType(): string;
|
|
8
|
+
equals<V extends AnyValueObject>(vo: V): boolean;
|
|
9
|
+
with(props: Partial<P>): this;
|
|
10
|
+
}
|
|
11
|
+
export type AnyValueObject = ValueObject<any>;
|
|
12
|
+
export type ValueObjectConstructorParamsWithProps<P extends object> = ConstructorParameters<typeof ValueObject<P>>;
|
|
13
|
+
export type ValueObjectClassWithProps<P extends object> = Class<ValueObject<P>, ValueObjectConstructorParamsWithProps<P>> & ClassStatic<typeof ValueObject<P>>;
|
|
14
|
+
export type ValueObjectConstructorParams<T extends AnyValueObject> = ValueObjectConstructorParamsWithProps<PropsOf<T>>;
|
|
15
|
+
export type ValueObjectClass<T extends AnyValueObject> = Class<T, ValueObjectConstructorParams<T>> & ClassStatic<typeof ValueObject<PropsOf<T>>>;
|
|
16
|
+
export type AnyValueObjectClass = ValueObjectClass<AnyValueObject>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ValueObject = void 0;
|
|
7
|
+
const value_object_1 = require("../metadata/value-object");
|
|
8
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
9
|
+
const props_envelope_1 = require("./props-envelope");
|
|
10
|
+
class ValueObject extends props_envelope_1.PropsEnvelope {
|
|
11
|
+
constructor(props) {
|
|
12
|
+
super(props);
|
|
13
|
+
}
|
|
14
|
+
static valueObjectType() {
|
|
15
|
+
return (0, value_object_1.getValueObjectType)(this.prototype);
|
|
16
|
+
}
|
|
17
|
+
valueObjectType() {
|
|
18
|
+
const prototype = Object.getPrototypeOf(this);
|
|
19
|
+
return (0, value_object_1.getValueObjectType)(prototype);
|
|
20
|
+
}
|
|
21
|
+
equals(vo) {
|
|
22
|
+
const equalsType = vo instanceof this.constructor;
|
|
23
|
+
const equalsValue = JSON.stringify(vo) === JSON.stringify(this);
|
|
24
|
+
return equalsType && equalsValue;
|
|
25
|
+
}
|
|
26
|
+
with(props) {
|
|
27
|
+
const newProps = lodash_1.default.merge(this.getProps(), props);
|
|
28
|
+
return new this.constructor(newProps);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.ValueObject = ValueObject;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AggregateClass, AggregateCommandHandler, AggregateEventApplier, AnyAggregate } from "../base/aggregate";
|
|
2
|
+
import { AnyCommand } from "../base/command";
|
|
3
|
+
import { AnyEvent } from "../base/event";
|
|
4
|
+
import { Class } from "../types/class";
|
|
5
|
+
export declare const TypeAggregate: <T extends AnyAggregate>(aggregateType?: string) => <U extends AggregateClass<T>>(target: U) => void;
|
|
6
|
+
export declare const ApplyEvent: <E extends AnyEvent>(eventClass: Class<E>) => <T extends AggregateEventApplier<E>>(target: object, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) => void;
|
|
7
|
+
export declare const ProcessCommand: <C extends AnyCommand>(commandClass: Class<C>) => <T extends AggregateCommandHandler<C>>(target: object, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) => void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProcessCommand = exports.ApplyEvent = exports.TypeAggregate = void 0;
|
|
4
|
+
const aggregate_1 = require("../metadata/aggregate");
|
|
5
|
+
const command_1 = require("../metadata/command");
|
|
6
|
+
const event_1 = require("../metadata/event");
|
|
7
|
+
const TypeAggregate = (aggregateType) => {
|
|
8
|
+
return (target) => {
|
|
9
|
+
aggregateType = aggregateType !== null && aggregateType !== void 0 ? aggregateType : target.name;
|
|
10
|
+
(0, aggregate_1.defineAggregateType)(target.prototype, aggregateType);
|
|
11
|
+
aggregate_1.AggregateRegistry.register(aggregateType, target);
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
exports.TypeAggregate = TypeAggregate;
|
|
15
|
+
const ApplyEvent = (eventClass) => {
|
|
16
|
+
return (target, propertyKey, descriptor) => {
|
|
17
|
+
if (typeof descriptor.value === "function") {
|
|
18
|
+
const eventType = (0, event_1.getEventType)(eventClass.prototype);
|
|
19
|
+
(0, aggregate_1.defineAggregateEventApplier)(target, eventType, descriptor.value);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
exports.ApplyEvent = ApplyEvent;
|
|
24
|
+
const ProcessCommand = (commandClass) => {
|
|
25
|
+
return (target, propertyKey, descriptor) => {
|
|
26
|
+
if (typeof descriptor.value === "function") {
|
|
27
|
+
const commandType = (0, command_1.getCommandType)(commandClass.prototype);
|
|
28
|
+
(0, aggregate_1.defineAggregateCommandHandler)(target, commandType, descriptor.value);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
exports.ProcessCommand = ProcessCommand;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypeCommand = void 0;
|
|
4
|
+
const command_1 = require("../metadata/command");
|
|
5
|
+
const TypeCommand = (commandType) => {
|
|
6
|
+
return (target) => {
|
|
7
|
+
commandType = commandType !== null && commandType !== void 0 ? commandType : target.name;
|
|
8
|
+
(0, command_1.defineCommandType)(target.prototype, commandType);
|
|
9
|
+
command_1.CommandRegistry.register(commandType, target);
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
exports.TypeCommand = TypeCommand;
|