@woltz/rich-domain 0.2.1
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/.github/workflows/ci.yml +40 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +1 -0
- package/.versionrc.json +21 -0
- package/.vscode/settings.json +3 -0
- package/CHANGELOG.md +81 -0
- package/LICENSE +21 -0
- package/README.md +712 -0
- package/commitlint.config.js +23 -0
- package/dist/base-entity.d.ts +67 -0
- package/dist/base-entity.d.ts.map +1 -0
- package/dist/base-entity.js +309 -0
- package/dist/base-entity.js.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +6 -0
- package/dist/constants.js.map +1 -0
- package/dist/criteria.d.ts +60 -0
- package/dist/criteria.d.ts.map +1 -0
- package/dist/criteria.js +214 -0
- package/dist/criteria.js.map +1 -0
- package/dist/deep-proxy.d.ts +34 -0
- package/dist/deep-proxy.d.ts.map +1 -0
- package/dist/deep-proxy.js +297 -0
- package/dist/deep-proxy.js.map +1 -0
- package/dist/domain-event-bus.d.ts +57 -0
- package/dist/domain-event-bus.d.ts.map +1 -0
- package/dist/domain-event-bus.js +112 -0
- package/dist/domain-event-bus.js.map +1 -0
- package/dist/domain-event.d.ts +55 -0
- package/dist/domain-event.d.ts.map +1 -0
- package/dist/domain-event.js +42 -0
- package/dist/domain-event.js.map +1 -0
- package/dist/entity.d.ts +13 -0
- package/dist/entity.d.ts.map +1 -0
- package/dist/entity.js +15 -0
- package/dist/entity.js.map +1 -0
- package/dist/filtering.d.ts +107 -0
- package/dist/filtering.d.ts.map +1 -0
- package/dist/filtering.js +202 -0
- package/dist/filtering.js.map +1 -0
- package/dist/id.d.ts +51 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +84 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/ordering.d.ts +93 -0
- package/dist/ordering.d.ts.map +1 -0
- package/dist/ordering.js +154 -0
- package/dist/ordering.js.map +1 -0
- package/dist/paginated-result.d.ts +62 -0
- package/dist/paginated-result.d.ts.map +1 -0
- package/dist/paginated-result.js +201 -0
- package/dist/paginated-result.js.map +1 -0
- package/dist/pagination.d.ts +218 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +281 -0
- package/dist/pagination.js.map +1 -0
- package/dist/repository/base-repository.d.ts +77 -0
- package/dist/repository/base-repository.d.ts.map +1 -0
- package/dist/repository/base-repository.js +80 -0
- package/dist/repository/base-repository.js.map +1 -0
- package/dist/repository/in-memory-repository.d.ts +46 -0
- package/dist/repository/in-memory-repository.d.ts.map +1 -0
- package/dist/repository/in-memory-repository.js +85 -0
- package/dist/repository/in-memory-repository.js.map +1 -0
- package/dist/repository/index.d.ts +42 -0
- package/dist/repository/index.d.ts.map +1 -0
- package/dist/repository/index.js +47 -0
- package/dist/repository/index.js.map +1 -0
- package/dist/repository/mapper.d.ts +56 -0
- package/dist/repository/mapper.d.ts.map +1 -0
- package/dist/repository/mapper.js +15 -0
- package/dist/repository/mapper.js.map +1 -0
- package/dist/repository/types.d.ts +87 -0
- package/dist/repository/types.d.ts.map +1 -0
- package/dist/repository/types.js +6 -0
- package/dist/repository/types.js.map +1 -0
- package/dist/repository/unit-of-work.d.ts +70 -0
- package/dist/repository/unit-of-work.d.ts.map +1 -0
- package/dist/repository/unit-of-work.js +122 -0
- package/dist/repository/unit-of-work.js.map +1 -0
- package/dist/repository.d.ts +2 -0
- package/dist/repository.d.ts.map +1 -0
- package/dist/repository.js +21 -0
- package/dist/repository.js.map +1 -0
- package/dist/specification.d.ts +102 -0
- package/dist/specification.d.ts.map +1 -0
- package/dist/specification.js +187 -0
- package/dist/specification.js.map +1 -0
- package/dist/types/criteria.d.ts +35 -0
- package/dist/types/criteria.d.ts.map +1 -0
- package/dist/types/criteria.js +17 -0
- package/dist/types/criteria.js.map +1 -0
- package/dist/types/domain.d.ts +30 -0
- package/dist/types/domain.d.ts.map +1 -0
- package/dist/types/domain.js +2 -0
- package/dist/types/domain.js.map +1 -0
- package/dist/types/history-tracker.d.ts +36 -0
- package/dist/types/history-tracker.d.ts.map +1 -0
- package/dist/types/history-tracker.js +2 -0
- package/dist/types/history-tracker.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/repository.d.ts +43 -0
- package/dist/types/repository.d.ts.map +1 -0
- package/dist/types/repository.js +2 -0
- package/dist/types/repository.js.map +1 -0
- package/dist/types/standard-schema.d.ts +15 -0
- package/dist/types/standard-schema.d.ts.map +1 -0
- package/dist/types/standard-schema.js +2 -0
- package/dist/types/standard-schema.js.map +1 -0
- package/dist/types/unit-of-work.d.ts +39 -0
- package/dist/types/unit-of-work.d.ts.map +1 -0
- package/dist/types/unit-of-work.js +2 -0
- package/dist/types/unit-of-work.js.map +1 -0
- package/dist/types/utils.d.ts +14 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/utils.js +2 -0
- package/dist/types/utils.js.map +1 -0
- package/dist/types.d.ts +88 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/dist/validation-error.d.ts +42 -0
- package/dist/validation-error.d.ts.map +1 -0
- package/dist/validation-error.js +73 -0
- package/dist/validation-error.js.map +1 -0
- package/dist/value-object.d.ts +47 -0
- package/dist/value-object.d.ts.map +1 -0
- package/dist/value-object.js +136 -0
- package/dist/value-object.js.map +1 -0
- package/eslint.config.js +51 -0
- package/jest.config.js +21 -0
- package/package.json +58 -0
- package/src/base-entity.ts +401 -0
- package/src/constants.ts +7 -0
- package/src/criteria.ts +291 -0
- package/src/deep-proxy.ts +339 -0
- package/src/domain-event-bus.ts +166 -0
- package/src/domain-event.ts +90 -0
- package/src/entity.ts +16 -0
- package/src/id.ts +94 -0
- package/src/index.ts +33 -0
- package/src/paginated-result.ts +274 -0
- package/src/repository/base-repository.ts +152 -0
- package/src/repository/in-memory-repository.ts +104 -0
- package/src/repository/index.ts +55 -0
- package/src/repository/mapper.ts +74 -0
- package/src/repository/unit-of-work.ts +148 -0
- package/src/types/criteria.ts +79 -0
- package/src/types/domain.ts +37 -0
- package/src/types/history-tracker.ts +45 -0
- package/src/types/index.ts +7 -0
- package/src/types/repository.ts +51 -0
- package/src/types/standard-schema.ts +19 -0
- package/src/types/unit-of-work.ts +46 -0
- package/src/types/utils.ts +29 -0
- package/src/validation-error.ts +97 -0
- package/src/value-object.ts +187 -0
- package/tests/criteria.test.ts +432 -0
- package/tests/domain-events.test.ts +445 -0
- package/tests/entity-equality.test.ts +487 -0
- package/tests/entity-validation.test.ts +339 -0
- package/tests/entity.test.ts +33 -0
- package/tests/history-tracker.spec.ts +667 -0
- package/tests/id.test.ts +341 -0
- package/tests/repository.test.ts +641 -0
- package/tests/to-json.test.ts +91 -0
- package/tests/utils.ts +151 -0
- package/tests/value-object-validation.test.ts +228 -0
- package/tests/value-objects.test.ts +52 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Domain Event Bus - Pub/Sub for Domain Events
|
|
3
|
+
// ============================================================================
|
|
4
|
+
/**
|
|
5
|
+
* Domain Event Bus - Singleton pattern for event pub/sub
|
|
6
|
+
*/
|
|
7
|
+
export class DomainEventBus {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.handlers = new Map();
|
|
10
|
+
this.wildcardHandlers = new Set();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get the singleton instance
|
|
14
|
+
*/
|
|
15
|
+
static getInstance() {
|
|
16
|
+
if (!DomainEventBus.instance) {
|
|
17
|
+
DomainEventBus.instance = new DomainEventBus();
|
|
18
|
+
}
|
|
19
|
+
return DomainEventBus.instance;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Subscribe to a specific event type
|
|
23
|
+
*/
|
|
24
|
+
subscribe(eventType, handler) {
|
|
25
|
+
const eventName = typeof eventType === "string" ? eventType : eventType.name;
|
|
26
|
+
if (!this.handlers.has(eventName)) {
|
|
27
|
+
this.handlers.set(eventName, new Set());
|
|
28
|
+
}
|
|
29
|
+
this.handlers.get(eventName).add(handler);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Subscribe to all events (wildcard)
|
|
33
|
+
*/
|
|
34
|
+
subscribeAll(handler) {
|
|
35
|
+
this.wildcardHandlers.add(handler);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Unsubscribe from a specific event type
|
|
39
|
+
*/
|
|
40
|
+
unsubscribe(eventType, handler) {
|
|
41
|
+
const eventName = typeof eventType === "string" ? eventType : eventType.name;
|
|
42
|
+
const handlers = this.handlers.get(eventName);
|
|
43
|
+
if (handlers) {
|
|
44
|
+
handlers.delete(handler);
|
|
45
|
+
if (handlers.size === 0) {
|
|
46
|
+
this.handlers.delete(eventName);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Unsubscribe from all events
|
|
52
|
+
*/
|
|
53
|
+
unsubscribeAll(handler) {
|
|
54
|
+
this.wildcardHandlers.delete(handler);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Publish a single event
|
|
58
|
+
*/
|
|
59
|
+
async publish(event) {
|
|
60
|
+
const eventName = event.eventName;
|
|
61
|
+
const handlers = this.handlers.get(eventName) || new Set();
|
|
62
|
+
// Execute specific handlers
|
|
63
|
+
const specificPromises = Array.from(handlers).map((handler) => this.executeHandler(handler, event));
|
|
64
|
+
// Execute wildcard handlers
|
|
65
|
+
const wildcardPromises = Array.from(this.wildcardHandlers).map((handler) => this.executeHandler(handler, event));
|
|
66
|
+
await Promise.all([...specificPromises, ...wildcardPromises]);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Publish multiple events
|
|
70
|
+
*/
|
|
71
|
+
async publishAll(events) {
|
|
72
|
+
await Promise.all(events.map((event) => this.publish(event)));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Clear all handlers (useful for testing)
|
|
76
|
+
*/
|
|
77
|
+
clearAllHandlers() {
|
|
78
|
+
this.handlers.clear();
|
|
79
|
+
this.wildcardHandlers.clear();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get count of handlers for an event type
|
|
83
|
+
*/
|
|
84
|
+
getHandlerCount(eventType) {
|
|
85
|
+
const eventName = typeof eventType === "string" ? eventType : eventType.name;
|
|
86
|
+
return this.handlers.get(eventName)?.size || 0;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Execute a handler (function or class)
|
|
90
|
+
*/
|
|
91
|
+
async executeHandler(handler, event) {
|
|
92
|
+
try {
|
|
93
|
+
if (typeof handler === "function") {
|
|
94
|
+
await handler(event);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
await handler.handle(event);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
console.error(`Error handling event ${event.eventName}:`, error);
|
|
102
|
+
// Don't throw - we don't want one handler failure to break others
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Convenience function to get the event bus instance
|
|
108
|
+
*/
|
|
109
|
+
export function getEventBus() {
|
|
110
|
+
return DomainEventBus.getInstance();
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=domain-event-bus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-event-bus.js","sourceRoot":"","sources":["../src/domain-event-bus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Id } from "./id";
|
|
2
|
+
/**
|
|
3
|
+
* Interface for all domain events
|
|
4
|
+
*/
|
|
5
|
+
export interface IDomainEvent {
|
|
6
|
+
/**
|
|
7
|
+
* Unique identifier for this event occurrence
|
|
8
|
+
*/
|
|
9
|
+
readonly eventId: string;
|
|
10
|
+
/**
|
|
11
|
+
* When the event occurred
|
|
12
|
+
*/
|
|
13
|
+
readonly occurredOn: Date;
|
|
14
|
+
/**
|
|
15
|
+
* Name/type of the event (e.g., "UserCreated", "OrderPlaced")
|
|
16
|
+
*/
|
|
17
|
+
readonly eventName: string;
|
|
18
|
+
/**
|
|
19
|
+
* ID of the aggregate that raised this event
|
|
20
|
+
*/
|
|
21
|
+
readonly aggregateId: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Base class for domain events
|
|
25
|
+
*/
|
|
26
|
+
export declare abstract class DomainEvent implements IDomainEvent {
|
|
27
|
+
readonly eventId: string;
|
|
28
|
+
readonly occurredOn: Date;
|
|
29
|
+
readonly aggregateId: string;
|
|
30
|
+
constructor(aggregateId: Id | string);
|
|
31
|
+
/**
|
|
32
|
+
* Get the event name (defaults to class name)
|
|
33
|
+
*/
|
|
34
|
+
get eventName(): string;
|
|
35
|
+
private generateEventId;
|
|
36
|
+
/**
|
|
37
|
+
* Convert event to JSON
|
|
38
|
+
*/
|
|
39
|
+
toJSON(): Record<string, any>;
|
|
40
|
+
/**
|
|
41
|
+
* Override this to provide event-specific data
|
|
42
|
+
*/
|
|
43
|
+
protected getPayload(): Record<string, any>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Event handler function type
|
|
47
|
+
*/
|
|
48
|
+
export type DomainEventHandler<T extends IDomainEvent = IDomainEvent> = (event: T) => void | Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Event handler class type
|
|
51
|
+
*/
|
|
52
|
+
export interface IDomainEventHandler<T extends IDomainEvent = IDomainEvent> {
|
|
53
|
+
handle(event: T): void | Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=domain-event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-event.d.ts","sourceRoot":"","sources":["../src/domain-event.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,8BAAsB,WAAY,YAAW,YAAY;IACvD,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,SAAgB,UAAU,EAAE,IAAI,CAAC;IACjC,SAAgB,WAAW,EAAE,MAAM,CAAC;gBAExB,WAAW,EAAE,EAAE,GAAG,MAAM;IAMpC;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAU7B;;OAEG;IACH,SAAS,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;CAG5C;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,IAAI,CACtE,KAAK,EAAE,CAAC,KACL,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY;IACxE,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Domain Events - Event-Driven Architecture Support
|
|
3
|
+
// ============================================================================
|
|
4
|
+
import { Id } from "./id";
|
|
5
|
+
/**
|
|
6
|
+
* Base class for domain events
|
|
7
|
+
*/
|
|
8
|
+
export class DomainEvent {
|
|
9
|
+
constructor(aggregateId) {
|
|
10
|
+
this.eventId = this.generateEventId();
|
|
11
|
+
this.occurredOn = new Date();
|
|
12
|
+
this.aggregateId = aggregateId instanceof Id ? aggregateId.value : aggregateId;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get the event name (defaults to class name)
|
|
16
|
+
*/
|
|
17
|
+
get eventName() {
|
|
18
|
+
return this.constructor.name;
|
|
19
|
+
}
|
|
20
|
+
generateEventId() {
|
|
21
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convert event to JSON
|
|
25
|
+
*/
|
|
26
|
+
toJSON() {
|
|
27
|
+
return {
|
|
28
|
+
eventId: this.eventId,
|
|
29
|
+
eventName: this.eventName,
|
|
30
|
+
occurredOn: this.occurredOn.toISOString(),
|
|
31
|
+
aggregateId: this.aggregateId,
|
|
32
|
+
...this.getPayload(),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Override this to provide event-specific data
|
|
37
|
+
*/
|
|
38
|
+
getPayload() {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=domain-event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-event.js","sourceRoot":"","sources":["../src/domain-event.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,oDAAoD;AACpD,+EAA+E;AAE/E,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AA2B1B;;GAEG;AACH,MAAM,OAAgB,WAAW;IAK/B,YAAY,WAAwB;QAClC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACtC,IAAI,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,WAAW,YAAY,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC;IACjF,CAAC;IAED;;OAEG;IACH,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/B,CAAC;IAEO,eAAe;QACrB,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACpE,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE;YACzC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,GAAG,IAAI,CAAC,UAAU,EAAE;SACrB,CAAC;IACJ,CAAC;IAED;;OAEG;IACO,UAAU;QAClB,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
|
package/dist/entity.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseEntity } from './base-entity';
|
|
2
|
+
import { BaseProps } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Entity - Has identity and lifecycle, but is not an aggregate root
|
|
5
|
+
*/
|
|
6
|
+
export declare class Entity<T extends BaseProps> extends BaseEntity<T> {
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Aggregate - Aggregate root that manages a consistency boundary
|
|
10
|
+
*/
|
|
11
|
+
export declare class Aggregate<T extends BaseProps> extends BaseEntity<T> {
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC;;GAEG;AACH,qBAAa,MAAM,CAAC,CAAC,SAAS,SAAS,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;CAAG;AAEjE;;GAEG;AACH,qBAAa,SAAS,CAAC,CAAC,SAAS,SAAS,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;CAAG"}
|
package/dist/entity.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Entity & Aggregate Classes
|
|
3
|
+
// ============================================================================
|
|
4
|
+
import { BaseEntity } from './base-entity';
|
|
5
|
+
/**
|
|
6
|
+
* Entity - Has identity and lifecycle, but is not an aggregate root
|
|
7
|
+
*/
|
|
8
|
+
export class Entity extends BaseEntity {
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Aggregate - Aggregate root that manages a consistency boundary
|
|
12
|
+
*/
|
|
13
|
+
export class Aggregate extends BaseEntity {
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity.js","sourceRoot":"","sources":["../src/entity.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,6BAA6B;AAC7B,+EAA+E;AAE/E,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C;;GAEG;AACH,MAAM,OAAO,MAA4B,SAAQ,UAAa;CAAG;AAEjE;;GAEG;AACH,MAAM,OAAO,SAA+B,SAAQ,UAAa;CAAG"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported filter operators
|
|
3
|
+
*/
|
|
4
|
+
export type FilterOperator = "equals" | "notEquals" | "greaterThan" | "greaterThanOrEquals" | "lessThan" | "lessThanOrEquals" | "in" | "notIn" | "contains" | "startsWith" | "endsWith" | "isNull" | "isNotNull";
|
|
5
|
+
/**
|
|
6
|
+
* Configuration for a single filter
|
|
7
|
+
*/
|
|
8
|
+
export interface FilterConfig<T> {
|
|
9
|
+
field: keyof T | string;
|
|
10
|
+
operator: FilterOperator;
|
|
11
|
+
value?: any;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Represents a single filter condition
|
|
15
|
+
* Can be used for in-memory filtering or converted to database-specific queries
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const filter = new Filter('age', 'greaterThan', 18);
|
|
20
|
+
* const adults = users.filter(filter.predicateFn());
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare class Filter<T> {
|
|
24
|
+
private readonly _field;
|
|
25
|
+
private readonly _operator;
|
|
26
|
+
private readonly _value?;
|
|
27
|
+
constructor(field: keyof T | string, operator: FilterOperator, value?: any);
|
|
28
|
+
/**
|
|
29
|
+
* Gets the field to filter
|
|
30
|
+
*/
|
|
31
|
+
get field(): keyof T | string;
|
|
32
|
+
/**
|
|
33
|
+
* Gets the filter operator
|
|
34
|
+
*/
|
|
35
|
+
get operator(): FilterOperator;
|
|
36
|
+
/**
|
|
37
|
+
* Gets the filter value
|
|
38
|
+
*/
|
|
39
|
+
get value(): any;
|
|
40
|
+
/**
|
|
41
|
+
* Returns configuration object for serialization
|
|
42
|
+
*/
|
|
43
|
+
toConfig(): FilterConfig<T>;
|
|
44
|
+
/**
|
|
45
|
+
* Checks if the operator requires a value
|
|
46
|
+
* @private
|
|
47
|
+
*/
|
|
48
|
+
private requiresValue;
|
|
49
|
+
/**
|
|
50
|
+
* Creates a predicate function for in-memory filtering
|
|
51
|
+
* Handles nested properties using dot notation (e.g., "address.city")
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const filter = new Filter<User>('age', 'greaterThan', 18);
|
|
56
|
+
* const adults = users.filter(filter.predicateFn());
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
predicateFn(): (item: T) => boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Gets nested property value using dot notation
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
private getNestedValue;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Logical operator for combining filters
|
|
68
|
+
*/
|
|
69
|
+
export type LogicalOperator = "and" | "or";
|
|
70
|
+
/**
|
|
71
|
+
* Represents a composite filter that combines multiple filters with AND/OR logic
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const composite = new CompositeFilter<User>('and', [
|
|
76
|
+
* new Filter('age', 'greaterThan', 18),
|
|
77
|
+
* new Filter('status', 'equals', 'active')
|
|
78
|
+
* ]);
|
|
79
|
+
* const filtered = users.filter(composite.predicateFn());
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare class CompositeFilter<T> {
|
|
83
|
+
private readonly _operator;
|
|
84
|
+
private readonly _filters;
|
|
85
|
+
constructor(operator: LogicalOperator, filters: (Filter<T> | CompositeFilter<T>)[]);
|
|
86
|
+
/**
|
|
87
|
+
* Gets the logical operator
|
|
88
|
+
*/
|
|
89
|
+
get operator(): LogicalOperator;
|
|
90
|
+
/**
|
|
91
|
+
* Gets all filters
|
|
92
|
+
*/
|
|
93
|
+
get filters(): readonly (Filter<T> | CompositeFilter<T>)[];
|
|
94
|
+
/**
|
|
95
|
+
* Creates a predicate function that applies the logical operator
|
|
96
|
+
*/
|
|
97
|
+
predicateFn(): (item: T) => boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Adds another filter with AND logic
|
|
100
|
+
*/
|
|
101
|
+
and(filter: Filter<T> | CompositeFilter<T>): CompositeFilter<T>;
|
|
102
|
+
/**
|
|
103
|
+
* Adds another filter with OR logic
|
|
104
|
+
*/
|
|
105
|
+
or(filter: Filter<T> | CompositeFilter<T>): CompositeFilter<T>;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=filtering.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filtering.d.ts","sourceRoot":"","sources":["../src/filtering.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,WAAW,GACX,aAAa,GACb,qBAAqB,GACrB,UAAU,GACV,kBAAkB,GAClB,IAAI,GACJ,OAAO,GACP,UAAU,GACV,YAAY,GACZ,UAAU,GACV,QAAQ,GACR,WAAW,CAAC;AAEhB;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC;IACxB,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAMD;;;;;;;;;GASG;AACH,qBAAa,MAAM,CAAC,CAAC;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAM;gBAElB,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,GAAG;IAW1E;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAAC,GAAG,MAAM,CAE5B;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,cAAc,CAE7B;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,GAAG,CAEf;IAED;;OAEG;IACH,QAAQ,IAAI,YAAY,CAAC,CAAC,CAAC;IAQ3B;;;OAGG;IACH,OAAO,CAAC,aAAa;IAIrB;;;;;;;;;OASG;IACH,WAAW,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO;IA+DnC;;;OAGG;IACH,OAAO,CAAC,cAAc;CAGvB;AAMD;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,IAAI,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,qBAAa,eAAe,CAAC,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;gBAElD,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE;IAQlF;;OAEG;IACH,IAAI,QAAQ,IAAI,eAAe,CAE9B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAEzD;IAED;;OAEG;IACH,WAAW,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO;IAWnC;;OAEG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;IAU/D;;OAEG;IACH,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;CAS/D"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// Filtering System
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Provides filtering/where clause capabilities for queries and in-memory collections
|
|
6
|
+
// Supports common comparison operators and can be extended for custom operators
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.CompositeFilter = exports.Filter = void 0;
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Filter Class
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Represents a single filter condition
|
|
14
|
+
* Can be used for in-memory filtering or converted to database-specific queries
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const filter = new Filter('age', 'greaterThan', 18);
|
|
19
|
+
* const adults = users.filter(filter.predicateFn());
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
class Filter {
|
|
23
|
+
constructor(field, operator, value) {
|
|
24
|
+
this._field = field;
|
|
25
|
+
this._operator = operator;
|
|
26
|
+
this._value = value;
|
|
27
|
+
// Validate that value is provided when required
|
|
28
|
+
if (this.requiresValue() && value === undefined) {
|
|
29
|
+
throw new Error(`Filter operator '${operator}' requires a value`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Gets the field to filter
|
|
34
|
+
*/
|
|
35
|
+
get field() {
|
|
36
|
+
return this._field;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Gets the filter operator
|
|
40
|
+
*/
|
|
41
|
+
get operator() {
|
|
42
|
+
return this._operator;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Gets the filter value
|
|
46
|
+
*/
|
|
47
|
+
get value() {
|
|
48
|
+
return this._value;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Returns configuration object for serialization
|
|
52
|
+
*/
|
|
53
|
+
toConfig() {
|
|
54
|
+
return {
|
|
55
|
+
field: this._field,
|
|
56
|
+
operator: this._operator,
|
|
57
|
+
value: this._value,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Checks if the operator requires a value
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
requiresValue() {
|
|
65
|
+
return this._operator !== "isNull" && this._operator !== "isNotNull";
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Creates a predicate function for in-memory filtering
|
|
69
|
+
* Handles nested properties using dot notation (e.g., "address.city")
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const filter = new Filter<User>('age', 'greaterThan', 18);
|
|
74
|
+
* const adults = users.filter(filter.predicateFn());
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
predicateFn() {
|
|
78
|
+
return (item) => {
|
|
79
|
+
const fieldValue = this.getNestedValue(item, this._field);
|
|
80
|
+
switch (this._operator) {
|
|
81
|
+
case "equals":
|
|
82
|
+
return fieldValue === this._value;
|
|
83
|
+
case "notEquals":
|
|
84
|
+
return fieldValue !== this._value;
|
|
85
|
+
case "greaterThan":
|
|
86
|
+
return fieldValue > this._value;
|
|
87
|
+
case "greaterThanOrEquals":
|
|
88
|
+
return fieldValue >= this._value;
|
|
89
|
+
case "lessThan":
|
|
90
|
+
return fieldValue < this._value;
|
|
91
|
+
case "lessThanOrEquals":
|
|
92
|
+
return fieldValue <= this._value;
|
|
93
|
+
case "in":
|
|
94
|
+
return Array.isArray(this._value) && this._value.includes(fieldValue);
|
|
95
|
+
case "notIn":
|
|
96
|
+
return Array.isArray(this._value) && !this._value.includes(fieldValue);
|
|
97
|
+
case "contains":
|
|
98
|
+
return (typeof fieldValue === "string" &&
|
|
99
|
+
typeof this._value === "string" &&
|
|
100
|
+
fieldValue.includes(this._value));
|
|
101
|
+
case "startsWith":
|
|
102
|
+
return (typeof fieldValue === "string" &&
|
|
103
|
+
typeof this._value === "string" &&
|
|
104
|
+
fieldValue.startsWith(this._value));
|
|
105
|
+
case "endsWith":
|
|
106
|
+
return (typeof fieldValue === "string" &&
|
|
107
|
+
typeof this._value === "string" &&
|
|
108
|
+
fieldValue.endsWith(this._value));
|
|
109
|
+
case "isNull":
|
|
110
|
+
return fieldValue === null || fieldValue === undefined;
|
|
111
|
+
case "isNotNull":
|
|
112
|
+
return fieldValue !== null && fieldValue !== undefined;
|
|
113
|
+
default:
|
|
114
|
+
// This should never happen with proper typing
|
|
115
|
+
throw new Error(`Unknown filter operator: ${this._operator}`);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Gets nested property value using dot notation
|
|
121
|
+
* @private
|
|
122
|
+
*/
|
|
123
|
+
getNestedValue(obj, path) {
|
|
124
|
+
return path.split(".").reduce((current, prop) => current?.[prop], obj);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.Filter = Filter;
|
|
128
|
+
/**
|
|
129
|
+
* Represents a composite filter that combines multiple filters with AND/OR logic
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const composite = new CompositeFilter<User>('and', [
|
|
134
|
+
* new Filter('age', 'greaterThan', 18),
|
|
135
|
+
* new Filter('status', 'equals', 'active')
|
|
136
|
+
* ]);
|
|
137
|
+
* const filtered = users.filter(composite.predicateFn());
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
class CompositeFilter {
|
|
141
|
+
constructor(operator, filters) {
|
|
142
|
+
if (filters.length === 0) {
|
|
143
|
+
throw new Error("At least one filter is required");
|
|
144
|
+
}
|
|
145
|
+
this._operator = operator;
|
|
146
|
+
this._filters = filters;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Gets the logical operator
|
|
150
|
+
*/
|
|
151
|
+
get operator() {
|
|
152
|
+
return this._operator;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Gets all filters
|
|
156
|
+
*/
|
|
157
|
+
get filters() {
|
|
158
|
+
return this._filters;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Creates a predicate function that applies the logical operator
|
|
162
|
+
*/
|
|
163
|
+
predicateFn() {
|
|
164
|
+
return (item) => {
|
|
165
|
+
if (this._operator === "and") {
|
|
166
|
+
return this._filters.every((filter) => filter.predicateFn()(item));
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// OR
|
|
170
|
+
return this._filters.some((filter) => filter.predicateFn()(item));
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Adds another filter with AND logic
|
|
176
|
+
*/
|
|
177
|
+
and(filter) {
|
|
178
|
+
if (this._operator === "and") {
|
|
179
|
+
// Flatten if already AND
|
|
180
|
+
return new CompositeFilter("and", [...this._filters, filter]);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
// Wrap in new AND
|
|
184
|
+
return new CompositeFilter("and", [this, filter]);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Adds another filter with OR logic
|
|
189
|
+
*/
|
|
190
|
+
or(filter) {
|
|
191
|
+
if (this._operator === "or") {
|
|
192
|
+
// Flatten if already OR
|
|
193
|
+
return new CompositeFilter("or", [...this._filters, filter]);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// Wrap in new OR
|
|
197
|
+
return new CompositeFilter("or", [this, filter]);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
exports.CompositeFilter = CompositeFilter;
|
|
202
|
+
//# sourceMappingURL=filtering.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filtering.js","sourceRoot":"","sources":["../src/filtering.ts"],"names":[],"mappings":"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"}
|
package/dist/id.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export declare class Id {
|
|
2
|
+
private readonly _value;
|
|
3
|
+
private readonly _isNew;
|
|
4
|
+
/**
|
|
5
|
+
* Create a new Id
|
|
6
|
+
* @param value - Optional existing ID value. If not provided, generates a new UUID.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // New entity (generates UUID)
|
|
10
|
+
* const newId = new Id();
|
|
11
|
+
* newId.isNew // true
|
|
12
|
+
*
|
|
13
|
+
* // Existing entity (uses provided ID)
|
|
14
|
+
* const existingId = new Id("550e8400-e29b-41d4-a716-446655440000");
|
|
15
|
+
* existingId.isNew // false
|
|
16
|
+
*/
|
|
17
|
+
constructor(value?: string);
|
|
18
|
+
/**
|
|
19
|
+
* Get the string value of the ID
|
|
20
|
+
*/
|
|
21
|
+
get value(): string;
|
|
22
|
+
/**
|
|
23
|
+
* Check if this ID represents a new entity
|
|
24
|
+
*/
|
|
25
|
+
get isNew(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Convert to string (for JSON serialization and comparisons)
|
|
28
|
+
*/
|
|
29
|
+
toString(): string;
|
|
30
|
+
/**
|
|
31
|
+
* Convert to JSON (returns the string value)
|
|
32
|
+
*/
|
|
33
|
+
toJSON(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Check equality with another Id or string
|
|
36
|
+
*/
|
|
37
|
+
equals(other: Id | string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Generate a UUID v4
|
|
40
|
+
*/
|
|
41
|
+
private generateUUID;
|
|
42
|
+
/**
|
|
43
|
+
* Create a new Id (convenience static method)
|
|
44
|
+
*/
|
|
45
|
+
static create(): Id;
|
|
46
|
+
/**
|
|
47
|
+
* Create an Id from an existing value
|
|
48
|
+
*/
|
|
49
|
+
static from(value: string): Id;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=id.d.ts.map
|
package/dist/id.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"AAKA,qBAAa,EAAE;IACb,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IAEjC;;;;;;;;;;;;OAYG;gBACS,KAAK,CAAC,EAAE,MAAM;IAY1B;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAElB;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED;;OAEG;IACH,QAAQ,IAAI,MAAM;IAIlB;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,EAAE,GAAG,MAAM,GAAG,OAAO;IAOnC;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,MAAM,CAAC,MAAM,IAAI,EAAE;IAInB;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,EAAE;CAG/B"}
|