@cratis/chronicle 5.0.0 → 5.1.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/projections/declarative/FromEveryBuilder.d.ts +6 -0
- package/dist/projections/declarative/FromEveryBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/FromEveryBuilder.js +27 -0
- package/dist/projections/declarative/FromEveryBuilder.js.map +1 -1
- package/dist/projections/declarative/IFromEveryBuilder.d.ts +22 -0
- package/dist/projections/declarative/IFromEveryBuilder.d.ts.map +1 -1
- package/package.json +5 -5
- package/projections/declarative/FromEveryBuilder.ts +30 -0
- package/projections/declarative/IFromEveryBuilder.ts +25 -0
- package/projections/declarative/ProjectionBuilderFor.spec.ts +58 -0
|
@@ -17,6 +17,12 @@ export declare class FromEveryBuilder<TReadModel> implements IFromEveryBuilder<T
|
|
|
17
17
|
/** @inheritdoc */
|
|
18
18
|
set(readModelPropertyAccessor: PropertyAccessor<TReadModel>): IAllSetBuilder<TReadModel, IFromEveryBuilder<TReadModel>>;
|
|
19
19
|
/** @inheritdoc */
|
|
20
|
+
count(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel>;
|
|
21
|
+
/** @inheritdoc */
|
|
22
|
+
increment(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel>;
|
|
23
|
+
/** @inheritdoc */
|
|
24
|
+
decrement(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel>;
|
|
25
|
+
/** @inheritdoc */
|
|
20
26
|
excludeChildProjections(): IFromEveryBuilder<TReadModel>;
|
|
21
27
|
}
|
|
22
28
|
//# sourceMappingURL=FromEveryBuilder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FromEveryBuilder.d.ts","sourceRoot":"","sources":["../../../projections/declarative/FromEveryBuilder.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAoC,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,eAAe,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,qBAAa,gBAAgB,CAAC,UAAU,CAAE,YAAW,iBAAiB,CAAC,UAAU,CAAC;IAC9E,QAAQ,CAAC,KAAK,EAAE,cAAc,CAG5B;IAEF,kBAAkB;IAClB,GAAG,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,UAAU,CAAC,GAAG,cAAc,CAAC,UAAU,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAavH,kBAAkB;IAClB,uBAAuB,IAAI,iBAAiB,CAAC,UAAU,CAAC;CAI3D"}
|
|
1
|
+
{"version":3,"file":"FromEveryBuilder.d.ts","sourceRoot":"","sources":["../../../projections/declarative/FromEveryBuilder.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAoC,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,eAAe,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,qBAAa,gBAAgB,CAAC,UAAU,CAAE,YAAW,iBAAiB,CAAC,UAAU,CAAC;IAC9E,QAAQ,CAAC,KAAK,EAAE,cAAc,CAG5B;IAEF,kBAAkB;IAClB,GAAG,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,UAAU,CAAC,GAAG,cAAc,CAAC,UAAU,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAavH,kBAAkB;IAClB,KAAK,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,UAAU,CAAC,EAAE,mBAAmB,EAAE,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC;IAS1H,kBAAkB;IAClB,SAAS,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,UAAU,CAAC,EAAE,mBAAmB,EAAE,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC;IAS9H,kBAAkB;IAClB,SAAS,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,UAAU,CAAC,EAAE,mBAAmB,EAAE,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC;IAS9H,kBAAkB;IAClB,uBAAuB,IAAI,iBAAiB,CAAC,UAAU,CAAC;CAI3D"}
|
|
@@ -20,6 +20,33 @@ export class FromEveryBuilder {
|
|
|
20
20
|
return new AllSetBuilder(property, (targetProperty, expression) => { this.entry.properties[targetProperty] = expression; }, this);
|
|
21
21
|
}
|
|
22
22
|
/** @inheritdoc */
|
|
23
|
+
count(readModelPropertyAccessor, contextPropertyName) {
|
|
24
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
25
|
+
const proxy = new Proxy({}, handler);
|
|
26
|
+
readModelPropertyAccessor(proxy);
|
|
27
|
+
const property = handler.property;
|
|
28
|
+
this.entry.properties[`${property}.$eventContext.${contextPropertyName}`] = '$count';
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
/** @inheritdoc */
|
|
32
|
+
increment(readModelPropertyAccessor, contextPropertyName) {
|
|
33
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
34
|
+
const proxy = new Proxy({}, handler);
|
|
35
|
+
readModelPropertyAccessor(proxy);
|
|
36
|
+
const property = handler.property;
|
|
37
|
+
this.entry.properties[`${property}.$eventContext.${contextPropertyName}`] = '$increment';
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
/** @inheritdoc */
|
|
41
|
+
decrement(readModelPropertyAccessor, contextPropertyName) {
|
|
42
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
43
|
+
const proxy = new Proxy({}, handler);
|
|
44
|
+
readModelPropertyAccessor(proxy);
|
|
45
|
+
const property = handler.property;
|
|
46
|
+
this.entry.properties[`${property}.$eventContext.${contextPropertyName}`] = '$decrement';
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
/** @inheritdoc */
|
|
23
50
|
excludeChildProjections() {
|
|
24
51
|
this.entry.includeChildren = false;
|
|
25
52
|
return this;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FromEveryBuilder.js","sourceRoot":"","sources":["../../../projections/declarative/FromEveryBuilder.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,qGAAqG;AAErG,OAAO,EAAoB,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AAG1F,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAUhD;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IAChB,KAAK,GAAmB;QAC7B,UAAU,EAAE,EAAE;QACd,eAAe,EAAE,IAAI;KACxB,CAAC;IAEF,kBAAkB;IAClB,GAAG,CAAC,yBAAuD;QACvD,MAAM,OAAO,GAAG,IAAI,gCAAgC,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACrC,yBAAyB,CAAC,KAAmB,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAElC,OAAO,IAAI,aAAa,CACpB,QAAQ,EACR,CAAC,cAAc,EAAE,UAAU,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EACvF,IAAI,CACP,CAAC;IACN,CAAC;IAED,kBAAkB;IAClB,uBAAuB;QACnB,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC;QACnC,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ"}
|
|
1
|
+
{"version":3,"file":"FromEveryBuilder.js","sourceRoot":"","sources":["../../../projections/declarative/FromEveryBuilder.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,qGAAqG;AAErG,OAAO,EAAoB,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AAG1F,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAUhD;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IAChB,KAAK,GAAmB;QAC7B,UAAU,EAAE,EAAE;QACd,eAAe,EAAE,IAAI;KACxB,CAAC;IAEF,kBAAkB;IAClB,GAAG,CAAC,yBAAuD;QACvD,MAAM,OAAO,GAAG,IAAI,gCAAgC,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACrC,yBAAyB,CAAC,KAAmB,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAElC,OAAO,IAAI,aAAa,CACpB,QAAQ,EACR,CAAC,cAAc,EAAE,UAAU,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EACvF,IAAI,CACP,CAAC;IACN,CAAC;IAED,kBAAkB;IAClB,KAAK,CAAC,yBAAuD,EAAE,mBAA2B;QACtF,MAAM,OAAO,GAAG,IAAI,gCAAgC,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACrC,yBAAyB,CAAC,KAAmB,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,QAAQ,kBAAkB,mBAAmB,EAAE,CAAC,GAAG,QAAQ,CAAC;QACrF,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,kBAAkB;IAClB,SAAS,CAAC,yBAAuD,EAAE,mBAA2B;QAC1F,MAAM,OAAO,GAAG,IAAI,gCAAgC,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACrC,yBAAyB,CAAC,KAAmB,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,QAAQ,kBAAkB,mBAAmB,EAAE,CAAC,GAAG,YAAY,CAAC;QACzF,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,kBAAkB;IAClB,SAAS,CAAC,yBAAuD,EAAE,mBAA2B;QAC1F,MAAM,OAAO,GAAG,IAAI,gCAAgC,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACrC,yBAAyB,CAAC,KAAmB,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,QAAQ,kBAAkB,mBAAmB,EAAE,CAAC,GAAG,YAAY,CAAC;QACzF,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,kBAAkB;IAClB,uBAAuB;QACnB,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC;QACnC,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ"}
|
|
@@ -11,6 +11,28 @@ export interface IFromEveryBuilder<TReadModel> {
|
|
|
11
11
|
* @returns An all-set builder for specifying the value source.
|
|
12
12
|
*/
|
|
13
13
|
set(readModelPropertyAccessor: PropertyAccessor<TReadModel>): IAllSetBuilder<TReadModel, IFromEveryBuilder<TReadModel>>;
|
|
14
|
+
/**
|
|
15
|
+
* Counts every projected event into a dictionary property, using a dynamic key resolved from an event context property.
|
|
16
|
+
* The dictionary value at the resolved key is incremented by one for each matching event.
|
|
17
|
+
* @param readModelPropertyAccessor - Accessor for the read model dictionary property (Record<string, number>).
|
|
18
|
+
* @param contextPropertyName - The event context property name used as the dictionary key (e.g., 'eventType').
|
|
19
|
+
* @returns This builder for fluent chaining.
|
|
20
|
+
*/
|
|
21
|
+
count(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel>;
|
|
22
|
+
/**
|
|
23
|
+
* Increments a dictionary property by one for every projected event, using a dynamic key resolved from an event context property.
|
|
24
|
+
* @param readModelPropertyAccessor - Accessor for the read model dictionary property (Record<string, number>).
|
|
25
|
+
* @param contextPropertyName - The event context property name used as the dictionary key (e.g., 'eventType').
|
|
26
|
+
* @returns This builder for fluent chaining.
|
|
27
|
+
*/
|
|
28
|
+
increment(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel>;
|
|
29
|
+
/**
|
|
30
|
+
* Decrements a dictionary property by one for every projected event, using a dynamic key resolved from an event context property.
|
|
31
|
+
* @param readModelPropertyAccessor - Accessor for the read model dictionary property (Record<string, number>).
|
|
32
|
+
* @param contextPropertyName - The event context property name used as the dictionary key (e.g., 'eventType').
|
|
33
|
+
* @returns This builder for fluent chaining.
|
|
34
|
+
*/
|
|
35
|
+
decrement(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel>;
|
|
14
36
|
/**
|
|
15
37
|
* Excludes child projections from the fromEvery definition.
|
|
16
38
|
* @returns This builder for fluent chaining.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IFromEveryBuilder.d.ts","sourceRoot":"","sources":["../../../projections/declarative/IFromEveryBuilder.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAAC,UAAU;IACzC;;;;OAIG;IACH,GAAG,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,UAAU,CAAC,GAAG,cAAc,CAAC,UAAU,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;IAExH;;;OAGG;IACH,uBAAuB,IAAI,iBAAiB,CAAC,UAAU,CAAC,CAAC;CAC5D"}
|
|
1
|
+
{"version":3,"file":"IFromEveryBuilder.d.ts","sourceRoot":"","sources":["../../../projections/declarative/IFromEveryBuilder.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAAC,UAAU;IACzC;;;;OAIG;IACH,GAAG,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,UAAU,CAAC,GAAG,cAAc,CAAC,UAAU,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;IAExH;;;;;;OAMG;IACH,KAAK,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,UAAU,CAAC,EAAE,mBAAmB,EAAE,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAE3H;;;;;OAKG;IACH,SAAS,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,UAAU,CAAC,EAAE,mBAAmB,EAAE,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAE/H;;;;;OAKG;IACH,SAAS,CAAC,yBAAyB,EAAE,gBAAgB,CAAC,UAAU,CAAC,EAAE,mBAAmB,EAAE,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAE/H;;;OAGG;IACH,uBAAuB,IAAI,iBAAiB,CAAC,UAAU,CAAC,CAAC;CAC5D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cratis/chronicle",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "Event sourcing for TypeScript and Node.js — the idiomatic client for Cratis Chronicle, the open-source event-sourcing database",
|
|
5
5
|
"author": "Cratis",
|
|
6
6
|
"license": "MIT",
|
|
@@ -159,8 +159,8 @@
|
|
|
159
159
|
"test": "vitest run"
|
|
160
160
|
},
|
|
161
161
|
"dependencies": {
|
|
162
|
-
"@bufbuild/protobuf": "^2.
|
|
163
|
-
"@cratis/chronicle.contracts": "
|
|
162
|
+
"@bufbuild/protobuf": "^2.15.0",
|
|
163
|
+
"@cratis/chronicle.contracts": "18.2.0",
|
|
164
164
|
"@grpc/grpc-js": "^1.14.4",
|
|
165
165
|
"@opentelemetry/api": "^1.9.1",
|
|
166
166
|
"nice-grpc": "^2.1.17",
|
|
@@ -169,8 +169,8 @@
|
|
|
169
169
|
"undici": "^8.10.2"
|
|
170
170
|
},
|
|
171
171
|
"devDependencies": {
|
|
172
|
-
"@cratis/fundamentals": "7.
|
|
173
|
-
"@types/node": "^26.
|
|
172
|
+
"@cratis/fundamentals": "7.19.2",
|
|
173
|
+
"@types/node": "^26.5.1",
|
|
174
174
|
"typescript": "^6.0.3",
|
|
175
175
|
"vitest": "^5.0.0"
|
|
176
176
|
},
|
|
@@ -38,6 +38,36 @@ export class FromEveryBuilder<TReadModel> implements IFromEveryBuilder<TReadMode
|
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/** @inheritdoc */
|
|
42
|
+
count(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel> {
|
|
43
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
44
|
+
const proxy = new Proxy({}, handler);
|
|
45
|
+
readModelPropertyAccessor(proxy as TReadModel);
|
|
46
|
+
const property = handler.property;
|
|
47
|
+
this.entry.properties[`${property}.$eventContext.${contextPropertyName}`] = '$count';
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** @inheritdoc */
|
|
52
|
+
increment(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel> {
|
|
53
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
54
|
+
const proxy = new Proxy({}, handler);
|
|
55
|
+
readModelPropertyAccessor(proxy as TReadModel);
|
|
56
|
+
const property = handler.property;
|
|
57
|
+
this.entry.properties[`${property}.$eventContext.${contextPropertyName}`] = '$increment';
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** @inheritdoc */
|
|
62
|
+
decrement(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel> {
|
|
63
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
64
|
+
const proxy = new Proxy({}, handler);
|
|
65
|
+
readModelPropertyAccessor(proxy as TReadModel);
|
|
66
|
+
const property = handler.property;
|
|
67
|
+
this.entry.properties[`${property}.$eventContext.${contextPropertyName}`] = '$decrement';
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
|
|
41
71
|
/** @inheritdoc */
|
|
42
72
|
excludeChildProjections(): IFromEveryBuilder<TReadModel> {
|
|
43
73
|
this.entry.includeChildren = false;
|
|
@@ -16,6 +16,31 @@ export interface IFromEveryBuilder<TReadModel> {
|
|
|
16
16
|
*/
|
|
17
17
|
set(readModelPropertyAccessor: PropertyAccessor<TReadModel>): IAllSetBuilder<TReadModel, IFromEveryBuilder<TReadModel>>;
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Counts every projected event into a dictionary property, using a dynamic key resolved from an event context property.
|
|
21
|
+
* The dictionary value at the resolved key is incremented by one for each matching event.
|
|
22
|
+
* @param readModelPropertyAccessor - Accessor for the read model dictionary property (Record<string, number>).
|
|
23
|
+
* @param contextPropertyName - The event context property name used as the dictionary key (e.g., 'eventType').
|
|
24
|
+
* @returns This builder for fluent chaining.
|
|
25
|
+
*/
|
|
26
|
+
count(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel>;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Increments a dictionary property by one for every projected event, using a dynamic key resolved from an event context property.
|
|
30
|
+
* @param readModelPropertyAccessor - Accessor for the read model dictionary property (Record<string, number>).
|
|
31
|
+
* @param contextPropertyName - The event context property name used as the dictionary key (e.g., 'eventType').
|
|
32
|
+
* @returns This builder for fluent chaining.
|
|
33
|
+
*/
|
|
34
|
+
increment(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Decrements a dictionary property by one for every projected event, using a dynamic key resolved from an event context property.
|
|
38
|
+
* @param readModelPropertyAccessor - Accessor for the read model dictionary property (Record<string, number>).
|
|
39
|
+
* @param contextPropertyName - The event context property name used as the dictionary key (e.g., 'eventType').
|
|
40
|
+
* @returns This builder for fluent chaining.
|
|
41
|
+
*/
|
|
42
|
+
decrement(readModelPropertyAccessor: PropertyAccessor<TReadModel>, contextPropertyName: string): IFromEveryBuilder<TReadModel>;
|
|
43
|
+
|
|
19
44
|
/**
|
|
20
45
|
* Excludes child projections from the fromEvery definition.
|
|
21
46
|
* @returns This builder for fluent chaining.
|
|
@@ -27,6 +27,9 @@ class Inventory {
|
|
|
27
27
|
total!: number;
|
|
28
28
|
removedTotal!: number;
|
|
29
29
|
thingsHappenedCount!: number;
|
|
30
|
+
countsByEventType!: Record<string, number>;
|
|
31
|
+
incrementsByEventType!: Record<string, number>;
|
|
32
|
+
decrementsByEventType!: Record<string, number>;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
interface FromRecord {
|
|
@@ -39,6 +42,11 @@ interface JoinRecord {
|
|
|
39
42
|
Value: { Properties: Record<string, string> };
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
interface AllDefinition {
|
|
46
|
+
Properties: Record<string, string>;
|
|
47
|
+
IncludeChildren: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
describe('ProjectionBuilderFor', () => {
|
|
43
51
|
describe('when using add on a from builder', () => {
|
|
44
52
|
it('should produce a $add expression targeting the event property', () => {
|
|
@@ -112,4 +120,54 @@ describe('ProjectionBuilderFor', () => {
|
|
|
112
120
|
expect(entry.Value.Properties.thingsHappenedCount).toBe('$count');
|
|
113
121
|
});
|
|
114
122
|
});
|
|
123
|
+
|
|
124
|
+
describe('when using count with event context property on fromEvery', () => {
|
|
125
|
+
it('should produce a $count expression with dictionary key from event context', () => {
|
|
126
|
+
const builder = new ProjectionBuilderFor<Inventory>();
|
|
127
|
+
builder.fromEvery(fromEvery => fromEvery.count(model => model.countsByEventType, 'eventType'));
|
|
128
|
+
|
|
129
|
+
const definition = builder.build('inventory', 'Inventory') as unknown as { All: AllDefinition };
|
|
130
|
+
|
|
131
|
+
expect(definition.All.Properties['countsByEventType.$eventContext.eventType']).toBe('$count');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe('when using increment with event context property on fromEvery', () => {
|
|
136
|
+
it('should produce a $increment expression with dictionary key from event context', () => {
|
|
137
|
+
const builder = new ProjectionBuilderFor<Inventory>();
|
|
138
|
+
builder.fromEvery(fromEvery => fromEvery.increment(model => model.incrementsByEventType, 'eventType'));
|
|
139
|
+
|
|
140
|
+
const definition = builder.build('inventory', 'Inventory') as unknown as { All: AllDefinition };
|
|
141
|
+
|
|
142
|
+
expect(definition.All.Properties['incrementsByEventType.$eventContext.eventType']).toBe('$increment');
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('when using decrement with event context property on fromEvery', () => {
|
|
147
|
+
it('should produce a $decrement expression with dictionary key from event context', () => {
|
|
148
|
+
const builder = new ProjectionBuilderFor<Inventory>();
|
|
149
|
+
builder.fromEvery(fromEvery => fromEvery.decrement(model => model.decrementsByEventType, 'eventType'));
|
|
150
|
+
|
|
151
|
+
const definition = builder.build('inventory', 'Inventory') as unknown as { All: AllDefinition };
|
|
152
|
+
|
|
153
|
+
expect(definition.All.Properties['decrementsByEventType.$eventContext.eventType']).toBe('$decrement');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('when using multiple fromEvery operations', () => {
|
|
158
|
+
it('should produce all operations in the All.Properties definition', () => {
|
|
159
|
+
const builder = new ProjectionBuilderFor<Inventory>();
|
|
160
|
+
builder.fromEvery(fromEvery => {
|
|
161
|
+
fromEvery.count(model => model.countsByEventType, 'eventType');
|
|
162
|
+
fromEvery.increment(model => model.incrementsByEventType, 'correlationId');
|
|
163
|
+
fromEvery.set(model => model.id).toEventSourceId();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const definition = builder.build('inventory', 'Inventory') as unknown as { All: AllDefinition };
|
|
167
|
+
|
|
168
|
+
expect(definition.All.Properties['countsByEventType.$eventContext.eventType']).toBe('$count');
|
|
169
|
+
expect(definition.All.Properties['incrementsByEventType.$eventContext.correlationId']).toBe('$increment');
|
|
170
|
+
expect(definition.All.Properties.id).toBe('$eventSourceId');
|
|
171
|
+
});
|
|
172
|
+
});
|
|
115
173
|
});
|