@cratis/chronicle 6.17.0 → 6.18.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/AddChildBuilder.d.ts +13 -2
- package/dist/projections/declarative/AddChildBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/AddChildBuilder.js +27 -1
- package/dist/projections/declarative/AddChildBuilder.js.map +1 -1
- package/dist/projections/declarative/FromBuilder.d.ts +4 -0
- package/dist/projections/declarative/FromBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/FromBuilder.js +1 -2
- package/dist/projections/declarative/FromBuilder.js.map +1 -1
- package/dist/projections/declarative/IAddChildBuilder.d.ts +12 -0
- package/dist/projections/declarative/IAddChildBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/IReadModelPropertiesBuilder.d.ts +16 -1
- package/dist/projections/declarative/IReadModelPropertiesBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/JoinBuilder.d.ts +4 -0
- package/dist/projections/declarative/JoinBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/JoinBuilder.js +1 -2
- package/dist/projections/declarative/JoinBuilder.js.map +1 -1
- package/dist/projections/declarative/ProjectionBuilderCore.js +1 -1
- package/dist/projections/declarative/ProjectionBuilderCore.js.map +1 -1
- package/dist/projections/modelBound/childrenAndNestedBuilder.d.ts.map +1 -1
- package/dist/projections/modelBound/childrenAndNestedBuilder.js +41 -10
- package/dist/projections/modelBound/childrenAndNestedBuilder.js.map +1 -1
- package/package.json +2 -2
- package/projections/ProjectionDefinitionCompiler.registration.spec.ts +4 -2
- package/projections/Projections.childrenAndNested.spec.ts +250 -1
- package/projections/declarative/AddChildBuilder.ts +33 -2
- package/projections/declarative/FromBuilder.ts +9 -1
- package/projections/declarative/IAddChildBuilder.ts +14 -0
- package/projections/declarative/IReadModelPropertiesBuilder.ts +18 -1
- package/projections/declarative/JoinBuilder.ts +9 -1
- package/projections/declarative/ProjectionBuilderCore.ts +1 -1
- package/projections/declarative/addChildCompatibility.standard.spec.ts +80 -0
- package/projections/eventContextExpressions.spec.ts +20 -0
- package/projections/modelBound/childrenAndNestedBuilder.ts +45 -11
|
@@ -48,6 +48,8 @@ export interface ChildrenDefinitionLike {
|
|
|
48
48
|
NoAutoMapProperties: string[];
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
const aggregateExpressions = ['$count', '$increment', '$decrement', '$add', '$subtract'];
|
|
52
|
+
|
|
51
53
|
/**
|
|
52
54
|
* Resolves the contract event type for a decorated event constructor.
|
|
53
55
|
* @param eventTypeConstructor - The event class constructor.
|
|
@@ -209,23 +211,20 @@ export function resolveNestedType(type: Function, property: string): Function |
|
|
|
209
211
|
|
|
210
212
|
/**
|
|
211
213
|
* Discovers the child model property used to identify instances, by convention: a property
|
|
212
|
-
* named `id` (case-insensitive), matching the
|
|
213
|
-
*
|
|
214
|
+
* named `id` (case-insensitive), or a property matching the event key when no id is found.
|
|
215
|
+
* TypeScript has no `[Key]` decorator equivalent.
|
|
214
216
|
* @param childType - The child/nested model type, when resolvable.
|
|
217
|
+
* @param eventKey - The configured event key, when present.
|
|
215
218
|
* @returns The discovered property name, or undefined when no convention match is found.
|
|
216
219
|
*/
|
|
217
|
-
function discoverIdentifiedBy(childType: Function | undefined): string | undefined {
|
|
220
|
+
function discoverIdentifiedBy(childType: Function | undefined, eventKey: string | undefined): string | undefined {
|
|
218
221
|
if (!childType) {
|
|
219
222
|
return undefined;
|
|
220
223
|
}
|
|
221
224
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return undefined;
|
|
225
|
+
const members = [...TypeIntrospector.getMembers(childType).keys()];
|
|
226
|
+
return members.find(name => name.toLowerCase() === 'id') ??
|
|
227
|
+
(eventKey !== undefined ? members.find(name => name.toLowerCase() === eventKey.toLowerCase()) : undefined);
|
|
229
228
|
}
|
|
230
229
|
|
|
231
230
|
/**
|
|
@@ -325,7 +324,7 @@ export function buildChildrenEntry(type: Function, property: string, metadataLis
|
|
|
325
324
|
const definition = createEmptyChildrenDefinition(type, childType);
|
|
326
325
|
|
|
327
326
|
const explicitIdentifiedBy = metadataList.find(metadata => metadata.identifiedBy)?.identifiedBy;
|
|
328
|
-
definition.IdentifiedBy = explicitIdentifiedBy ?? discoverIdentifiedBy(childType) ?? '$eventSourceId';
|
|
327
|
+
definition.IdentifiedBy = explicitIdentifiedBy ?? discoverIdentifiedBy(childType, metadataList[0]?.key) ?? '$eventSourceId';
|
|
329
328
|
|
|
330
329
|
for (const metadata of metadataList) {
|
|
331
330
|
const eventType = toContractEventType(metadata.eventType);
|
|
@@ -340,6 +339,41 @@ export function buildChildrenEntry(type: Function, property: string, metadataLis
|
|
|
340
339
|
}
|
|
341
340
|
|
|
342
341
|
populateFromType(definition, childType);
|
|
342
|
+
|
|
343
|
+
// For non-aggregate-only creating events, populate an unmapped child identifier from
|
|
344
|
+
// the creating event's key. IdentifiedBy selects the child property; it is not itself
|
|
345
|
+
// a property mapping. TypeScript has no [Key] decorator, so an explicit identifiedBy
|
|
346
|
+
// plays the same role as a discovered id for this default.
|
|
347
|
+
const identifier = definition.IdentifiedBy;
|
|
348
|
+
if (definition.AutoMap === AutoMap.Enabled && identifier !== '$eventSourceId') {
|
|
349
|
+
const prototype = childType?.prototype;
|
|
350
|
+
const hasExplicitMapping = prototype !== undefined && (
|
|
351
|
+
getSetFromMetadata(prototype, identifier).length > 0 ||
|
|
352
|
+
getSetFromContextMetadata(prototype, identifier).length > 0 ||
|
|
353
|
+
getSetValueMetadata(prototype, identifier).length > 0 ||
|
|
354
|
+
getAddFromMetadata(prototype, identifier).length > 0 ||
|
|
355
|
+
getSubtractFromMetadata(prototype, identifier).length > 0);
|
|
356
|
+
if (!hasExplicitMapping) {
|
|
357
|
+
for (const metadata of metadataList) {
|
|
358
|
+
const entry = definition.From.find(candidate => getEventTypeMapKey(candidate.Key) === getEventTypeMapKey(toContractEventType(metadata.eventType)))!;
|
|
359
|
+
const mappings = Object.values(entry.Value.Properties);
|
|
360
|
+
// Preserve the kernel's aggregate-only AutoMap exemption: Changeset.AddChild already
|
|
361
|
+
// initializes the child identifier from the resolved key before applying property mappers.
|
|
362
|
+
if (mappings.length > 0 && mappings.every(expression =>
|
|
363
|
+
aggregateExpressions.some(aggregate => expression.startsWith(aggregate)))) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
// Child property mappings may replace the creating key (for example, a constant-key count).
|
|
367
|
+
const key = entry.Value.Key;
|
|
368
|
+
// When an event property is also the identifier, AutoMap can fill it directly.
|
|
369
|
+
if (key.toLowerCase() !== identifier.toLowerCase() && !(identifier in entry.Value.Properties)) {
|
|
370
|
+
entry.Value.Properties[identifier] = key === '$eventSourceId'
|
|
371
|
+
? eventContextPropertyExpression('eventSourceId')
|
|
372
|
+
: key;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
343
377
|
return definition;
|
|
344
378
|
}
|
|
345
379
|
|