@woltz/rich-domain 1.3.0 → 1.3.2
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/aggregate-changes.js +1 -1
- package/dist/aggregate-changes.js.map +1 -1
- package/dist/base-entity.d.ts.map +1 -1
- package/dist/base-entity.js +17 -5
- package/dist/base-entity.js.map +1 -1
- package/dist/change-tracker.d.ts +1 -1
- package/dist/change-tracker.d.ts.map +1 -1
- package/dist/change-tracker.js +20 -8
- package/dist/change-tracker.js.map +1 -1
- package/dist/criteria.js +6 -5
- package/dist/criteria.js.map +1 -1
- package/dist/domain-event-bus.js +4 -4
- package/dist/domain-event-bus.js.map +1 -1
- package/dist/domain-event.js +3 -0
- package/dist/domain-event.js.map +1 -1
- package/dist/entity-changes.js +1 -0
- package/dist/entity-changes.js.map +1 -1
- package/dist/entity-schema-registry.d.ts +4 -0
- package/dist/entity-schema-registry.d.ts.map +1 -1
- package/dist/entity-schema-registry.js +8 -6
- package/dist/entity-schema-registry.js.map +1 -1
- package/dist/exceptions.js +26 -1
- package/dist/exceptions.js.map +1 -1
- package/dist/id.js +2 -0
- package/dist/id.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/paginated-result.d.ts.map +1 -1
- package/dist/paginated-result.js +9 -0
- package/dist/paginated-result.js.map +1 -1
- package/dist/repository/unit-of-work.js +3 -7
- package/dist/repository/unit-of-work.js.map +1 -1
- package/dist/types/domain.d.ts +0 -1
- package/dist/types/domain.d.ts.map +1 -1
- package/dist/validation-error.d.ts +15 -1
- package/dist/validation-error.d.ts.map +1 -1
- package/dist/validation-error.js +46 -3
- package/dist/validation-error.js.map +1 -1
- package/dist/value-object.d.ts.map +1 -1
- package/dist/value-object.js +29 -1
- package/dist/value-object.js.map +1 -1
- package/package.json +9 -11
- package/eslint.config.js +0 -57
- package/jest.config.js +0 -21
- package/src/aggregate-changes.ts +0 -444
- package/src/base-entity.ts +0 -404
- package/src/change-tracker.ts +0 -1133
- package/src/constants.ts +0 -81
- package/src/criteria.ts +0 -521
- package/src/crypto.ts +0 -31
- package/src/domain-event-bus.ts +0 -152
- package/src/domain-event.ts +0 -49
- package/src/entity-changes.ts +0 -146
- package/src/entity-schema-registry.ts +0 -502
- package/src/entity.ts +0 -5
- package/src/exceptions.ts +0 -435
- package/src/id.ts +0 -98
- package/src/index.ts +0 -52
- package/src/mapper.ts +0 -6
- package/src/paginated-result.ts +0 -238
- package/src/repository/base-repository.ts +0 -33
- package/src/repository/index.ts +0 -3
- package/src/repository/unit-of-work.ts +0 -76
- package/src/types/change-tracker.ts +0 -264
- package/src/types/criteria.ts +0 -159
- package/src/types/domain-event.ts +0 -38
- package/src/types/domain.ts +0 -34
- package/src/types/index.ts +0 -7
- package/src/types/standard-schema.ts +0 -19
- package/src/types/unit-of-work.ts +0 -46
- package/src/types/utils.ts +0 -20
- package/src/utils/criteria-operator-validation.ts +0 -209
- package/src/utils/helpers.ts +0 -34
- package/src/validation-error.ts +0 -91
- package/src/value-object.ts +0 -244
package/src/domain-event-bus.ts
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { IDomainEvent, DomainEventHandler, IDomainEventHandler } from ".";
|
|
2
|
-
|
|
3
|
-
type EventConstructor<T extends IDomainEvent = IDomainEvent> = new (
|
|
4
|
-
...args: any[]
|
|
5
|
-
) => T;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Domain Event Bus - Singleton pattern for event pub/sub
|
|
9
|
-
*/
|
|
10
|
-
export class DomainEventBus {
|
|
11
|
-
private static instance: DomainEventBus;
|
|
12
|
-
private handlers: Map<
|
|
13
|
-
string,
|
|
14
|
-
Set<DomainEventHandler<any> | IDomainEventHandler<any>>
|
|
15
|
-
> = new Map();
|
|
16
|
-
private wildcardHandlers: Set<
|
|
17
|
-
DomainEventHandler<any> | IDomainEventHandler<any>
|
|
18
|
-
> = new Set();
|
|
19
|
-
|
|
20
|
-
private constructor() {}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Get the singleton instance
|
|
24
|
-
*/
|
|
25
|
-
static getInstance(): DomainEventBus {
|
|
26
|
-
if (!DomainEventBus.instance) {
|
|
27
|
-
DomainEventBus.instance = new DomainEventBus();
|
|
28
|
-
}
|
|
29
|
-
return DomainEventBus.instance;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Subscribe to a specific event type
|
|
34
|
-
*/
|
|
35
|
-
subscribe<T extends IDomainEvent>(props: {
|
|
36
|
-
event: EventConstructor<T> | string;
|
|
37
|
-
handler: DomainEventHandler<T> | IDomainEventHandler<T>;
|
|
38
|
-
}): void {
|
|
39
|
-
const { event, handler } = props;
|
|
40
|
-
const eventName = typeof event === "string" ? event : event.name;
|
|
41
|
-
|
|
42
|
-
if (!this.handlers.has(eventName)) {
|
|
43
|
-
this.handlers.set(eventName, new Set());
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
this.handlers.get(eventName)!.add(handler);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Subscribe to all events (wildcard)
|
|
51
|
-
*/
|
|
52
|
-
subscribeAll(
|
|
53
|
-
handler:
|
|
54
|
-
| DomainEventHandler<IDomainEvent>
|
|
55
|
-
| IDomainEventHandler<IDomainEvent>
|
|
56
|
-
): void {
|
|
57
|
-
this.wildcardHandlers.add(handler);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Unsubscribe from a specific event type
|
|
62
|
-
*/
|
|
63
|
-
unsubscribe<T extends IDomainEvent>(
|
|
64
|
-
eventType: EventConstructor<T> | string,
|
|
65
|
-
handler: DomainEventHandler<T> | IDomainEventHandler<T>
|
|
66
|
-
): void {
|
|
67
|
-
const eventName =
|
|
68
|
-
typeof eventType === "string" ? eventType : eventType.name;
|
|
69
|
-
const handlers = this.handlers.get(eventName);
|
|
70
|
-
|
|
71
|
-
if (handlers) {
|
|
72
|
-
handlers.delete(handler);
|
|
73
|
-
if (handlers.size === 0) {
|
|
74
|
-
this.handlers.delete(eventName);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Unsubscribe from all events
|
|
81
|
-
*/
|
|
82
|
-
unsubscribeAll(
|
|
83
|
-
handler:
|
|
84
|
-
| DomainEventHandler<IDomainEvent>
|
|
85
|
-
| IDomainEventHandler<IDomainEvent>
|
|
86
|
-
): void {
|
|
87
|
-
this.wildcardHandlers.delete(handler);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Publish a single event
|
|
92
|
-
*/
|
|
93
|
-
async publish<T extends IDomainEvent>(event: T): Promise<void> {
|
|
94
|
-
const eventName = event.eventName;
|
|
95
|
-
const handlers = this.handlers.get(eventName) || new Set();
|
|
96
|
-
|
|
97
|
-
// Execute specific handlers
|
|
98
|
-
const specificPromises = Array.from(handlers).map((handler) =>
|
|
99
|
-
this.executeHandler(handler, event)
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
// Execute wildcard handlers
|
|
103
|
-
const wildcardPromises = Array.from(this.wildcardHandlers).map((handler) =>
|
|
104
|
-
this.executeHandler(handler, event)
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
await Promise.all([...specificPromises, ...wildcardPromises]);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Publish multiple events
|
|
112
|
-
*/
|
|
113
|
-
async publishAll(events: IDomainEvent[]): Promise<void> {
|
|
114
|
-
await Promise.all(events.map((event) => this.publish(event)));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Clear all handlers (useful for testing)
|
|
119
|
-
*/
|
|
120
|
-
clearAllHandlers(): void {
|
|
121
|
-
this.handlers.clear();
|
|
122
|
-
this.wildcardHandlers.clear();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Get count of handlers for an event type
|
|
127
|
-
*/
|
|
128
|
-
getHandlerCount(eventType: EventConstructor | string): number {
|
|
129
|
-
const eventName =
|
|
130
|
-
typeof eventType === "string" ? eventType : eventType.name;
|
|
131
|
-
return this.handlers.get(eventName)?.size || 0;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Execute a handler (function or class)
|
|
136
|
-
*/
|
|
137
|
-
private async executeHandler(
|
|
138
|
-
handler: DomainEventHandler<any> | IDomainEventHandler<any>,
|
|
139
|
-
event: IDomainEvent
|
|
140
|
-
): Promise<void> {
|
|
141
|
-
try {
|
|
142
|
-
if (typeof handler === "function") {
|
|
143
|
-
await handler(event);
|
|
144
|
-
} else {
|
|
145
|
-
await handler.handle(event);
|
|
146
|
-
}
|
|
147
|
-
} catch (error) {
|
|
148
|
-
console.error(`Error handling event ${event.eventName}:`, error);
|
|
149
|
-
// Don't throw - we don't want one handler failure to break others
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
package/src/domain-event.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { IDomainEvent } from ".";
|
|
2
|
-
import { Id } from "./id";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Base class for domain events
|
|
6
|
-
*/
|
|
7
|
-
export abstract class DomainEvent implements IDomainEvent {
|
|
8
|
-
public readonly eventId: string;
|
|
9
|
-
public readonly occurredOn: Date;
|
|
10
|
-
public readonly aggregateId: string;
|
|
11
|
-
|
|
12
|
-
constructor(aggregateId: Id | string) {
|
|
13
|
-
this.eventId = this.generateEventId();
|
|
14
|
-
this.occurredOn = new Date();
|
|
15
|
-
this.aggregateId =
|
|
16
|
-
aggregateId instanceof Id ? aggregateId.value : aggregateId;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Get the event name (defaults to class name)
|
|
21
|
-
*/
|
|
22
|
-
get eventName(): string {
|
|
23
|
-
return this.constructor.name;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
private generateEventId(): string {
|
|
27
|
-
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Convert event to JSON
|
|
32
|
-
*/
|
|
33
|
-
toJSON(): Record<string, any> {
|
|
34
|
-
return {
|
|
35
|
-
eventId: this.eventId,
|
|
36
|
-
eventName: this.eventName,
|
|
37
|
-
occurredOn: this.occurredOn.toISOString(),
|
|
38
|
-
aggregateId: this.aggregateId,
|
|
39
|
-
...this.getPayload(),
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Override this to provide event-specific data
|
|
45
|
-
*/
|
|
46
|
-
protected getPayload(): Record<string, any> {
|
|
47
|
-
return {};
|
|
48
|
-
}
|
|
49
|
-
}
|
package/src/entity-changes.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Operation,
|
|
3
|
-
CreateOperation,
|
|
4
|
-
UpdateOperation,
|
|
5
|
-
DeleteOperation,
|
|
6
|
-
} from "./types/change-tracker";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Represents the changes filtered for a specific entity.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* const changes = user.getChanges();
|
|
14
|
-
* const postChanges = changes.for('Post');
|
|
15
|
-
*
|
|
16
|
-
* if (postChanges.hasCreates()) {
|
|
17
|
-
* console.log('Created posts:', postChanges.creates);
|
|
18
|
-
* }
|
|
19
|
-
*
|
|
20
|
-
* if (postChanges.hasUpdates()) {
|
|
21
|
-
* postChanges.updates.forEach(({ entity, changed }) => {
|
|
22
|
-
* console.log(`Post ${entity.id} has changed:`, changed);
|
|
23
|
-
* });
|
|
24
|
-
* }
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export class EntityChanges<T = any> {
|
|
28
|
-
constructor(private readonly operations: Operation<T>[]) {}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Returns all created entities
|
|
32
|
-
*/
|
|
33
|
-
get creates(): T[] {
|
|
34
|
-
return this.operations
|
|
35
|
-
.filter((op): op is CreateOperation<T> => op.type === "create")
|
|
36
|
-
.map((op) => op.data);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Returns all updated entities with their changed fields
|
|
41
|
-
*/
|
|
42
|
-
get updates(): Array<{ entity: T; changed: Record<string, any> }> {
|
|
43
|
-
return this.operations
|
|
44
|
-
.filter((op): op is UpdateOperation<T> => op.type === "update")
|
|
45
|
-
.map((op) => ({
|
|
46
|
-
entity: op.data,
|
|
47
|
-
changed: op.changedFields,
|
|
48
|
-
}));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Returns all deleted entities
|
|
53
|
-
*/
|
|
54
|
-
get deletes(): T[] {
|
|
55
|
-
return this.operations
|
|
56
|
-
.filter((op): op is DeleteOperation<T> => op.type === "delete")
|
|
57
|
-
.map((op) => op.data);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Returns the IDs of the created entities
|
|
62
|
-
*/
|
|
63
|
-
get createIds(): string[] {
|
|
64
|
-
return this.operations
|
|
65
|
-
.filter((op): op is CreateOperation<T> => op.type === "create")
|
|
66
|
-
.map((op) => this.extractId(op.data))
|
|
67
|
-
.filter((id): id is string => id !== undefined);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Returns the IDs of the updated entities
|
|
72
|
-
*/
|
|
73
|
-
get updateIds(): string[] {
|
|
74
|
-
return this.operations
|
|
75
|
-
.filter((op): op is UpdateOperation<T> => op.type === "update")
|
|
76
|
-
.map((op) => op.id);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Returns the IDs of the deleted entities
|
|
81
|
-
*/
|
|
82
|
-
get deleteIds(): string[] {
|
|
83
|
-
return this.operations
|
|
84
|
-
.filter((op): op is DeleteOperation<T> => op.type === "delete")
|
|
85
|
-
.map((op) => op.id);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Checks if there are any creates
|
|
90
|
-
*/
|
|
91
|
-
hasCreates(): boolean {
|
|
92
|
-
return this.creates.length > 0;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Checks if there are any updates
|
|
97
|
-
*/
|
|
98
|
-
hasUpdates(): boolean {
|
|
99
|
-
return this.updates.length > 0;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Checks if there are any deletes
|
|
104
|
-
*/
|
|
105
|
-
hasDeletes(): boolean {
|
|
106
|
-
return this.deletes.length > 0;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Checks if there is any change
|
|
111
|
-
*/
|
|
112
|
-
hasChanges(): boolean {
|
|
113
|
-
return this.operations.length > 0;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Checks if it is empty (no changes)
|
|
118
|
-
*/
|
|
119
|
-
isEmpty(): boolean {
|
|
120
|
-
return this.operations.length === 0;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Returns the total number of operations
|
|
125
|
-
*/
|
|
126
|
-
get count(): number {
|
|
127
|
-
return this.operations.length;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Returns the raw operations (for advanced use cases)
|
|
132
|
-
*/
|
|
133
|
-
get rawOperations(): Operation<T>[] {
|
|
134
|
-
return [...this.operations];
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Extracts the ID from an entity
|
|
139
|
-
*/
|
|
140
|
-
private extractId(entity: any): string | undefined {
|
|
141
|
-
if (!entity) return undefined;
|
|
142
|
-
if (entity.id?.value) return entity.id.value;
|
|
143
|
-
if (typeof entity.id === "string") return entity.id;
|
|
144
|
-
return undefined;
|
|
145
|
-
}
|
|
146
|
-
}
|