@cratis/chronicle 6.26.0 → 6.28.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/connection/ChronicleConnection.auth.spec.ts +15 -11
- package/dist/projections/modelBound/childrenFrom.d.ts +19 -0
- package/dist/projections/modelBound/childrenFrom.d.ts.map +1 -1
- package/dist/projections/modelBound/childrenFrom.js +14 -13
- package/dist/projections/modelBound/childrenFrom.js.map +1 -1
- package/dist/projections/modelBound/index.d.ts +1 -1
- package/dist/projections/modelBound/index.d.ts.map +1 -1
- package/dist/testing/EventScenario.d.ts.map +1 -1
- package/dist/testing/EventScenario.js +10 -1
- package/dist/testing/EventScenario.js.map +1 -1
- package/dist/testing/InProcessConstraints.d.ts.map +1 -1
- package/dist/testing/InProcessConstraints.js +43 -19
- package/dist/testing/InProcessConstraints.js.map +1 -1
- package/package.json +1 -1
- package/projections/Projections.childrenFromOptions.spec.ts +118 -0
- package/projections/modelBound/childrenFrom.ts +41 -5
- package/projections/modelBound/index.ts +1 -1
- package/testing/EventScenario.constraint-composite.spec.ts +343 -0
- package/testing/EventScenario.constraints.spec.ts +1 -1
- package/testing/EventScenario.fixtures.spec.ts +2 -1
- package/testing/EventScenario.ts +12 -1
- package/testing/InProcessConstraints.ts +48 -19
- package/testing/ReadModelScenario.childrenFrom.spec.ts +35 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright (c) Cratis. All rights reserved.
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { afterEach, describe, expect, it, onTestFinished, vi } from 'vitest';
|
|
5
5
|
import { createServer, ServerError, type ServiceImplementation } from 'nice-grpc';
|
|
6
6
|
import { ConnectionServiceDefinition, EventStoresDefinition, ServerDefinition } from '@cratis/chronicle.contracts';
|
|
7
7
|
import { status } from '@grpc/grpc-js';
|
|
@@ -233,20 +233,24 @@ describe('ChronicleConnection authentication', () => {
|
|
|
233
233
|
|
|
234
234
|
it('keeps retrying proxy 403 responses without an OAuth error code', async () => {
|
|
235
235
|
const random = vi.spyOn(Math, 'random').mockReturnValue(0);
|
|
236
|
-
|
|
236
|
+
// Restore even when the test times out, so a hang cannot leak the stub into later tests.
|
|
237
|
+
onTestFinished(() => random.mockRestore());
|
|
238
|
+
let fourthCheck!: () => void;
|
|
239
|
+
const reachedFourthCheck = new Promise<void>(resolve => fourthCheck = resolve);
|
|
240
|
+
const checks = vi.fn(() => { if (checks.mock.calls.length === 4) fourthCheck(); });
|
|
237
241
|
const port = await listenAuthenticated(checks);
|
|
238
242
|
fetchToken.mockRejectedValue(new OAuthTokenHttpError(403, '<html>blocked</html>'));
|
|
239
243
|
const client = new ChronicleClient(ChronicleOptions.fromConnectionString(`chronicle://user:secret@127.0.0.1:${port}?disableTls=true`, { discoveryPatterns: [] }));
|
|
240
244
|
clients.push(client);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
245
|
+
let settled = false;
|
|
246
|
+
const pending = client.getEventStores().then(() => undefined, error => error as Error).finally(() => settled = true);
|
|
247
|
+
// Wait for the fourth attempt itself rather than a wall-clock window; a credential
|
|
248
|
+
// rejection would stop after three attempts and settle the call instead.
|
|
249
|
+
await Promise.race([reachedFourthCheck, pending]);
|
|
250
|
+
expect(settled).toBe(false);
|
|
251
|
+
expect(checks.mock.calls.length).toBeGreaterThanOrEqual(4);
|
|
252
|
+
client.dispose();
|
|
253
|
+
expect((await pending).message).toMatch(/disposed/);
|
|
250
254
|
}, 15000);
|
|
251
255
|
|
|
252
256
|
it('rejects an API key after three unauthenticated kernel responses', async () => {
|
|
@@ -13,6 +13,25 @@ export interface ChildrenFromMetadata {
|
|
|
13
13
|
/** The event property name used as the parent key. Defaults to the event source identifier. */
|
|
14
14
|
readonly parentKey?: string;
|
|
15
15
|
}
|
|
16
|
+
/** Options for the options form of the childrenFrom property decorator. */
|
|
17
|
+
export interface ChildrenFromOptions {
|
|
18
|
+
/** The child type, for TypeScript runtimes without emitted generic metadata. */
|
|
19
|
+
readonly childType?: Function;
|
|
20
|
+
/** The event property name used as the key for children. Defaults to the event source identifier. */
|
|
21
|
+
readonly key?: string;
|
|
22
|
+
/** The child model property name used to uniquely identify instances in the collection. */
|
|
23
|
+
readonly identifiedBy?: string;
|
|
24
|
+
/** The event property name used as the parent key. Defaults to the event source identifier. */
|
|
25
|
+
readonly parentKey?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Property decorator that configures a children collection sub-projection from an event type.
|
|
29
|
+
* Use this form to name the child type and an explicit child key together.
|
|
30
|
+
* @param eventType - The event constructor.
|
|
31
|
+
* @param options - The child type, key, identifiedBy and parentKey.
|
|
32
|
+
* @returns A property decorator.
|
|
33
|
+
*/
|
|
34
|
+
export declare function childrenFrom(eventType: Function, options: ChildrenFromOptions): ChroniclePropertyDecorator;
|
|
16
35
|
/**
|
|
17
36
|
* Property decorator that configures a children collection sub-projection from an event type.
|
|
18
37
|
* @param eventType - The event constructor.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"childrenFrom.d.ts","sourceRoot":"","sources":["../../../projections/modelBound/childrenFrom.ts"],"names":[],"mappings":"AAGA,OAAO,kBAAkB,CAAC;AAG1B,OAAO,EAAE,0BAA0B,EAAuB,MAAM,0CAA0C,CAAC;AAE3G,8DAA8D;AAC9D,MAAM,WAAW,oBAAoB;IACjC,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC;IAC9B,qGAAqG;IACrG,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,2FAA2F;IAC3F,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,+FAA+F;IAC/F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC/B;AAID;;;;;;;GAOG;AACH,wBAAgB,YAAY,
|
|
1
|
+
{"version":3,"file":"childrenFrom.d.ts","sourceRoot":"","sources":["../../../projections/modelBound/childrenFrom.ts"],"names":[],"mappings":"AAGA,OAAO,kBAAkB,CAAC;AAG1B,OAAO,EAAE,0BAA0B,EAAuB,MAAM,0CAA0C,CAAC;AAE3G,8DAA8D;AAC9D,MAAM,WAAW,oBAAoB;IACjC,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC;IAC9B,qGAAqG;IACrG,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,2FAA2F;IAC3F,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,+FAA+F;IAC/F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,2EAA2E;AAC3E,MAAM,WAAW,mBAAmB;IAChC,gFAAgF;IAChF,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC;IAC9B,qGAAqG;IACrG,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,2FAA2F;IAC3F,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,+FAA+F;IAC/F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC/B;AAID;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,mBAAmB,GAAG,0BAA0B,CAAC;AAC5G;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,QAAQ,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,0BAA0B,CAAC;AAkClJ;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAEnG"}
|
|
@@ -5,26 +5,27 @@ import { TypeIntrospector } from '../../types/index.js';
|
|
|
5
5
|
import { decorateModelBoundProperty } from '../../types/modelBoundProperty.js';
|
|
6
6
|
import { getPropertyMetadata } from '../../types/propertyDecoratorMetadata.js';
|
|
7
7
|
const METADATA_KEY = 'chronicle:projection:childrenFrom';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* @param eventType - The event constructor.
|
|
11
|
-
* @param key - Optional event property name to use as the key for children, or the child constructor.
|
|
12
|
-
* @param identifiedBy - Optional child model property name used to identify instances.
|
|
13
|
-
* @param parentKey - Optional event property name used as the parent key.
|
|
14
|
-
* @returns A property decorator.
|
|
15
|
-
*/
|
|
16
|
-
export function childrenFrom(eventType, key, identifiedBy, parentKey) {
|
|
8
|
+
export function childrenFrom(eventType, keyOrOptions, identifiedBy, parentKey) {
|
|
9
|
+
const metadata = toMetadata(eventType, keyOrOptions, identifiedBy, parentKey);
|
|
17
10
|
return decorateModelBoundProperty((target, propertyKey) => {
|
|
18
11
|
const propKey = propertyKey.toString();
|
|
19
12
|
TypeIntrospector.trackProperty(target.constructor, propKey);
|
|
20
13
|
const existing = Reflect.getMetadata(METADATA_KEY, target, propKey) ?? [];
|
|
21
|
-
const metadata = {
|
|
22
|
-
eventType, key: typeof key === 'string' ? key : undefined,
|
|
23
|
-
childType: typeof key === 'function' ? key : undefined, identifiedBy, parentKey
|
|
24
|
-
};
|
|
25
14
|
Reflect.defineMetadata(METADATA_KEY, [...existing, metadata], target, propKey);
|
|
26
15
|
});
|
|
27
16
|
}
|
|
17
|
+
function toMetadata(eventType, keyOrOptions, identifiedBy, parentKey) {
|
|
18
|
+
if (typeof keyOrOptions === 'object' && keyOrOptions !== null) {
|
|
19
|
+
return {
|
|
20
|
+
eventType, childType: keyOrOptions.childType, key: keyOrOptions.key,
|
|
21
|
+
identifiedBy: keyOrOptions.identifiedBy, parentKey: keyOrOptions.parentKey
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
eventType, key: typeof keyOrOptions === 'string' ? keyOrOptions : undefined,
|
|
26
|
+
childType: typeof keyOrOptions === 'function' ? keyOrOptions : undefined, identifiedBy, parentKey
|
|
27
|
+
};
|
|
28
|
+
}
|
|
28
29
|
/**
|
|
29
30
|
* Retrieves all childrenFrom metadata stored on the given property.
|
|
30
31
|
* @param target - The class prototype.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"childrenFrom.js","sourceRoot":"","sources":["../../../projections/modelBound/childrenFrom.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,qGAAqG;AAErG,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAA8B,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"childrenFrom.js","sourceRoot":"","sources":["../../../projections/modelBound/childrenFrom.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,qGAAqG;AAErG,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAA8B,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AA4B3G,MAAM,YAAY,GAAG,mCAAmC,CAAC;AAmBzD,MAAM,UAAU,YAAY,CACxB,SAAmB,EACnB,YAAsD,EACtD,YAAqB,EACrB,SAAkB;IAElB,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;IAC9E,OAAO,0BAA0B,CAAC,CAAC,MAAc,EAAE,WAA4B,EAAE,EAAE;QAC/E,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAC;QACvC,gBAAgB,CAAC,aAAa,CAAE,MAAoC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAA2B,OAAO,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;QAClG,OAAO,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,GAAG,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,UAAU,CACf,SAAmB,EACnB,YAAiE,EACjE,YAAgC,EAChC,SAA6B;IAE7B,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC5D,OAAO;YACH,SAAS,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS,EAAE,GAAG,EAAE,YAAY,CAAC,GAAG;YACnE,YAAY,EAAE,YAAY,CAAC,YAAY,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS;SAC7E,CAAC;IACN,CAAC;IACD,OAAO;QACH,SAAS,EAAE,GAAG,EAAE,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS;QAC3E,SAAS,EAAE,OAAO,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,EAAE,YAAY,EAAE,SAAS;KACpG,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAc,EAAE,WAAmB;IACvE,OAAO,mBAAmB,CAAyB,YAAY,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;AAChG,CAAC"}
|
|
@@ -18,7 +18,7 @@ export type { DecrementMetadata } from './decrement.js';
|
|
|
18
18
|
export { count, getCountMetadata } from './count.js';
|
|
19
19
|
export type { CountMetadata } from './count.js';
|
|
20
20
|
export { childrenFrom, getChildrenFromMetadata } from './childrenFrom.js';
|
|
21
|
-
export type { ChildrenFromMetadata } from './childrenFrom.js';
|
|
21
|
+
export type { ChildrenFromMetadata, ChildrenFromOptions } from './childrenFrom.js';
|
|
22
22
|
export { nested, isNested } from './nested.js';
|
|
23
23
|
export { clearWith, getClearWithClassMetadata, getClearWithPropertyMetadata } from './clearWith.js';
|
|
24
24
|
export type { ClearWithMetadata } from './clearWith.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../projections/modelBound/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACvF,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChF,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAClD,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACjE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACjE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACrD,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../projections/modelBound/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EventScenario.d.ts","sourceRoot":"","sources":["../../testing/EventScenario.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACxF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAQhE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAUzE,sFAAsF;AACtF,qBAAa,aAAa;IACtB,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,yBAAyB,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IAExC,YAAY,OAAO,GAAE,oBAAyB,
|
|
1
|
+
{"version":3,"file":"EventScenario.d.ts","sourceRoot":"","sources":["../../testing/EventScenario.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACxF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAQhE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAUzE,sFAAsF;AACtF,qBAAa,aAAa;IACtB,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,yBAAyB,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IAExC,YAAY,OAAO,GAAE,oBAAyB,EA8F7C;IAED,qDAAqD;IACrD,IAAI,QAAQ,IAAI,SAAS,CAKxB;IACK,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAE1F;IACD,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAC/F,UAAU,CAAC,MAAM,EAAE,qBAAqB,EAAE,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAO9F,IAAI,OAAO,IAAI,SAAS,YAAY,EAAE,CAAmE;IACzG,IAAI,cAAc,IAAI,SAAS,aAAa,EAAE,CAA0E;IAExH,+DAA+D;IAC/D,IAAI,IAAI,IAAI;QAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;QAAC,QAAQ,CAAC,cAAc,EAAE,SAAS,aAAa,EAAE,CAAA;KAAE,CAE3G;CACJ"}
|
|
@@ -83,9 +83,18 @@ export class EventScenario {
|
|
|
83
83
|
}
|
|
84
84
|
for (const entry of capture.uniqueConstraint?.eventDefinitions ?? []) {
|
|
85
85
|
const type = eventTypes.find(type => getEventTypeFor(type).id.value === entry.eventTypeId);
|
|
86
|
-
|
|
86
|
+
const schemaTypes = entry.properties.map(property => getEventTypeMetadata(type)?.schema.properties?.[property]?.type ?? '');
|
|
87
|
+
if (entry.properties.length === 1 && !['string', 'boolean'].includes(schemaTypes[0])) {
|
|
87
88
|
throw new UnsupportedEventSequenceOperation('artifacts.constraints', name, 'The constrained property must be a schema-backed string or boolean.');
|
|
88
89
|
}
|
|
90
|
+
// constraints-ignore-casing.json captures folded string keys only.
|
|
91
|
+
if (capture.uniqueConstraint.ignoreCasing && schemaTypes.some(schemaType => schemaType !== 'string')) {
|
|
92
|
+
throw new UnsupportedEventSequenceOperation('artifacts.constraints', name, 'Case-insensitive keys must be schema-backed strings.');
|
|
93
|
+
}
|
|
94
|
+
// constraints-composite.json captures string components only.
|
|
95
|
+
if (entry.properties.length > 1 && schemaTypes.some(schemaType => schemaType !== 'string')) {
|
|
96
|
+
throw new UnsupportedEventSequenceOperation('artifacts.constraints', name, 'Every property of a composite key must be a schema-backed string.');
|
|
97
|
+
}
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EventScenario.js","sourceRoot":"","sources":["../../testing/EventScenario.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"EventScenario.js","sourceRoot":"","sources":["../../testing/EventScenario.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InProcessConstraints.d.ts","sourceRoot":"","sources":["../../testing/InProcessConstraints.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,IAAI,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AACvG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAEpF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAGpF,MAAM,MAAM,uBAAuB,GAAG,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"InProcessConstraints.d.ts","sourceRoot":"","sources":["../../testing/InProcessConstraints.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,IAAI,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AACvG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAEpF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAGpF,MAAM,MAAM,uBAAuB,GAAG,4BAA4B,CAAC;AAwCnE,6FAA6F;AAC7F,qBAAa,oBAAoB;IAKjB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAJzC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAkC;IACzE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAqB;IAE3D,YAA6B,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAyEhF;IAED,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE9C;IAED,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAgD;IAE5F,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEpE;IAED,yGAAyG;IACzG,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,EAAE,QAAQ,EAAE,SAAS,aAAa,EAAE,GAAG,uBAAuB,EAAE,CA+FzG;IAED,cAAc,CAAC,SAAS,EAAE,mBAAmB,GAAG,mBAAmB,CAElE;IAED,OAAO,CAAC,WAAW;CAGtB"}
|
|
@@ -16,6 +16,26 @@ function kernelKeyString(value, name) {
|
|
|
16
16
|
function keyHash(value) {
|
|
17
17
|
return createHash('sha256').update(value).digest('hex');
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* The kernel key: each declared property's string in declared order, joined with a literal '-'
|
|
21
|
+
* (UniqueConstraintDefinitionExtensions.GetPropertiesAndValues/GetValue at Chronicle 8fe5d30). Not a tuple:
|
|
22
|
+
* ['a-b', 'c'] and ['a', 'b-c'] claim the same key, as constraints-composite.json captures.
|
|
23
|
+
*/
|
|
24
|
+
function claimOf(name, unique, eventTypeId, content) {
|
|
25
|
+
const properties = unique.eventDefinitions.find(entry => entry.eventTypeId === eventTypeId)?.properties;
|
|
26
|
+
if (properties === undefined)
|
|
27
|
+
return undefined;
|
|
28
|
+
const parts = properties.map(property => ({ property, raw: kernelKeyString(content[property], name) }));
|
|
29
|
+
const joined = parts.map(part => part.raw).join('-');
|
|
30
|
+
if (!unique.ignoreCasing)
|
|
31
|
+
return { key: keyHash(joined), parts };
|
|
32
|
+
// The kernel applies .NET ToLowerInvariant to the joined value. constraints-ignore-casing.json proves
|
|
33
|
+
// only the ASCII key domain, where that is exactly A-Z to a-z; host Unicode case tables are not used.
|
|
34
|
+
if (!/^[\x20-\x7e]*$/.test(joined)) {
|
|
35
|
+
throw new UnsupportedEventSequenceOperation('artifacts.constraints', name, 'Case-insensitive keys outside the ASCII key domain are not fixture-backed.');
|
|
36
|
+
}
|
|
37
|
+
return { key: keyHash(joined.replace(/[A-Z]/g, letter => String.fromCharCode(letter.charCodeAt(0) + 32))), parts };
|
|
38
|
+
}
|
|
19
39
|
/** Narrow, fixture-backed unscoped constraint validation over serialized event snapshots. */
|
|
20
40
|
export class InProcessConstraints {
|
|
21
41
|
_definitions;
|
|
@@ -35,10 +55,12 @@ export class InProcessConstraints {
|
|
|
35
55
|
}
|
|
36
56
|
if (capture.uniqueConstraint) {
|
|
37
57
|
const unique = capture.uniqueConstraint;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
58
|
+
// constraints-composite.json installs one, two and three flat properties per event type.
|
|
59
|
+
// The kernel keys properties by path with ToDictionary, so duplicate paths are not a key shape.
|
|
60
|
+
if (unique.eventDefinitions.length === 0 || unique.eventDefinitions.some(entry => entry.properties.length < 1 || entry.properties.length > 3 ||
|
|
61
|
+
new Set(entry.properties).size !== entry.properties.length ||
|
|
62
|
+
entry.properties.some(property => !/^[a-z][a-zA-Z0-9]*$/.test(property)))) {
|
|
63
|
+
throw this.unsupported(name, 'Only one to three distinct flat properties per event type are fixture-backed; nested, indexed or repeated key paths are not.');
|
|
42
64
|
}
|
|
43
65
|
for (const id of [unique.removedWithEventTypeId, ...(unique.removedWithEventTypeIds ?? [])]) {
|
|
44
66
|
if (id === undefined)
|
|
@@ -53,7 +75,7 @@ export class InProcessConstraints {
|
|
|
53
75
|
}
|
|
54
76
|
for (const entry of unique.eventDefinitions) {
|
|
55
77
|
const properties = this._constrainedProperties.get(entry.eventTypeId) ?? new Set();
|
|
56
|
-
properties.add(
|
|
78
|
+
entry.properties.forEach(property => properties.add(property));
|
|
57
79
|
this._constrainedProperties.set(entry.eventTypeId, properties);
|
|
58
80
|
}
|
|
59
81
|
}
|
|
@@ -125,13 +147,13 @@ export class InProcessConstraints {
|
|
|
125
147
|
claims.delete(source);
|
|
126
148
|
continue;
|
|
127
149
|
}
|
|
128
|
-
const
|
|
129
|
-
if (
|
|
150
|
+
const properties = unique.eventDefinitions.find(entry => entry.eventTypeId === type)?.properties;
|
|
151
|
+
if (properties === undefined)
|
|
130
152
|
continue;
|
|
131
|
-
|
|
132
|
-
if (typeof value !== 'string' && typeof value !== 'boolean')
|
|
153
|
+
if (properties.some(property => !['string', 'boolean'].includes(typeof prior.content[property]))) {
|
|
133
154
|
throw this.unsupported(name, 'History has an unproven key.');
|
|
134
|
-
|
|
155
|
+
}
|
|
156
|
+
claims.set(source, { key: claimOf(name, unique, type, prior.content).key,
|
|
135
157
|
sequence: prior.context.sequenceNumber.toString() });
|
|
136
158
|
}
|
|
137
159
|
owners.set(name, claims);
|
|
@@ -143,19 +165,21 @@ export class InProcessConstraints {
|
|
|
143
165
|
const source = event.context.eventSourceId;
|
|
144
166
|
const violationCount = violations.length;
|
|
145
167
|
for (const [name, definition] of this._definitions) {
|
|
146
|
-
const
|
|
147
|
-
if (
|
|
148
|
-
const
|
|
149
|
-
const key = keyHash(raw);
|
|
168
|
+
const claim = definition.uniqueConstraint && claimOf(name, definition.uniqueConstraint, type, event.content);
|
|
169
|
+
if (claim) {
|
|
170
|
+
const key = claim.key;
|
|
150
171
|
const existing = [...owners.get(name).entries()].find(([, claim]) => claim.key === key);
|
|
151
172
|
const batchClaims = stagedKeys.get(name) ?? new Map();
|
|
152
173
|
const batchOwner = batchClaims.get(key);
|
|
153
174
|
if (existing && existing[0] !== source || batchOwner !== undefined && batchOwner !== source) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
175
|
+
// One violation per declared property, in declared order, each with its own original value.
|
|
176
|
+
const sequence = existing?.[1].sequence ?? unavailable;
|
|
177
|
+
for (const { property, raw } of claim.parts) {
|
|
178
|
+
violations.push({ EventTypeId: type, SequenceNumber: BigInt(sequence), ConstraintType: 1,
|
|
179
|
+
ConstraintName: name,
|
|
180
|
+
Message: `Event '${type}' on member '${property}' violated a unique constraint on sequence number ${sequence}`,
|
|
181
|
+
Details: { PropertyName: property, PropertyValue: raw } });
|
|
182
|
+
}
|
|
159
183
|
}
|
|
160
184
|
else {
|
|
161
185
|
batchClaims.set(key, source);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InProcessConstraints.js","sourceRoot":"","sources":["../../testing/InProcessConstraints.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InProcessConstraints.js","sourceRoot":"","sources":["../../testing/InProcessConstraints.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,qGAAqG;AAErG,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAEhF,OAAO,EAAE,iCAAiC,EAAE,MAAM,wCAAwC,CAAC;AAI3F,MAAM,WAAW,GAAG,sBAAsB,CAAC;AAC3C,oGAAoG;AACpG,MAAM,YAAY,GAAG,iCAAiC,CAAC;AAEvD,SAAS,eAAe,CAAC,KAAc,EAAE,IAAY;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACxE,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAChE,MAAM,IAAI,iCAAiC,CAAC,uBAAuB,EAAE,IAAI,EACrE,mEAAmE,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,OAAO,CAAC,KAAa;IAC1B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC;AAKD;;;;GAIG;AACH,SAAS,OAAO,CAAC,IAAY,EAAE,MAAqB,EAAE,WAAmB,EAAE,OAAgC;IACvG,MAAM,UAAU,GAAG,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,KAAK,WAAW,CAAC,EAAE,UAAU,CAAC;IACxG,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC/C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACxG,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrD,IAAI,CAAC,MAAM,CAAC,YAAY;QAAE,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;IACjE,sGAAsG;IACtG,sGAAsG;IACtG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,iCAAiC,CAAC,uBAAuB,EAAE,IAAI,EACrE,4EAA4E,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;AACvH,CAAC;AAED,6FAA6F;AAC7F,MAAM,OAAO,oBAAoB;IAKA,YAAY;IAJxB,sBAAsB,GAAG,IAAI,GAAG,EAAuB,CAAC;IACxD,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,qBAAqB,GAAG,IAAI,GAAG,EAAU,CAAC;IAE3D,YAA6B,YAAoD;4BAApD,YAAY;QACrC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC/C,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;QAChD,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,YAAY,EAAE,CAAC;YACzC,IAAI,OAAO,CAAC,gBAAgB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;gBACtD,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,gEAAgE,CAAC,CAAC;YACnG,CAAC;YACD,IAAI,OAAO,CAAC,KAAK,CAAC,kBAAkB,IAAI,OAAO,CAAC,KAAK,CAAC,kBAAkB,IAAI,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC;gBACzG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,4CAA4C,CAAC,CAAC;YAC/E,CAAC;YACD,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;gBAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;gBACxC,yFAAyF;gBACzF,gGAAgG;gBAChG,IAAI,MAAM,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAC7E,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;oBAC1D,IAAI,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,UAAU,CAAC,MAAM;oBAC1D,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC5E,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,8HAA8H,CAAC,CAAC;gBACjK,CAAC;gBACD,KAAK,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;oBAC1F,IAAI,EAAE,KAAK,SAAS;wBAAE,SAAS;oBAC/B,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACpC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;wBACxC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,mEAAmE,CAAC,CAAC;oBACtG,CAAC;oBACD,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;oBAC5B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAC3B,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACvC,CAAC;gBACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;oBAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;oBAC3F,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAC/D,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;gBACnE,CAAC;YACL,CAAC;iBAAM,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;gBACjC,MAAM,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;gBACvC,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;gBACxD,MAAM,QAAQ,GAAG,MAAM,CAAC,uBAAuB,IAAI,EAAE,CAAC;gBACtD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;gBAC9D,wFAAwF;gBACxF,mEAAmE;gBACnE,yFAAyF;gBACzF,kEAAkE;gBAClE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;oBAC5C,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,CAAC;oBAC5D,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;oBAC/D,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,2EAA2E,CAAC,CAAC;gBAC9G,CAAC;gBACD,oGAAoG;gBACpG,IAAI,QAAQ,CAAC,MAAM,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;oBAC7C,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,yEAAyE,CAAC,CAAC;gBAC5G,CAAC;gBACD,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YACvD,CAAC;iBAAM,CAAC;gBACJ,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,gCAAgC,CAAC,CAAC;YACnE,CAAC;YACD,MAAM,GAAG,GAAG,OAAO,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC;gBAClF,OAAO,CAAC,eAAe,EAAE,YAAY,IAAI,CAAC,OAAO,CAAC,eAAgB,CAAC,WAAW,CAAC,CAAC;YACpF,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;gBACnB,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;oBAAE,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,iDAAiD,CAAC,CAAC;gBAC1G,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YAC/B,CAAC;QACL,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,YAAY,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,UAAU,CAAC,gBAAgB,CAAC;YAC3C,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,KAAK,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC1F,IAAI,EAAE,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;oBAC5E,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,0EAA0E,CAAC,CAAC;gBAC7G,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAED,iBAAiB,CAAC,WAAmB;QACjC,OAAO,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACxG,CAAC;IAED,cAAc,CAAC,WAAmB,IAAa,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAE5F,qBAAqB,CAAC,WAAmB,EAAE,QAAgB;QACvD,OAAO,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC;IAChF,CAAC;IAED,yGAAyG;IACzG,QAAQ,CAAC,OAAiC,EAAE,QAAkC;QAC1E,MAAM,UAAU,GAA8B,EAAE,CAAC;QACjD,iFAAiF;QACjF,mGAAmG;QACnG,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0D,CAAC;QACjF,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACjD,IAAI,CAAC,UAAU,CAAC,gBAAgB;gBAAE,SAAS;YAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6C,CAAC;YACpE,MAAM,MAAM,GAAG,UAAU,CAAC,gBAAgB,CAAC;YAC3C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACrG,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC;gBACtC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;gBAC3C,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBACtB,SAAS;gBACb,CAAC;gBACD,MAAM,UAAU,GAAG,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC,EAAE,UAAU,CAAC;gBACjG,IAAI,UAAU,KAAK,SAAS;oBAAE,SAAS;gBACvC,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC/F,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,8BAA8B,CAAC,CAAC;gBACjE,CAAC;gBACD,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAE,CAAC,GAAG;oBACrE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC7D,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC7B,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,GAAG,EAA+B,CAAC;QAC1D,MAAM,YAAY,GAAG,IAAI,GAAG,EAA4C,CAAC;QACzE,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC;YACtC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;YAC3C,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC;YACzC,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACjD,MAAM,KAAK,GAAG,UAAU,CAAC,gBAAgB,IAAI,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,gBAAgB,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC7G,IAAI,KAAK,EAAE,CAAC;oBACR,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;oBACtB,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;oBACzF,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;oBACtE,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBACxC,IAAI,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;wBAC1F,4FAA4F;wBAC5F,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,WAAW,CAAC;wBACvD,KAAK,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;4BAC1C,UAAU,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;gCACpF,cAAc,EAAE,IAAI;gCACpB,OAAO,EAAE,UAAU,IAAI,gBAAgB,QAAQ,qDAAqD,QAAQ,EAAE;gCAC9G,OAAO,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;wBACnE,CAAC;oBACL,CAAC;yBAAM,CAAC;wBACJ,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;wBAC7B,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;oBACtC,CAAC;gBACL,CAAC;gBACD,MAAM,UAAU,GAAG,UAAU,CAAC,eAAe,CAAC;gBAC9C,IAAI,UAAU,IAAI,CAAC,UAAU,CAAC,YAAY,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrF,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;oBACpE,MAAM,QAAQ,GAAG,UAAU,CAAC,uBAAuB,IAAI,EAAE,CAAC;oBAC1D,uFAAuF;oBACvF,IAAI,KAAgC,CAAC;oBACrC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;wBAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,KAAK,MAAM;4BAAE,SAAS;wBACrD,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC;wBAC3C,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;4BAAE,KAAK,GAAG,SAAS,CAAC;6BAC/C,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;4BAAE,KAAK,GAAG,KAAK,CAAC;oBAClE,CAAC;oBACD,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAA+B,CAAC;oBAChF,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBACjC,2EAA2E;oBAC3E,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,EAAE,CAAC;wBACnD,mFAAmF;wBACnF,MAAM,QAAQ,GAAG,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,WAAW,CAAC;wBACzE,UAAU,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;4BACpF,cAAc,EAAE,IAAI;4BACpB,OAAO,EAAE,UAAU,IAAI,gEAAgE,QAAQ,EAAE;4BACjG,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;oBACvB,CAAC;yBAAM,CAAC;wBACJ,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;wBAC3B,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;oBACnC,CAAC;gBACL,CAAC;YACL,CAAC;YACD,gFAAgF;YAChF,0EAA0E;YAC1E,IAAI,UAAU,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;gBACvC,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;oBACjD,IAAI,UAAU,CAAC,eAAe,EAAE,uBAAuB,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;wBACtE,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAA+B,CAAC;wBAChF,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;wBAC/B,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;oBACnC,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;IAED,cAAc,CAAC,SAA8B;QACzC,OAAO,wBAAwB,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAClE,CAAC;IAEO,WAAW,CAAC,IAAY,EAAE,MAAc;QAC5C,OAAO,IAAI,iCAAiC,CAAC,uBAAuB,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACxF,CAAC;CACJ"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import 'reflect-metadata';
|
|
5
|
+
import { field } from '@cratis/fundamentals';
|
|
6
|
+
import { chai, describe, it, vi } from 'vitest';
|
|
7
|
+
import { IClientArtifactsProvider } from '../artifacts/index.js';
|
|
8
|
+
import { ChronicleConnection } from '../connection/index.js';
|
|
9
|
+
import { eventType } from '../events/eventTypeDecorator.js';
|
|
10
|
+
import { childrenFrom } from './modelBound/childrenFrom.js';
|
|
11
|
+
import { fromEvent } from './modelBound/fromEvent.js';
|
|
12
|
+
import { Projections } from './Projections.js';
|
|
13
|
+
|
|
14
|
+
chai.should();
|
|
15
|
+
|
|
16
|
+
class KeyedItemAdded {
|
|
17
|
+
itemId = '';
|
|
18
|
+
orderId = '';
|
|
19
|
+
name = '';
|
|
20
|
+
}
|
|
21
|
+
eventType()(KeyedItemAdded);
|
|
22
|
+
|
|
23
|
+
class KeyedOrderCreated {}
|
|
24
|
+
eventType()(KeyedOrderCreated);
|
|
25
|
+
|
|
26
|
+
// No @field metadata on any collection: the child type comes only from the options.
|
|
27
|
+
class KeyedItem {
|
|
28
|
+
id = '';
|
|
29
|
+
sku = '';
|
|
30
|
+
name = '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class KeyedOrder {
|
|
34
|
+
byKey: KeyedItem[] = [];
|
|
35
|
+
byIdentifiedBy: KeyedItem[] = [];
|
|
36
|
+
byParentKey: KeyedItem[] = [];
|
|
37
|
+
byKeyAndIdentifiedBy: KeyedItem[] = [];
|
|
38
|
+
byKeyAndParentKey: KeyedItem[] = [];
|
|
39
|
+
byAll: KeyedItem[] = [];
|
|
40
|
+
byFieldMetadata: KeyedItem[] = [];
|
|
41
|
+
}
|
|
42
|
+
childrenFrom(KeyedItemAdded, { childType: KeyedItem, key: 'itemId' })(KeyedOrder.prototype, 'byKey');
|
|
43
|
+
childrenFrom(KeyedItemAdded, { childType: KeyedItem, identifiedBy: 'sku' })(KeyedOrder.prototype, 'byIdentifiedBy');
|
|
44
|
+
childrenFrom(KeyedItemAdded, { childType: KeyedItem, parentKey: 'orderId' })(KeyedOrder.prototype, 'byParentKey');
|
|
45
|
+
childrenFrom(KeyedItemAdded, { childType: KeyedItem, key: 'itemId', identifiedBy: 'sku' })(KeyedOrder.prototype, 'byKeyAndIdentifiedBy');
|
|
46
|
+
childrenFrom(KeyedItemAdded, { childType: KeyedItem, key: 'itemId', parentKey: 'orderId' })(KeyedOrder.prototype, 'byKeyAndParentKey');
|
|
47
|
+
childrenFrom(KeyedItemAdded, { childType: KeyedItem, key: 'itemId', identifiedBy: 'sku', parentKey: 'orderId' })(KeyedOrder.prototype, 'byAll');
|
|
48
|
+
childrenFrom(KeyedItemAdded, { key: 'itemId' })(KeyedOrder.prototype, 'byFieldMetadata');
|
|
49
|
+
field(Array, { enumerable: true, genericArguments: [KeyedItem] })(KeyedOrder.prototype, 'byFieldMetadata');
|
|
50
|
+
fromEvent(KeyedOrderCreated)(KeyedOrder);
|
|
51
|
+
|
|
52
|
+
interface ChildrenDefinition {
|
|
53
|
+
IdentifiedBy: string;
|
|
54
|
+
From: Array<{ Key: { Id: string }; Value: { Key: string; ParentKey: string; Properties: Record<string, string> } }>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function registeredChildren(): Promise<Record<string, ChildrenDefinition>> {
|
|
58
|
+
const register = vi.fn().mockResolvedValue(undefined);
|
|
59
|
+
const connection = {
|
|
60
|
+
readModels: { registerMany: vi.fn().mockResolvedValue(undefined) },
|
|
61
|
+
projections: { register }
|
|
62
|
+
} as unknown as ChronicleConnection;
|
|
63
|
+
const artifacts = {
|
|
64
|
+
eventTypes: [], readModels: [KeyedOrder], reactors: [], reducers: [], seeders: [], constraints: [],
|
|
65
|
+
projections: [], webhooks: [], eventTypeMigrations: [], globalForHandlers: []
|
|
66
|
+
} as unknown as IClientArtifactsProvider;
|
|
67
|
+
await new Projections('test-store', 'test-namespace', connection, artifacts, 'test-sink').register();
|
|
68
|
+
return register.mock.calls[0][0].Projections[0].Children;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function creation(children: Record<string, ChildrenDefinition>, property: string) {
|
|
72
|
+
const child = children[property];
|
|
73
|
+
const entry = child.From.find(candidate => candidate.Key.Id === 'KeyedItemAdded')!;
|
|
74
|
+
return { identifiedBy: child.IdentifiedBy, key: entry.Value.Key, parentKey: entry.Value.ParentKey, properties: entry.Value.Properties };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
describe('when registering childrenFrom with the options form', () => {
|
|
78
|
+
it('should key children by the event property and map the discovered identifier from it', async () => {
|
|
79
|
+
creation(await registeredChildren(), 'byKey').should.deep.equal({
|
|
80
|
+
identifiedBy: 'id', key: 'itemId', parentKey: '$eventSourceId', properties: { id: 'itemId' }
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should use an explicit identifiedBy with the default event source key', async () => {
|
|
85
|
+
creation(await registeredChildren(), 'byIdentifiedBy').should.deep.equal({
|
|
86
|
+
identifiedBy: 'sku', key: '$eventSourceId', parentKey: '$eventSourceId', properties: { sku: '$eventContext(EventSourceId)' }
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should use an explicit parent key with the default child key', async () => {
|
|
91
|
+
creation(await registeredChildren(), 'byParentKey').should.deep.equal({
|
|
92
|
+
identifiedBy: 'id', key: '$eventSourceId', parentKey: 'orderId', properties: { id: '$eventContext(EventSourceId)' }
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should map an explicit identifiedBy from an explicit key', async () => {
|
|
97
|
+
creation(await registeredChildren(), 'byKeyAndIdentifiedBy').should.deep.equal({
|
|
98
|
+
identifiedBy: 'sku', key: 'itemId', parentKey: '$eventSourceId', properties: { sku: 'itemId' }
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should combine an explicit key and parent key', async () => {
|
|
103
|
+
creation(await registeredChildren(), 'byKeyAndParentKey').should.deep.equal({
|
|
104
|
+
identifiedBy: 'id', key: 'itemId', parentKey: 'orderId', properties: { id: 'itemId' }
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should combine key, identifiedBy and parent key', async () => {
|
|
109
|
+
creation(await registeredChildren(), 'byAll').should.deep.equal({
|
|
110
|
+
identifiedBy: 'sku', key: 'itemId', parentKey: 'orderId', properties: { sku: 'itemId' }
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should emit the same definition when the child type comes from field metadata', async () => {
|
|
115
|
+
const children = await registeredChildren();
|
|
116
|
+
creation(children, 'byFieldMetadata').should.deep.equal(creation(children, 'byKey'));
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -20,8 +20,28 @@ export interface ChildrenFromMetadata {
|
|
|
20
20
|
readonly parentKey?: string;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/** Options for the options form of the childrenFrom property decorator. */
|
|
24
|
+
export interface ChildrenFromOptions {
|
|
25
|
+
/** The child type, for TypeScript runtimes without emitted generic metadata. */
|
|
26
|
+
readonly childType?: Function;
|
|
27
|
+
/** The event property name used as the key for children. Defaults to the event source identifier. */
|
|
28
|
+
readonly key?: string;
|
|
29
|
+
/** The child model property name used to uniquely identify instances in the collection. */
|
|
30
|
+
readonly identifiedBy?: string;
|
|
31
|
+
/** The event property name used as the parent key. Defaults to the event source identifier. */
|
|
32
|
+
readonly parentKey?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
const METADATA_KEY = 'chronicle:projection:childrenFrom';
|
|
24
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Property decorator that configures a children collection sub-projection from an event type.
|
|
39
|
+
* Use this form to name the child type and an explicit child key together.
|
|
40
|
+
* @param eventType - The event constructor.
|
|
41
|
+
* @param options - The child type, key, identifiedBy and parentKey.
|
|
42
|
+
* @returns A property decorator.
|
|
43
|
+
*/
|
|
44
|
+
export function childrenFrom(eventType: Function, options: ChildrenFromOptions): ChroniclePropertyDecorator;
|
|
25
45
|
/**
|
|
26
46
|
* Property decorator that configures a children collection sub-projection from an event type.
|
|
27
47
|
* @param eventType - The event constructor.
|
|
@@ -30,24 +50,40 @@ const METADATA_KEY = 'chronicle:projection:childrenFrom';
|
|
|
30
50
|
* @param parentKey - Optional event property name used as the parent key.
|
|
31
51
|
* @returns A property decorator.
|
|
32
52
|
*/
|
|
53
|
+
export function childrenFrom(eventType: Function, key?: string | Function, identifiedBy?: string, parentKey?: string): ChroniclePropertyDecorator;
|
|
33
54
|
export function childrenFrom(
|
|
34
55
|
eventType: Function,
|
|
35
|
-
|
|
56
|
+
keyOrOptions?: string | Function | ChildrenFromOptions,
|
|
36
57
|
identifiedBy?: string,
|
|
37
58
|
parentKey?: string
|
|
38
59
|
): ChroniclePropertyDecorator {
|
|
60
|
+
const metadata = toMetadata(eventType, keyOrOptions, identifiedBy, parentKey);
|
|
39
61
|
return decorateModelBoundProperty((target: object, propertyKey: string | symbol) => {
|
|
40
62
|
const propKey = propertyKey.toString();
|
|
41
63
|
TypeIntrospector.trackProperty((target as { constructor: Function }).constructor, propKey);
|
|
42
64
|
const existing: ChildrenFromMetadata[] = Reflect.getMetadata(METADATA_KEY, target, propKey) ?? [];
|
|
43
|
-
const metadata: ChildrenFromMetadata = {
|
|
44
|
-
eventType, key: typeof key === 'string' ? key : undefined,
|
|
45
|
-
childType: typeof key === 'function' ? key : undefined, identifiedBy, parentKey
|
|
46
|
-
};
|
|
47
65
|
Reflect.defineMetadata(METADATA_KEY, [...existing, metadata], target, propKey);
|
|
48
66
|
});
|
|
49
67
|
}
|
|
50
68
|
|
|
69
|
+
function toMetadata(
|
|
70
|
+
eventType: Function,
|
|
71
|
+
keyOrOptions: string | Function | ChildrenFromOptions | undefined,
|
|
72
|
+
identifiedBy: string | undefined,
|
|
73
|
+
parentKey: string | undefined
|
|
74
|
+
): ChildrenFromMetadata {
|
|
75
|
+
if (typeof keyOrOptions === 'object' && keyOrOptions !== null) {
|
|
76
|
+
return {
|
|
77
|
+
eventType, childType: keyOrOptions.childType, key: keyOrOptions.key,
|
|
78
|
+
identifiedBy: keyOrOptions.identifiedBy, parentKey: keyOrOptions.parentKey
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
eventType, key: typeof keyOrOptions === 'string' ? keyOrOptions : undefined,
|
|
83
|
+
childType: typeof keyOrOptions === 'function' ? keyOrOptions : undefined, identifiedBy, parentKey
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
51
87
|
/**
|
|
52
88
|
* Retrieves all childrenFrom metadata stored on the given property.
|
|
53
89
|
* @param target - The class prototype.
|
|
@@ -21,7 +21,7 @@ export type { DecrementMetadata } from './decrement.js';
|
|
|
21
21
|
export { count, getCountMetadata } from './count.js';
|
|
22
22
|
export type { CountMetadata } from './count.js';
|
|
23
23
|
export { childrenFrom, getChildrenFromMetadata } from './childrenFrom.js';
|
|
24
|
-
export type { ChildrenFromMetadata } from './childrenFrom.js';
|
|
24
|
+
export type { ChildrenFromMetadata, ChildrenFromOptions } from './childrenFrom.js';
|
|
25
25
|
export { nested, isNested } from './nested.js';
|
|
26
26
|
export { clearWith, getClearWithClassMetadata, getClearWithPropertyMetadata } from './clearWith.js';
|
|
27
27
|
export type { ClearWithMetadata } from './clearWith.js';
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import 'reflect-metadata';
|
|
5
|
+
import { readFileSync } from 'node:fs';
|
|
6
|
+
import { chai, describe, it, vi } from 'vitest';
|
|
7
|
+
import { field } from '@cratis/fundamentals';
|
|
8
|
+
import { eventType, getEventTypeMetadata } from '../events/eventTypeDecorator.js';
|
|
9
|
+
import { constraint } from '../events/constraints/constraint.js';
|
|
10
|
+
import { compileConstraints } from '../events/constraints/Constraints.js';
|
|
11
|
+
import type { IConstraint } from '../events/constraints/IConstraint.js';
|
|
12
|
+
import type { IConstraintBuilder } from '../events/constraints/IConstraintBuilder.js';
|
|
13
|
+
import { EventScenario, UnsupportedEventSequenceOperation } from './index.js';
|
|
14
|
+
import { InProcessConstraints } from './InProcessConstraints.js';
|
|
15
|
+
import { ReactorScenario } from './ReactorScenario.js';
|
|
16
|
+
import { reactor } from '../reactors/reactor.js';
|
|
17
|
+
|
|
18
|
+
chai.should();
|
|
19
|
+
class OracleDomainText { @field(String) key: string; constructor(key: string) { this.key = key; } }
|
|
20
|
+
eventType('OracleDomainText')(OracleDomainText);
|
|
21
|
+
class OracleDomainRemoved { @field(String) label: string; constructor(label: string) { this.label = label; } }
|
|
22
|
+
eventType('OracleDomainRemoved')(OracleDomainRemoved);
|
|
23
|
+
class OracleCompositeName {
|
|
24
|
+
@field(String) first: string; @field(String) last: string;
|
|
25
|
+
constructor(first: string, last: string) { this.first = first; this.last = last; }
|
|
26
|
+
}
|
|
27
|
+
eventType('OracleCompositeName')(OracleCompositeName);
|
|
28
|
+
class OracleCompositeAlias {
|
|
29
|
+
@field(String) given: string; @field(String) family: string;
|
|
30
|
+
constructor(given: string, family: string) { this.given = given; this.family = family; }
|
|
31
|
+
}
|
|
32
|
+
eventType('OracleCompositeAlias')(OracleCompositeAlias);
|
|
33
|
+
class OracleCompositeTriple {
|
|
34
|
+
@field(String) first: string; @field(String) middle: string; @field(String) last: string;
|
|
35
|
+
constructor(first: string, middle: string, last: string) { this.first = first; this.middle = middle; this.last = last; }
|
|
36
|
+
}
|
|
37
|
+
eventType('OracleCompositeTriple')(OracleCompositeTriple);
|
|
38
|
+
|
|
39
|
+
// Declared order differs from field order on the alias type: family, then given.
|
|
40
|
+
class FullName implements IConstraint {
|
|
41
|
+
define(builder: IConstraintBuilder) {
|
|
42
|
+
builder.unique(key => key.on(OracleCompositeName, event => event.first, event => event.last)
|
|
43
|
+
.on(OracleCompositeAlias, event => event.family, event => event.given)
|
|
44
|
+
.on(OracleDomainText, event => event.key)
|
|
45
|
+
.removedWith(OracleDomainRemoved).withMessage('Taken: {PropertyName}={PropertyValue}'));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
constraint('OracleFullName')(FullName);
|
|
49
|
+
class Triple implements IConstraint {
|
|
50
|
+
define(builder: IConstraintBuilder) {
|
|
51
|
+
builder.unique(key => key.on(OracleCompositeTriple, event => event.first, event => event.middle, event => event.last));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
constraint('OracleTriple')(Triple);
|
|
55
|
+
class Handle implements IConstraint {
|
|
56
|
+
define(builder: IConstraintBuilder) {
|
|
57
|
+
builder.unique(key => key.on(OracleDomainText, event => event.key).ignoreCasing()
|
|
58
|
+
.removedWith(OracleDomainRemoved).withMessage('Handle taken: {PropertyValue}'));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
constraint('OracleHandle')(Handle);
|
|
62
|
+
class CasedName implements IConstraint {
|
|
63
|
+
define(builder: IConstraintBuilder) {
|
|
64
|
+
builder.unique(key => key.on(OracleCompositeName, event => event.first, event => event.last).ignoreCasing());
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
constraint('OracleCasedName')(CasedName);
|
|
68
|
+
|
|
69
|
+
const aliases = { string: OracleDomainText, removed: OracleDomainRemoved, name: OracleCompositeName,
|
|
70
|
+
alias: OracleCompositeAlias, triple: OracleCompositeTriple };
|
|
71
|
+
type Alias = keyof typeof aliases;
|
|
72
|
+
type Input = { source: string; type: Alias; value?: string; values?: Record<string, string> };
|
|
73
|
+
type History = { sequence: string; source: string; sourceType: string; streamType: string; streamId: string;
|
|
74
|
+
type: string; content: Record<string, string>; hash: string };
|
|
75
|
+
type Violation = { EventTypeId: string; SequenceNumber: string; ConstraintType: number; ConstraintName: string;
|
|
76
|
+
Message: string; Details: Record<string, string> };
|
|
77
|
+
type Outcome = { success: boolean; sequences: string[]; violations: Array<{ id: string; message: string; details: Record<string, string> }>;
|
|
78
|
+
wireViolations: Violation[]; errors: string[]; history: History[]; next: string };
|
|
79
|
+
type Fixture = { eventSchemas: Record<string, { eventTypeId: string; properties: Record<string, string> }>;
|
|
80
|
+
constraintDefinitions: Array<{ kind: string; name: string; events: Array<{ type: string; properties: string[] }>;
|
|
81
|
+
ignoreCasing: boolean; removedWithEventTypeIds: string[]; message: string }>;
|
|
82
|
+
isolatedConstraintOperations: Array<{ mode: 'single' | 'batch'; events: Input[] }>;
|
|
83
|
+
expected: { outcomes: Outcome[] } };
|
|
84
|
+
const aliasById = Object.fromEntries(Object.entries(aliases).map(([alias, type]) => [getEventTypeMetadata(type)!.eventType.id.value, alias]));
|
|
85
|
+
const makeEvent = ({ type, value, values }: Input): object => {
|
|
86
|
+
switch (type) {
|
|
87
|
+
case 'string': return new OracleDomainText(value!);
|
|
88
|
+
case 'removed': return new OracleDomainRemoved(value!);
|
|
89
|
+
case 'name': return new OracleCompositeName(values!.first, values!.last);
|
|
90
|
+
case 'alias': return new OracleCompositeAlias(values!.given, values!.family);
|
|
91
|
+
case 'triple': return new OracleCompositeTriple(values!.first, values!.middle, values!.last);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const historyOf = (scenario: EventScenario): History[] => scenario.appendedEvents.map(entry => ({
|
|
95
|
+
sequence: entry.context.sequenceNumber.toString(), source: entry.context.eventSourceId,
|
|
96
|
+
sourceType: entry.context.eventSourceType, streamType: entry.context.eventStreamType, streamId: entry.context.eventStreamId,
|
|
97
|
+
type: entry.eventType.id.value, content: entry.content as Record<string, string>, hash: entry.context.hash
|
|
98
|
+
}));
|
|
99
|
+
const unsupported = async (action: () => unknown, operation: string, reason: string) => {
|
|
100
|
+
await Promise.resolve().then(action).then(() => { throw new Error('Expected rejection'); }, error => {
|
|
101
|
+
(error instanceof UnsupportedEventSequenceOperation).should.be.true;
|
|
102
|
+
(error as Error).message.should.include(`UnsupportedEventSequenceOperation: ${operation}:`);
|
|
103
|
+
(error as Error).message.should.include(reason);
|
|
104
|
+
(error as Error).message.should.include('Use a kernel-backed test.');
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
const compositeTypes = Object.values(aliases);
|
|
108
|
+
const shapeReason = 'Only one to three distinct flat properties per event type are fixture-backed; nested, indexed or repeated key paths are not.';
|
|
109
|
+
|
|
110
|
+
async function matchesFixture(name: string, selected: readonly Function[], constraints: readonly Function[]) {
|
|
111
|
+
const fixture = JSON.parse(readFileSync(new URL(`./fixtures/${name}.json`, import.meta.url), 'utf8')) as Fixture;
|
|
112
|
+
const ids = new Set(selected);
|
|
113
|
+
Object.fromEntries(Object.entries(aliases).filter(([, type]) => ids.has(type)).map(([alias, type]) => {
|
|
114
|
+
const metadata = getEventTypeMetadata(type)!;
|
|
115
|
+
return [alias, { eventTypeId: metadata.eventType.id.value,
|
|
116
|
+
properties: Object.fromEntries(Object.entries(metadata.schema.properties ?? {}).map(([key, property]) => [key, property.type])) }];
|
|
117
|
+
})).should.deep.equal(fixture.eventSchemas);
|
|
118
|
+
const compiled = compileConstraints({ eventTypes: [...selected], constraints: [...constraints] });
|
|
119
|
+
[...compiled].map(([key, capture]) => ({ kind: 'uniqueProperty', name: key,
|
|
120
|
+
events: capture.uniqueConstraint!.eventDefinitions.map(entry => ({ type: aliasById[entry.eventTypeId], properties: entry.properties })),
|
|
121
|
+
ignoreCasing: capture.uniqueConstraint!.ignoreCasing,
|
|
122
|
+
removedWithEventTypeIds: (capture.uniqueConstraint!.removedWithEventTypeIds ?? []).map(id => aliasById[id]),
|
|
123
|
+
message: capture.uniqueConstraint!.message ?? ''
|
|
124
|
+
})).should.deep.equal(fixture.constraintDefinitions);
|
|
125
|
+
fixture.isolatedConstraintOperations.length.should.be.greaterThan(0);
|
|
126
|
+
fixture.expected.outcomes.length.should.equal(fixture.isolatedConstraintOperations.length);
|
|
127
|
+
fixture.expected.outcomes.some(outcome => !outcome.success).should.be.true;
|
|
128
|
+
const scenario = new EventScenario({ artifacts: { eventTypes: [...selected], constraints: [...constraints] } });
|
|
129
|
+
const notifications = scenario.eventSequence.appendOperations[Symbol.asyncIterator]();
|
|
130
|
+
const validate = vi.spyOn(InProcessConstraints.prototype, 'validate');
|
|
131
|
+
let count = 0;
|
|
132
|
+
try {
|
|
133
|
+
for (const [index, operation] of fixture.isolatedConstraintOperations.entries()) {
|
|
134
|
+
const expected = fixture.expected.outcomes[index];
|
|
135
|
+
const before = historyOf(scenario);
|
|
136
|
+
const calls = validate.mock.calls.length;
|
|
137
|
+
const nextNotification = notifications.next();
|
|
138
|
+
const results = operation.mode === 'single'
|
|
139
|
+
? [await scenario.append(operation.events[0].source, makeEvent(operation.events[0]))]
|
|
140
|
+
: await scenario.appendMany(operation.events.map(entry => ({ eventSourceId: entry.source, event: makeEvent(entry) })));
|
|
141
|
+
const notification = (await nextNotification).value!;
|
|
142
|
+
validate.mock.calls.length.should.equal(calls + 1);
|
|
143
|
+
const raw = validate.mock.results.at(-1)?.value as ReturnType<InProcessConstraints['validate']>;
|
|
144
|
+
raw.map(({ SequenceNumber, ...violation }) => ({ ...violation, SequenceNumber: SequenceNumber.toString() }))
|
|
145
|
+
.should.deep.equal(expected.wireViolations);
|
|
146
|
+
notification.length.should.equal(operation.events.length);
|
|
147
|
+
notification.every(item => item.result.isSuccess === expected.success).should.be.true;
|
|
148
|
+
count += operation.events.length;
|
|
149
|
+
scenario.results.length.should.equal(count);
|
|
150
|
+
results.length.should.equal(operation.events.length);
|
|
151
|
+
for (const [position, result] of results.entries()) {
|
|
152
|
+
result.isSuccess.should.equal(expected.success);
|
|
153
|
+
result.sequenceNumber.value.toString().should.equal(expected.success ? expected.sequences[position] : '0');
|
|
154
|
+
result.constraintViolations.map(item => ({ id: item.constraintId, message: item.message, details: item.details }))
|
|
155
|
+
.should.deep.equal(expected.violations);
|
|
156
|
+
result.errors.map(item => item.message).should.deep.equal(expected.errors);
|
|
157
|
+
}
|
|
158
|
+
if (!expected.success) historyOf(scenario).should.deep.equal(before);
|
|
159
|
+
historyOf(scenario).should.deep.equal(expected.history);
|
|
160
|
+
(await scenario.eventSequence.getNextSequenceNumber()).value.toString().should.equal(expected.next);
|
|
161
|
+
}
|
|
162
|
+
} finally {
|
|
163
|
+
validate.mockRestore();
|
|
164
|
+
await notifications.return?.();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
describe('fixture-backed composite unique-property keys', () => {
|
|
169
|
+
it('matches the pinned kernel constraints-composite: declared order, dash joining, per-property violations, hashes and rollback',
|
|
170
|
+
() => matchesFixture('constraints-composite', compositeTypes, [FullName, Triple]));
|
|
171
|
+
|
|
172
|
+
it('rejects a repeated key path at the key-shape check, while the distinct shape is accepted', async () => {
|
|
173
|
+
class Repeated implements IConstraint {
|
|
174
|
+
define(builder: IConstraintBuilder) {
|
|
175
|
+
builder.unique(key => key.on(OracleCompositeName, event => event.first, event => event.first));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
constraint('OracleRepeatedPath')(Repeated);
|
|
179
|
+
class Distinct implements IConstraint {
|
|
180
|
+
define(builder: IConstraintBuilder) {
|
|
181
|
+
builder.unique(key => key.on(OracleCompositeName, event => event.first, event => event.last));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
constraint('OracleRepeatedPath')(Distinct);
|
|
185
|
+
new EventScenario({ artifacts: { eventTypes: [OracleCompositeName], constraints: [Distinct] } }).should.be.instanceOf(EventScenario);
|
|
186
|
+
await unsupported(() => new EventScenario({ artifacts: { eventTypes: [OracleCompositeName], constraints: [Repeated] } }),
|
|
187
|
+
'artifacts.constraints (OracleRepeatedPath)', shapeReason);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('rejects four key properties at the key-shape check, while three are accepted', async () => {
|
|
191
|
+
class Quad {
|
|
192
|
+
@field(String) a = 'a'; @field(String) b = 'b'; @field(String) c = 'c'; @field(String) d = 'd';
|
|
193
|
+
}
|
|
194
|
+
eventType('OracleCompositeQuad')(Quad);
|
|
195
|
+
class Four implements IConstraint {
|
|
196
|
+
define(builder: IConstraintBuilder) {
|
|
197
|
+
builder.unique(key => key.on(Quad, event => event.a, event => event.b, event => event.c, event => event.d));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
constraint('OracleQuad')(Four);
|
|
201
|
+
class Three implements IConstraint {
|
|
202
|
+
define(builder: IConstraintBuilder) { builder.unique(key => key.on(Quad, event => event.a, event => event.b, event => event.c)); }
|
|
203
|
+
}
|
|
204
|
+
constraint('OracleQuad')(Three);
|
|
205
|
+
new EventScenario({ artifacts: { eventTypes: [Quad], constraints: [Three] } }).should.be.instanceOf(EventScenario);
|
|
206
|
+
await unsupported(() => new EventScenario({ artifacts: { eventTypes: [Quad], constraints: [Four] } }),
|
|
207
|
+
'artifacts.constraints (OracleQuad)', shapeReason);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('rejects nested and indexed key paths at the key-shape check, while the flat path is accepted', async () => {
|
|
211
|
+
// The event schema must stay flat to pass the schema check; the accessors reach the paths 'a.b' and 'items.0'.
|
|
212
|
+
class Nested { @field(String) a = 'a'; }
|
|
213
|
+
eventType('OracleCompositeNested')(Nested);
|
|
214
|
+
type Shaped = { a: { b: string }; items: string[] };
|
|
215
|
+
class Deep implements IConstraint {
|
|
216
|
+
define(builder: IConstraintBuilder) {
|
|
217
|
+
builder.unique(key => key.on(Nested, event => event.a, event => (event as unknown as Shaped).a.b));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
constraint('OracleNestedPath')(Deep);
|
|
221
|
+
class Indexed implements IConstraint {
|
|
222
|
+
define(builder: IConstraintBuilder) {
|
|
223
|
+
builder.unique(key => key.on(Nested, event => event.a, event => (event as unknown as Shaped).items[0]));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
constraint('OracleNestedPath')(Indexed);
|
|
227
|
+
class Flat implements IConstraint {
|
|
228
|
+
define(builder: IConstraintBuilder) { builder.unique(key => key.on(Nested, event => event.a)); }
|
|
229
|
+
}
|
|
230
|
+
constraint('OracleNestedPath')(Flat);
|
|
231
|
+
new EventScenario({ artifacts: { eventTypes: [Nested], constraints: [Flat] } }).should.be.instanceOf(EventScenario);
|
|
232
|
+
await unsupported(() => new EventScenario({ artifacts: { eventTypes: [Nested], constraints: [Deep] } }),
|
|
233
|
+
'artifacts.constraints (OracleNestedPath)', shapeReason);
|
|
234
|
+
await unsupported(() => new EventScenario({ artifacts: { eventTypes: [Nested], constraints: [Indexed] } }),
|
|
235
|
+
'artifacts.constraints (OracleNestedPath)', shapeReason);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('rejects a composite with a boolean component, while the boolean alone is accepted', async () => {
|
|
239
|
+
class Mixed { @field(String) label = 'x'; @field(Boolean) active = true; }
|
|
240
|
+
eventType('OracleCompositeMixed')(Mixed);
|
|
241
|
+
class Composite implements IConstraint {
|
|
242
|
+
define(builder: IConstraintBuilder) { builder.unique(key => key.on(Mixed, event => event.label, event => event.active)); }
|
|
243
|
+
}
|
|
244
|
+
constraint('OracleMixed')(Composite);
|
|
245
|
+
class Single implements IConstraint {
|
|
246
|
+
define(builder: IConstraintBuilder) { builder.unique(key => key.on(Mixed, event => event.active)); }
|
|
247
|
+
}
|
|
248
|
+
constraint('OracleMixed')(Single);
|
|
249
|
+
new EventScenario({ artifacts: { eventTypes: [Mixed], constraints: [Single] } }).should.be.instanceOf(EventScenario);
|
|
250
|
+
await unsupported(() => new EventScenario({ artifacts: { eventTypes: [Mixed], constraints: [Composite] } }),
|
|
251
|
+
'artifacts.constraints (OracleMixed)', 'Every property of a composite key must be a schema-backed string.');
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('rejects an unproven component value in a batch and leaves history, results and claims unchanged', async () => {
|
|
255
|
+
const scenario = new EventScenario({ artifacts: { eventTypes: compositeTypes, constraints: [FullName, Triple] } });
|
|
256
|
+
(await scenario.append('A', new OracleCompositeName('Ada', 'Lovelace'))).isSuccess.should.be.true;
|
|
257
|
+
const before = historyOf(scenario);
|
|
258
|
+
const results = [...scenario.results];
|
|
259
|
+
await unsupported(() => scenario.appendMany([{ eventSourceId: 'B', event: new OracleCompositeName('Grace', 'Hopper') },
|
|
260
|
+
{ eventSourceId: 'C', event: new OracleCompositeName('Ada', 'Love!') }]), 'artifacts.constraints (OracleFullName)',
|
|
261
|
+
'Only fixture-backed scalar string and boolean keys are supported.');
|
|
262
|
+
historyOf(scenario).should.deep.equal(before);
|
|
263
|
+
scenario.results.should.deep.equal(results);
|
|
264
|
+
(await scenario.append('D', new OracleCompositeName('Grace', 'Hopper'))).isSuccess.should.be.true;
|
|
265
|
+
(await scenario.append('E', new OracleCompositeName('Ada', 'Lovelace'))).constraintViolations
|
|
266
|
+
.map(item => item.message).should.deep.equal(['Taken: first=Ada', 'Taken: last=Lovelace']);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('rolls back a setup call that ends in a delimiter collision', async () => {
|
|
270
|
+
const scenario = new EventScenario({ artifacts: { eventTypes: compositeTypes, constraints: [FullName, Triple] } });
|
|
271
|
+
await scenario.given.forEventSource('A').events(new OracleCompositeName('a-b', 'c'));
|
|
272
|
+
await scenario.given.forEventSource('B').events(new OracleCompositeName('x', 'y'), new OracleCompositeName('a', 'b-c'))
|
|
273
|
+
.then(() => { throw new Error('Invalid setup succeeded'); }, error => {
|
|
274
|
+
(error as Error).message.should.include('EventScenario given setup failed');
|
|
275
|
+
});
|
|
276
|
+
historyOf(scenario).map(entry => entry.source).should.deep.equal(['A']);
|
|
277
|
+
(await scenario.append('C', new OracleCompositeName('x', 'y'))).isSuccess.should.be.true;
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('delivers only committed composite claims to a reactor', async () => {
|
|
281
|
+
const calls: string[] = [];
|
|
282
|
+
@reactor('composite-reactor')
|
|
283
|
+
class CompositeReactor {
|
|
284
|
+
oracleCompositeName(event: OracleCompositeName) { calls.push(`${event.first}/${event.last}`); }
|
|
285
|
+
oracleCompositeAlias(event: OracleCompositeAlias) { calls.push(`${event.family}/${event.given}`); }
|
|
286
|
+
}
|
|
287
|
+
const subject = new ReactorScenario(CompositeReactor, { artifacts: { eventTypes: compositeTypes, constraints: [FullName, Triple] } });
|
|
288
|
+
await subject.when.forEventSource('A').events(new OracleCompositeName('Ada', 'Lovelace'));
|
|
289
|
+
await subject.when.forEventSource('B').events(new OracleCompositeAlias('Lovelace', 'Ada'))
|
|
290
|
+
.then(() => { throw new Error('Colliding alias delivered'); }, error => {
|
|
291
|
+
(error as Error).message.should.include('ReactorScenario action append failed');
|
|
292
|
+
});
|
|
293
|
+
await subject.when.forEventSource('B').events(new OracleCompositeAlias('Ada', 'Lovelace'));
|
|
294
|
+
calls.should.deep.equal(['Ada/Lovelace', 'Lovelace/Ada']);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
describe('fixture-backed ASCII case-insensitive unique-property keys', () => {
|
|
299
|
+
const casingTypes = [OracleDomainText, OracleDomainRemoved, OracleCompositeName];
|
|
300
|
+
const asciiReason = 'Case-insensitive keys outside the ASCII key domain are not fixture-backed.';
|
|
301
|
+
|
|
302
|
+
it('matches the pinned kernel constraints-ignore-casing: ASCII folding, original-cased details, ownership, hashes and rollback',
|
|
303
|
+
() => matchesFixture('constraints-ignore-casing', casingTypes, [Handle, CasedName]));
|
|
304
|
+
|
|
305
|
+
it('rejects a non-ASCII key under ignoreCasing before mutation, while the case-sensitive definition accepts it', async () => {
|
|
306
|
+
const sensitive = new EventScenario({ artifacts: { eventTypes: compositeTypes, constraints: [FullName, Triple] } });
|
|
307
|
+
(await sensitive.append('A', new OracleCompositeName('Zo\u00e9', 'X'))).isSuccess.should.be.true;
|
|
308
|
+
const scenario = new EventScenario({ artifacts: { eventTypes: casingTypes, constraints: [Handle, CasedName] } });
|
|
309
|
+
(await scenario.append('A', new OracleDomainText('Alice'))).isSuccess.should.be.true;
|
|
310
|
+
const before = historyOf(scenario);
|
|
311
|
+
const results = [...scenario.results];
|
|
312
|
+
const notifications = scenario.eventSequence.appendOperations[Symbol.asyncIterator]();
|
|
313
|
+
try {
|
|
314
|
+
const notification = notifications.next();
|
|
315
|
+
await unsupported(() => scenario.append('B', new OracleDomainText('Zo\u00e9')), 'artifacts.constraints (OracleHandle)', asciiReason);
|
|
316
|
+
await unsupported(() => scenario.appendMany([{ eventSourceId: 'C', event: new OracleDomainText('Bob') },
|
|
317
|
+
{ eventSourceId: 'D', event: new OracleCompositeName('zo\u00e9', 'x') }]), 'artifacts.constraints (OracleCasedName)', asciiReason);
|
|
318
|
+
await unsupported(() => scenario.append('E', new OracleCompositeName('Zo\u00e9', 'X')), 'artifacts.constraints (OracleCasedName)', asciiReason);
|
|
319
|
+
historyOf(scenario).should.deep.equal(before);
|
|
320
|
+
scenario.results.should.deep.equal(results);
|
|
321
|
+
(await scenario.append('C', new OracleDomainText('BOB'))).isSuccess.should.be.true;
|
|
322
|
+
(await notification).value!.map(item => item.event.content).should.deep.equal([{ key: 'BOB' }]);
|
|
323
|
+
} finally { await notifications.return?.(); }
|
|
324
|
+
(await scenario.append('F', new OracleDomainText('bob'))).constraintViolations.map(item => item.message)
|
|
325
|
+
.should.deep.equal(['Handle taken: bob']);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('rejects ignoreCasing on a boolean key, while the case-sensitive boolean key is accepted', async () => {
|
|
329
|
+
class Flagged { @field(Boolean) active = true; }
|
|
330
|
+
eventType('OracleCasedFlag')(Flagged);
|
|
331
|
+
class Folded implements IConstraint {
|
|
332
|
+
define(builder: IConstraintBuilder) { builder.unique(key => key.on(Flagged, event => event.active).ignoreCasing()); }
|
|
333
|
+
}
|
|
334
|
+
constraint('OracleCasedFlag')(Folded);
|
|
335
|
+
class Exact implements IConstraint {
|
|
336
|
+
define(builder: IConstraintBuilder) { builder.unique(key => key.on(Flagged, event => event.active)); }
|
|
337
|
+
}
|
|
338
|
+
constraint('OracleCasedFlag')(Exact);
|
|
339
|
+
new EventScenario({ artifacts: { eventTypes: [Flagged], constraints: [Exact] } }).should.be.instanceOf(EventScenario);
|
|
340
|
+
await unsupported(() => new EventScenario({ artifacts: { eventTypes: [Flagged], constraints: [Folded] } }),
|
|
341
|
+
'artifacts.constraints (OracleCasedFlag)', 'Case-insensitive keys must be schema-backed strings.');
|
|
342
|
+
});
|
|
343
|
+
});
|
|
@@ -367,7 +367,7 @@ describe('fixture-backed unscoped constraints', () => {
|
|
|
367
367
|
scoped(builder => builder.perEventStreamType().unique(key => key.on(OracleKeyClaimed, event => event.key)));
|
|
368
368
|
scoped(builder => builder.perEventSourceType().unique(key => key.on(OracleKeyClaimed, event => event.key)));
|
|
369
369
|
scoped(builder => builder.unique(key => key.on(OracleKeyClaimed, event => event.key, event => event.key)));
|
|
370
|
-
scoped(builder => builder.unique(key => key.on(OracleKeyClaimed, event => event.key).ignoreCasing()));
|
|
370
|
+
scoped(builder => builder.perEventStreamId().unique(key => key.on(OracleKeyClaimed, event => event.key).ignoreCasing()));
|
|
371
371
|
scoped(builder => builder.unique(key => key.on(OracleKeyClaimed, event => event.key))
|
|
372
372
|
.uniqueFor(OracleOnceRecorded));
|
|
373
373
|
class AnotherOnce { @field(String) label = 'second'; }
|
|
@@ -58,7 +58,8 @@ const directory = new URL('./fixtures/', import.meta.url);
|
|
|
58
58
|
const fixtures = readdirSync(directory).filter(name => name.endsWith('.json') &&
|
|
59
59
|
!['batches.json', 'batch-omitted-routes.json', 'batch-rollback.json', 'builders.json', 'constraints.json', 'constraints-isolation.json', 'constraints-key-domain.json',
|
|
60
60
|
'constraints-property-lifecycle.json', 'constraints-property-covered-removal.json', 'constraints-event-type-cycles.json',
|
|
61
|
-
'constraints-event-type-siblings.json'
|
|
61
|
+
'constraints-event-type-siblings.json', 'constraints-composite.json',
|
|
62
|
+
'constraints-ignore-casing.json'].includes(name)).map(name => ({
|
|
62
63
|
name, fixture: JSON.parse(readFileSync(new URL(name, directory), 'utf8')) as Fixture
|
|
63
64
|
}));
|
|
64
65
|
const artifacts = { eventTypes: [OracleEventRecorded, AlternateRecorded, BoundaryRecorded], constraints: [] };
|
package/testing/EventScenario.ts
CHANGED
|
@@ -98,10 +98,21 @@ export class EventScenario {
|
|
|
98
98
|
}
|
|
99
99
|
for (const entry of capture.uniqueConstraint?.eventDefinitions ?? []) {
|
|
100
100
|
const type = eventTypes.find(type => getEventTypeFor(type).id.value === entry.eventTypeId)!;
|
|
101
|
-
|
|
101
|
+
const schemaTypes = entry.properties.map(property => getEventTypeMetadata(type)?.schema.properties?.[property]?.type ?? '');
|
|
102
|
+
if (entry.properties.length === 1 && !['string', 'boolean'].includes(schemaTypes[0])) {
|
|
102
103
|
throw new UnsupportedEventSequenceOperation('artifacts.constraints', name,
|
|
103
104
|
'The constrained property must be a schema-backed string or boolean.');
|
|
104
105
|
}
|
|
106
|
+
// constraints-ignore-casing.json captures folded string keys only.
|
|
107
|
+
if (capture.uniqueConstraint!.ignoreCasing && schemaTypes.some(schemaType => schemaType !== 'string')) {
|
|
108
|
+
throw new UnsupportedEventSequenceOperation('artifacts.constraints', name,
|
|
109
|
+
'Case-insensitive keys must be schema-backed strings.');
|
|
110
|
+
}
|
|
111
|
+
// constraints-composite.json captures string components only.
|
|
112
|
+
if (entry.properties.length > 1 && schemaTypes.some(schemaType => schemaType !== 'string')) {
|
|
113
|
+
throw new UnsupportedEventSequenceOperation('artifacts.constraints', name,
|
|
114
|
+
'Every property of a composite key must be a schema-backed string.');
|
|
115
|
+
}
|
|
105
116
|
}
|
|
106
117
|
}
|
|
107
118
|
} catch (error) {
|
|
@@ -26,6 +26,29 @@ function keyHash(value: string): string {
|
|
|
26
26
|
return createHash('sha256').update(value).digest('hex');
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
type UniqueCapture = NonNullable<ConstraintCapture['uniqueConstraint']>;
|
|
30
|
+
type Claim = { key: string; parts: Array<{ property: string; raw: string }> };
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The kernel key: each declared property's string in declared order, joined with a literal '-'
|
|
34
|
+
* (UniqueConstraintDefinitionExtensions.GetPropertiesAndValues/GetValue at Chronicle 8fe5d30). Not a tuple:
|
|
35
|
+
* ['a-b', 'c'] and ['a', 'b-c'] claim the same key, as constraints-composite.json captures.
|
|
36
|
+
*/
|
|
37
|
+
function claimOf(name: string, unique: UniqueCapture, eventTypeId: string, content: Record<string, unknown>): Claim | undefined {
|
|
38
|
+
const properties = unique.eventDefinitions.find(entry => entry.eventTypeId === eventTypeId)?.properties;
|
|
39
|
+
if (properties === undefined) return undefined;
|
|
40
|
+
const parts = properties.map(property => ({ property, raw: kernelKeyString(content[property], name) }));
|
|
41
|
+
const joined = parts.map(part => part.raw).join('-');
|
|
42
|
+
if (!unique.ignoreCasing) return { key: keyHash(joined), parts };
|
|
43
|
+
// The kernel applies .NET ToLowerInvariant to the joined value. constraints-ignore-casing.json proves
|
|
44
|
+
// only the ASCII key domain, where that is exactly A-Z to a-z; host Unicode case tables are not used.
|
|
45
|
+
if (!/^[\x20-\x7e]*$/.test(joined)) {
|
|
46
|
+
throw new UnsupportedEventSequenceOperation('artifacts.constraints', name,
|
|
47
|
+
'Case-insensitive keys outside the ASCII key domain are not fixture-backed.');
|
|
48
|
+
}
|
|
49
|
+
return { key: keyHash(joined.replace(/[A-Z]/g, letter => String.fromCharCode(letter.charCodeAt(0) + 32))), parts };
|
|
50
|
+
}
|
|
51
|
+
|
|
29
52
|
/** Narrow, fixture-backed unscoped constraint validation over serialized event snapshots. */
|
|
30
53
|
export class InProcessConstraints {
|
|
31
54
|
private readonly _constrainedProperties = new Map<string, Set<string>>();
|
|
@@ -44,10 +67,13 @@ export class InProcessConstraints {
|
|
|
44
67
|
}
|
|
45
68
|
if (capture.uniqueConstraint) {
|
|
46
69
|
const unique = capture.uniqueConstraint;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
70
|
+
// constraints-composite.json installs one, two and three flat properties per event type.
|
|
71
|
+
// The kernel keys properties by path with ToDictionary, so duplicate paths are not a key shape.
|
|
72
|
+
if (unique.eventDefinitions.length === 0 || unique.eventDefinitions.some(entry =>
|
|
73
|
+
entry.properties.length < 1 || entry.properties.length > 3 ||
|
|
74
|
+
new Set(entry.properties).size !== entry.properties.length ||
|
|
75
|
+
entry.properties.some(property => !/^[a-z][a-zA-Z0-9]*$/.test(property)))) {
|
|
76
|
+
throw this.unsupported(name, 'Only one to three distinct flat properties per event type are fixture-backed; nested, indexed or repeated key paths are not.');
|
|
51
77
|
}
|
|
52
78
|
for (const id of [unique.removedWithEventTypeId, ...(unique.removedWithEventTypeIds ?? [])]) {
|
|
53
79
|
if (id === undefined) continue;
|
|
@@ -61,7 +87,7 @@ export class InProcessConstraints {
|
|
|
61
87
|
}
|
|
62
88
|
for (const entry of unique.eventDefinitions) {
|
|
63
89
|
const properties = this._constrainedProperties.get(entry.eventTypeId) ?? new Set<string>();
|
|
64
|
-
properties.add(
|
|
90
|
+
entry.properties.forEach(property => properties.add(property));
|
|
65
91
|
this._constrainedProperties.set(entry.eventTypeId, properties);
|
|
66
92
|
}
|
|
67
93
|
} else if (capture.uniqueEventType) {
|
|
@@ -132,11 +158,12 @@ export class InProcessConstraints {
|
|
|
132
158
|
claims.delete(source);
|
|
133
159
|
continue;
|
|
134
160
|
}
|
|
135
|
-
const
|
|
136
|
-
if (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
161
|
+
const properties = unique.eventDefinitions.find(entry => entry.eventTypeId === type)?.properties;
|
|
162
|
+
if (properties === undefined) continue;
|
|
163
|
+
if (properties.some(property => !['string', 'boolean'].includes(typeof prior.content[property]))) {
|
|
164
|
+
throw this.unsupported(name, 'History has an unproven key.');
|
|
165
|
+
}
|
|
166
|
+
claims.set(source, { key: claimOf(name, unique, type, prior.content)!.key,
|
|
140
167
|
sequence: prior.context.sequenceNumber.toString() });
|
|
141
168
|
}
|
|
142
169
|
owners.set(name, claims);
|
|
@@ -148,19 +175,21 @@ export class InProcessConstraints {
|
|
|
148
175
|
const source = event.context.eventSourceId;
|
|
149
176
|
const violationCount = violations.length;
|
|
150
177
|
for (const [name, definition] of this._definitions) {
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
const
|
|
154
|
-
const key = keyHash(raw);
|
|
178
|
+
const claim = definition.uniqueConstraint && claimOf(name, definition.uniqueConstraint, type, event.content);
|
|
179
|
+
if (claim) {
|
|
180
|
+
const key = claim.key;
|
|
155
181
|
const existing = [...owners.get(name)!.entries()].find(([, claim]) => claim.key === key);
|
|
156
182
|
const batchClaims = stagedKeys.get(name) ?? new Map<string, string>();
|
|
157
183
|
const batchOwner = batchClaims.get(key);
|
|
158
184
|
if (existing && existing[0] !== source || batchOwner !== undefined && batchOwner !== source) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
185
|
+
// One violation per declared property, in declared order, each with its own original value.
|
|
186
|
+
const sequence = existing?.[1].sequence ?? unavailable;
|
|
187
|
+
for (const { property, raw } of claim.parts) {
|
|
188
|
+
violations.push({ EventTypeId: type, SequenceNumber: BigInt(sequence), ConstraintType: 1,
|
|
189
|
+
ConstraintName: name,
|
|
190
|
+
Message: `Event '${type}' on member '${property}' violated a unique constraint on sequence number ${sequence}`,
|
|
191
|
+
Details: { PropertyName: property, PropertyValue: raw } });
|
|
192
|
+
}
|
|
164
193
|
} else {
|
|
165
194
|
batchClaims.set(key, source);
|
|
166
195
|
stagedKeys.set(name, batchClaims);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
2
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
|
+
|
|
4
|
+
import { chai, describe, it } from 'vitest';
|
|
5
|
+
import { eventType } from '../events/eventTypeDecorator.js';
|
|
6
|
+
import { childrenFrom } from '../projections/modelBound/childrenFrom.js';
|
|
7
|
+
import { fromEvent } from '../projections/modelBound/fromEvent.js';
|
|
8
|
+
import { ReadModelScenario, UnsupportedProjectionOperation } from './index.js';
|
|
9
|
+
|
|
10
|
+
chai.should();
|
|
11
|
+
|
|
12
|
+
class ScenarioItemAdded {
|
|
13
|
+
itemId = '';
|
|
14
|
+
name = '';
|
|
15
|
+
}
|
|
16
|
+
eventType('scenario-keyed-item-added')(ScenarioItemAdded);
|
|
17
|
+
|
|
18
|
+
class ScenarioItem {
|
|
19
|
+
id = '';
|
|
20
|
+
name = '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class ScenarioOrder {
|
|
24
|
+
items: ScenarioItem[] = [];
|
|
25
|
+
}
|
|
26
|
+
childrenFrom(ScenarioItemAdded, { childType: ScenarioItem, key: 'itemId' })(ScenarioOrder.prototype, 'items');
|
|
27
|
+
fromEvent(ScenarioItemAdded)(ScenarioOrder);
|
|
28
|
+
|
|
29
|
+
describe('when a read model scenario evaluates keyed children from the options form', () => {
|
|
30
|
+
it('should reject children projections explicitly when the scenario is created', () => {
|
|
31
|
+
(() => new ReadModelScenario(ScenarioOrder, { eventTypes: [ScenarioItemAdded], reducers: [], projections: [] }))
|
|
32
|
+
.should.throw(UnsupportedProjectionOperation)
|
|
33
|
+
.with.property('message').that.includes('Children.items (@childrenFrom)').and.includes('children projections');
|
|
34
|
+
});
|
|
35
|
+
});
|