@cratis/chronicle 3.0.0 → 3.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/EventStore.ts +17 -1
- package/IEventStore.ts +16 -0
- package/auditing/CausationType.ts +10 -0
- package/compliance/ComplianceContracts.ts +84 -0
- package/compliance/IPIIManager.ts +17 -0
- package/compliance/PIIManager.ts +31 -0
- package/compliance/index.ts +2 -0
- package/connection/ChronicleConnection.ts +7 -1
- package/connection/ChronicleServices.ts +2 -0
- package/connection/Guid.ts +18 -0
- package/dist/EventStore.d.ts +8 -0
- package/dist/EventStore.d.ts.map +1 -1
- package/dist/EventStore.js +13 -1
- package/dist/EventStore.js.map +1 -1
- package/dist/IEventStore.d.ts +12 -0
- package/dist/IEventStore.d.ts.map +1 -1
- package/dist/auditing/CausationType.d.ts +8 -0
- package/dist/auditing/CausationType.d.ts.map +1 -1
- package/dist/auditing/CausationType.js +8 -0
- package/dist/auditing/CausationType.js.map +1 -1
- package/dist/compliance/ComplianceContracts.d.ts +40 -0
- package/dist/compliance/ComplianceContracts.d.ts.map +1 -1
- package/dist/compliance/ComplianceContracts.js +71 -0
- package/dist/compliance/ComplianceContracts.js.map +1 -1
- package/dist/compliance/IPIIManager.d.ts +15 -0
- package/dist/compliance/IPIIManager.d.ts.map +1 -0
- package/dist/compliance/IPIIManager.js +4 -0
- package/dist/compliance/IPIIManager.js.map +1 -0
- package/dist/compliance/PIIManager.d.ts +20 -0
- package/dist/compliance/PIIManager.d.ts.map +1 -0
- package/dist/compliance/PIIManager.js +30 -0
- package/dist/compliance/PIIManager.js.map +1 -0
- package/dist/compliance/index.d.ts +2 -0
- package/dist/compliance/index.d.ts.map +1 -1
- package/dist/compliance/index.js +1 -0
- package/dist/compliance/index.js.map +1 -1
- package/dist/connection/ChronicleConnection.d.ts +1 -0
- package/dist/connection/ChronicleConnection.d.ts.map +1 -1
- package/dist/connection/ChronicleConnection.js +6 -1
- package/dist/connection/ChronicleConnection.js.map +1 -1
- package/dist/connection/ChronicleServices.d.ts +2 -0
- package/dist/connection/ChronicleServices.d.ts.map +1 -1
- package/dist/connection/Guid.d.ts +5 -0
- package/dist/connection/Guid.d.ts.map +1 -1
- package/dist/connection/Guid.js +15 -0
- package/dist/connection/Guid.js.map +1 -1
- package/dist/eventSequences/AppendOperationsBroadcaster.d.ts +16 -0
- package/dist/eventSequences/AppendOperationsBroadcaster.d.ts.map +1 -0
- package/dist/eventSequences/AppendOperationsBroadcaster.js +77 -0
- package/dist/eventSequences/AppendOperationsBroadcaster.js.map +1 -0
- package/dist/eventSequences/AppendOptions.d.ts +7 -0
- package/dist/eventSequences/AppendOptions.d.ts.map +1 -1
- package/dist/eventSequences/AppendResult.d.ts +14 -0
- package/dist/eventSequences/AppendResult.d.ts.map +1 -1
- package/dist/eventSequences/AppendedEventWithResult.d.ts +13 -0
- package/dist/eventSequences/AppendedEventWithResult.d.ts.map +1 -0
- package/dist/eventSequences/AppendedEventWithResult.js +4 -0
- package/dist/eventSequences/AppendedEventWithResult.js.map +1 -0
- package/dist/eventSequences/CompleteStreamError.d.ts +17 -0
- package/dist/eventSequences/CompleteStreamError.d.ts.map +1 -0
- package/dist/eventSequences/CompleteStreamError.js +20 -0
- package/dist/eventSequences/CompleteStreamError.js.map +1 -0
- package/dist/eventSequences/CompleteStreamResult.d.ts +14 -0
- package/dist/eventSequences/CompleteStreamResult.d.ts.map +1 -0
- package/dist/eventSequences/CompleteStreamResult.js +4 -0
- package/dist/eventSequences/CompleteStreamResult.js.map +1 -0
- package/dist/eventSequences/ConcurrencyViolation.d.ts +13 -0
- package/dist/eventSequences/ConcurrencyViolation.d.ts.map +1 -0
- package/dist/eventSequences/ConcurrencyViolation.js +4 -0
- package/dist/eventSequences/ConcurrencyViolation.js.map +1 -0
- package/dist/eventSequences/EventForEventSourceId.d.ts +8 -0
- package/dist/eventSequences/EventForEventSourceId.d.ts.map +1 -1
- package/dist/eventSequences/EventSequence.d.ts +35 -1
- package/dist/eventSequences/EventSequence.d.ts.map +1 -1
- package/dist/eventSequences/EventSequence.js +350 -19
- package/dist/eventSequences/EventSequence.js.map +1 -1
- package/dist/eventSequences/IEventSequence.d.ts +85 -1
- package/dist/eventSequences/IEventSequence.d.ts.map +1 -1
- package/dist/eventSequences/WaitForCompletionResult.d.ts +11 -0
- package/dist/eventSequences/WaitForCompletionResult.d.ts.map +1 -0
- package/dist/eventSequences/WaitForCompletionResult.js +4 -0
- package/dist/eventSequences/WaitForCompletionResult.js.map +1 -0
- package/dist/eventSequences/index.d.ts +5 -0
- package/dist/eventSequences/index.d.ts.map +1 -1
- package/dist/eventSequences/index.js +1 -0
- package/dist/eventSequences/index.js.map +1 -1
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.d.ts +3 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.d.ts.map +1 -1
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.js +9 -0
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.js.map +1 -1
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptions.d.ts +6 -0
- package/dist/eventStoreSubscriptions/IEventStoreSubscriptions.d.ts.map +1 -1
- package/dist/eventStoreSubscriptions/contracts.d.ts +18 -0
- package/dist/eventStoreSubscriptions/contracts.d.ts.map +1 -1
- package/dist/eventStoreSubscriptions/contracts.js +106 -0
- package/dist/eventStoreSubscriptions/contracts.js.map +1 -1
- package/dist/events/constraints/Constraints.js +1 -1
- package/dist/events/constraints/Constraints.js.map +1 -1
- package/dist/externalServices/ExternalServiceBuilder.d.ts +42 -0
- package/dist/externalServices/ExternalServiceBuilder.d.ts.map +1 -0
- package/dist/externalServices/ExternalServiceBuilder.js +110 -0
- package/dist/externalServices/ExternalServiceBuilder.js.map +1 -0
- package/dist/externalServices/ExternalServices.d.ts +19 -0
- package/dist/externalServices/ExternalServices.d.ts.map +1 -0
- package/dist/externalServices/ExternalServices.js +30 -0
- package/dist/externalServices/ExternalServices.js.map +1 -0
- package/dist/externalServices/ExternalServicesContracts.d.ts +137 -0
- package/dist/externalServices/ExternalServicesContracts.d.ts.map +1 -0
- package/dist/externalServices/ExternalServicesContracts.js +654 -0
- package/dist/externalServices/ExternalServicesContracts.js.map +1 -0
- package/dist/externalServices/IExternalServiceBuilder.d.ts +67 -0
- package/dist/externalServices/IExternalServiceBuilder.d.ts.map +1 -0
- package/dist/externalServices/IExternalServiceBuilder.js +4 -0
- package/dist/externalServices/IExternalServiceBuilder.js.map +1 -0
- package/dist/externalServices/IExternalServices.d.ts +13 -0
- package/dist/externalServices/IExternalServices.d.ts.map +1 -0
- package/dist/externalServices/IExternalServices.js +4 -0
- package/dist/externalServices/IExternalServices.js.map +1 -0
- package/dist/externalServices/index.d.ts +5 -0
- package/dist/externalServices/index.d.ts.map +1 -0
- package/dist/externalServices/index.js +5 -0
- package/dist/externalServices/index.js.map +1 -0
- package/dist/identities/IIdentityManager.d.ts +17 -0
- package/dist/identities/IIdentityManager.d.ts.map +1 -0
- package/dist/identities/IIdentityManager.js +4 -0
- package/dist/identities/IIdentityManager.js.map +1 -0
- package/dist/identities/IdentityManager.d.ts +20 -0
- package/dist/identities/IdentityManager.d.ts.map +1 -0
- package/dist/identities/IdentityManager.js +31 -0
- package/dist/identities/IdentityManager.js.map +1 -0
- package/dist/identities/index.d.ts +3 -0
- package/dist/identities/index.d.ts.map +1 -0
- package/dist/identities/index.js +4 -0
- package/dist/identities/index.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/observation/FailedPartition.d.ts +15 -0
- package/dist/observation/FailedPartition.d.ts.map +1 -0
- package/dist/observation/FailedPartition.js +4 -0
- package/dist/observation/FailedPartition.js.map +1 -0
- package/dist/observation/FailedPartitionAttempt.d.ts +15 -0
- package/dist/observation/FailedPartitionAttempt.d.ts.map +1 -0
- package/dist/observation/FailedPartitionAttempt.js +4 -0
- package/dist/observation/FailedPartitionAttempt.js.map +1 -0
- package/dist/observation/FailedPartitions.d.ts +24 -0
- package/dist/observation/FailedPartitions.d.ts.map +1 -0
- package/dist/observation/FailedPartitions.js +39 -0
- package/dist/observation/FailedPartitions.js.map +1 -0
- package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.d.ts +19 -0
- package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.d.ts.map +1 -0
- package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.js +4 -0
- package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.js.map +1 -0
- package/dist/observation/ICanBeNotifiedWhenReplay.d.ts +17 -0
- package/dist/observation/ICanBeNotifiedWhenReplay.d.ts.map +1 -0
- package/dist/observation/ICanBeNotifiedWhenReplay.js +4 -0
- package/dist/observation/ICanBeNotifiedWhenReplay.js.map +1 -0
- package/dist/observation/IFailedPartitions.d.ts +18 -0
- package/dist/observation/IFailedPartitions.d.ts.map +1 -0
- package/dist/observation/IFailedPartitions.js +4 -0
- package/dist/observation/IFailedPartitions.js.map +1 -0
- package/dist/observation/index.d.ts +6 -0
- package/dist/observation/index.d.ts.map +1 -1
- package/dist/observation/index.js +1 -0
- package/dist/observation/index.js.map +1 -1
- package/dist/observation/notifyReplayLifecycle.d.ts +13 -0
- package/dist/observation/notifyReplayLifecycle.d.ts.map +1 -0
- package/dist/observation/notifyReplayLifecycle.js +54 -0
- package/dist/observation/notifyReplayLifecycle.js.map +1 -0
- package/dist/observation/toClientFailedPartition.d.ts +9 -0
- package/dist/observation/toClientFailedPartition.d.ts.map +1 -0
- package/dist/observation/toClientFailedPartition.js +23 -0
- package/dist/observation/toClientFailedPartition.js.map +1 -0
- package/dist/projections/Projections.d.ts +0 -4
- package/dist/projections/Projections.d.ts.map +1 -1
- package/dist/projections/Projections.js +25 -103
- package/dist/projections/Projections.js.map +1 -1
- package/dist/projections/declarative/AddBuilder.d.ts +17 -0
- package/dist/projections/declarative/AddBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/AddBuilder.js +28 -0
- package/dist/projections/declarative/AddBuilder.js.map +1 -0
- package/dist/projections/declarative/AddChildBuilder.d.ts +56 -0
- package/dist/projections/declarative/AddChildBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/AddChildBuilder.js +72 -0
- package/dist/projections/declarative/AddChildBuilder.js.map +1 -0
- package/dist/projections/declarative/ChildrenBuilder.d.ts +28 -0
- package/dist/projections/declarative/ChildrenBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/ChildrenBuilder.js +72 -0
- package/dist/projections/declarative/ChildrenBuilder.js.map +1 -0
- package/dist/projections/declarative/CompositeKeyBuilder.d.ts +16 -0
- package/dist/projections/declarative/CompositeKeyBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/CompositeKeyBuilder.js +29 -0
- package/dist/projections/declarative/CompositeKeyBuilder.js.map +1 -0
- package/dist/projections/declarative/FromBuilder.d.ts +8 -6
- package/dist/projections/declarative/FromBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/FromBuilder.js +44 -14
- package/dist/projections/declarative/FromBuilder.js.map +1 -1
- package/dist/projections/declarative/ICompositeKeyBuilder.d.ts +5 -0
- package/dist/projections/declarative/ICompositeKeyBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/JoinBuilder.d.ts +7 -5
- package/dist/projections/declarative/JoinBuilder.d.ts.map +1 -1
- package/dist/projections/declarative/JoinBuilder.js +50 -16
- package/dist/projections/declarative/JoinBuilder.js.map +1 -1
- package/dist/projections/declarative/NestedBuilder.d.ts +24 -0
- package/dist/projections/declarative/NestedBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/NestedBuilder.js +60 -0
- package/dist/projections/declarative/NestedBuilder.js.map +1 -0
- package/dist/projections/declarative/ProjectionBuilderCore.d.ts +127 -0
- package/dist/projections/declarative/ProjectionBuilderCore.d.ts.map +1 -0
- package/dist/projections/declarative/ProjectionBuilderCore.js +180 -0
- package/dist/projections/declarative/ProjectionBuilderCore.js.map +1 -0
- package/dist/projections/declarative/ProjectionBuilderFor.d.ts +6 -32
- package/dist/projections/declarative/ProjectionBuilderFor.d.ts.map +1 -1
- package/dist/projections/declarative/ProjectionBuilderFor.js +24 -118
- package/dist/projections/declarative/ProjectionBuilderFor.js.map +1 -1
- package/dist/projections/declarative/SubtractBuilder.d.ts +17 -0
- package/dist/projections/declarative/SubtractBuilder.d.ts.map +1 -0
- package/dist/projections/declarative/SubtractBuilder.js +28 -0
- package/dist/projections/declarative/SubtractBuilder.js.map +1 -0
- package/dist/projections/declarative/index.d.ts +9 -0
- package/dist/projections/declarative/index.d.ts.map +1 -1
- package/dist/projections/declarative/index.js +8 -0
- package/dist/projections/declarative/index.js.map +1 -1
- package/dist/projections/modelBound/childrenAndNestedBuilder.d.ts +90 -0
- package/dist/projections/modelBound/childrenAndNestedBuilder.d.ts.map +1 -0
- package/dist/projections/modelBound/childrenAndNestedBuilder.js +290 -0
- package/dist/projections/modelBound/childrenAndNestedBuilder.js.map +1 -0
- package/dist/reactors/ReactorSideEffects.d.ts +29 -0
- package/dist/reactors/ReactorSideEffects.d.ts.map +1 -0
- package/dist/reactors/ReactorSideEffects.js +70 -0
- package/dist/reactors/ReactorSideEffects.js.map +1 -0
- package/dist/reactors/Reactors.d.ts +4 -1
- package/dist/reactors/Reactors.d.ts.map +1 -1
- package/dist/reactors/Reactors.js +23 -4
- package/dist/reactors/Reactors.js.map +1 -1
- package/dist/reducers/Reducers.d.ts.map +1 -1
- package/dist/reducers/Reducers.js +15 -3
- package/dist/reducers/Reducers.js.map +1 -1
- package/dist/reducers/reducer.d.ts +9 -1
- package/dist/reducers/reducer.d.ts.map +1 -1
- package/dist/reducers/reducer.js +4 -2
- package/dist/reducers/reducer.js.map +1 -1
- package/dist/transactions/IUnitOfWork.d.ts +18 -0
- package/dist/transactions/IUnitOfWork.d.ts.map +1 -1
- package/dist/transactions/UnitOfWork.d.ts +9 -0
- package/dist/transactions/UnitOfWork.d.ts.map +1 -1
- package/dist/transactions/UnitOfWork.js +14 -0
- package/dist/transactions/UnitOfWork.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/eventSequences/AppendOperationsBroadcaster.ts +83 -0
- package/eventSequences/AppendOptions.ts +8 -0
- package/eventSequences/AppendResult.ts +16 -0
- package/eventSequences/AppendedEventWithResult.ts +17 -0
- package/eventSequences/CompleteStreamError.ts +20 -0
- package/eventSequences/CompleteStreamResult.ts +13 -0
- package/eventSequences/ConcurrencyViolation.ts +18 -0
- package/eventSequences/EventForEventSourceId.ts +12 -0
- package/eventSequences/EventSequence.spec.ts +588 -0
- package/eventSequences/EventSequence.ts +406 -20
- package/eventSequences/IEventSequence.ts +109 -1
- package/eventSequences/WaitForCompletionResult.ts +15 -0
- package/eventSequences/index.ts +5 -0
- package/eventStoreSubscriptions/EventStoreSubscriptions.spec.ts +52 -0
- package/eventStoreSubscriptions/EventStoreSubscriptions.ts +19 -1
- package/eventStoreSubscriptions/IEventStoreSubscriptions.ts +7 -0
- package/eventStoreSubscriptions/contracts.ts +126 -0
- package/events/constraints/Constraints.ts +1 -1
- package/externalServices/ExternalServiceBuilder.ts +128 -0
- package/externalServices/ExternalServices.ts +34 -0
- package/externalServices/ExternalServicesContracts.ts +709 -0
- package/externalServices/IExternalServiceBuilder.ts +76 -0
- package/externalServices/IExternalServices.ts +16 -0
- package/externalServices/index.ts +7 -0
- package/identities/IIdentityManager.ts +19 -0
- package/identities/IdentityManager.ts +32 -0
- package/identities/index.ts +5 -0
- package/index.ts +6 -0
- package/observation/FailedPartition.ts +21 -0
- package/observation/FailedPartitionAttempt.ts +21 -0
- package/observation/FailedPartitions.spec.ts +75 -0
- package/observation/FailedPartitions.ts +44 -0
- package/observation/ICanBeNotifiedWhenPartitionReplayed.ts +22 -0
- package/observation/ICanBeNotifiedWhenReplay.ts +20 -0
- package/observation/IFailedPartitions.ts +22 -0
- package/observation/index.ts +6 -0
- package/observation/notifyReplayLifecycle.spec.ts +98 -0
- package/observation/notifyReplayLifecycle.ts +61 -0
- package/observation/toClientFailedPartition.ts +26 -0
- package/package.json +12 -2
- package/projections/Projections.childrenAndNested.spec.ts +188 -0
- package/projections/Projections.spec.ts +131 -0
- package/projections/Projections.ts +37 -119
- package/projections/declarative/AddBuilder.ts +28 -0
- package/projections/declarative/AddChildBuilder.ts +97 -0
- package/projections/declarative/ChildrenBuilder.spec.ts +157 -0
- package/projections/declarative/ChildrenBuilder.ts +90 -0
- package/projections/declarative/CompositeKeyBuilder.spec.ts +117 -0
- package/projections/declarative/CompositeKeyBuilder.ts +38 -0
- package/projections/declarative/FromBuilder.ts +60 -15
- package/projections/declarative/ICompositeKeyBuilder.ts +6 -0
- package/projections/declarative/JoinBuilder.ts +66 -17
- package/projections/declarative/NestedBuilder.ts +76 -0
- package/projections/declarative/ProjectionBuilderCore.ts +257 -0
- package/projections/declarative/ProjectionBuilderFor.spec.ts +115 -0
- package/projections/declarative/ProjectionBuilderFor.ts +29 -168
- package/projections/declarative/SubtractBuilder.ts +28 -0
- package/projections/declarative/index.ts +9 -0
- package/projections/modelBound/childrenAndNestedBuilder.ts +354 -0
- package/reactors/ReactorSideEffects.spec.ts +182 -0
- package/reactors/ReactorSideEffects.ts +97 -0
- package/reactors/Reactors.ts +29 -4
- package/reducers/Reducers.spec.ts +87 -0
- package/reducers/Reducers.ts +15 -3
- package/reducers/reducer.spec.ts +40 -0
- package/reducers/reducer.ts +11 -2
- package/transactions/IUnitOfWork.ts +21 -0
- package/transactions/UnitOfWork.spec.ts +82 -0
- package/transactions/UnitOfWork.ts +20 -0
|
@@ -0,0 +1,97 @@
|
|
|
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 { PropertyAccessor, PropertyPathResolverProxyHandler } from '@cratis/fundamentals';
|
|
5
|
+
import { IAddChildBuilder } from './IAddChildBuilder';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A single `.addChild()` accumulation captured on a from/join builder, later merged into the
|
|
9
|
+
* owning projection builder's `Children` definitions once the enclosing `.from()`/`.join()`
|
|
10
|
+
* call resolves the event type it belongs to.
|
|
11
|
+
*/
|
|
12
|
+
export interface ChildAdditionEntry {
|
|
13
|
+
/** The read model property the child is added to. */
|
|
14
|
+
targetProperty: string;
|
|
15
|
+
/** The child model property used to identify instances, when set via the builder callback overload. */
|
|
16
|
+
identifiedBy?: string;
|
|
17
|
+
/** The event property used as the key, when set via the builder callback overload. */
|
|
18
|
+
usingKey?: string;
|
|
19
|
+
/** The event property whose value becomes the child directly, when set via the plain accessor overload. */
|
|
20
|
+
fromEventProperty?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Implements {@link IAddChildBuilder} and doubles as a {@link ProxyHandler} so a single probe
|
|
25
|
+
* object can resolve `.addChild()`'s two call shapes at runtime: a plain event-property
|
|
26
|
+
* accessor (`e => e.someProperty`), or a builder callback (`b => b.usingKey(...)`). Known
|
|
27
|
+
* builder members are dispatched to the real implementation below; any other property access
|
|
28
|
+
* (the plain-accessor shape) falls through to the same path-capturing proxy used everywhere
|
|
29
|
+
* else in this file for `PropertyAccessor<T>` resolution.
|
|
30
|
+
* @template TChildModel - The child model type.
|
|
31
|
+
* @template TEvent - The event type.
|
|
32
|
+
*/
|
|
33
|
+
export class AddChildBuilder<TChildModel, TEvent> implements IAddChildBuilder<TChildModel, TEvent>, ProxyHandler<object> {
|
|
34
|
+
private readonly _pathHandler = new PropertyPathResolverProxyHandler();
|
|
35
|
+
private readonly _pathProxy = new Proxy({}, this._pathHandler);
|
|
36
|
+
private _usedAsBuilder = false;
|
|
37
|
+
private _identifiedByProperty: string | undefined;
|
|
38
|
+
private _usingKeyProperty: string | undefined;
|
|
39
|
+
|
|
40
|
+
/** Whether any builder member (`identifiedBy`/`usingKey`) was invoked on the probe. */
|
|
41
|
+
get usedAsBuilder(): boolean {
|
|
42
|
+
return this._usedAsBuilder;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The child model property captured via `identifiedBy()`, if any. */
|
|
46
|
+
get identifiedByProperty(): string | undefined {
|
|
47
|
+
return this._identifiedByProperty;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The event property captured via `usingKey()`, if any. */
|
|
51
|
+
get usingKeyProperty(): string | undefined {
|
|
52
|
+
return this._usingKeyProperty;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The event property path captured when the probe was used as a plain accessor. */
|
|
56
|
+
get capturedEventProperty(): string {
|
|
57
|
+
return this._pathHandler.property;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @inheritdoc */
|
|
61
|
+
identifiedBy(childPropertyAccessor: PropertyAccessor<TChildModel>): IAddChildBuilder<TChildModel, TEvent> {
|
|
62
|
+
this._usedAsBuilder = true;
|
|
63
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
64
|
+
const proxy = new Proxy({}, handler);
|
|
65
|
+
childPropertyAccessor(proxy as TChildModel);
|
|
66
|
+
this._identifiedByProperty = handler.property;
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** @inheritdoc */
|
|
71
|
+
usingKey(eventPropertyAccessor: PropertyAccessor<TEvent>): IAddChildBuilder<TChildModel, TEvent> {
|
|
72
|
+
this._usedAsBuilder = true;
|
|
73
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
74
|
+
const proxy = new Proxy({}, handler);
|
|
75
|
+
eventPropertyAccessor(proxy as TEvent);
|
|
76
|
+
this._usingKeyProperty = handler.property;
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Proxy `get` trap: known builder members dispatch to the real implementation above;
|
|
82
|
+
* anything else (a plain event property accessed by the accessor overload) falls through
|
|
83
|
+
* to path-capturing so the accessor overload keeps working against the same probe.
|
|
84
|
+
* @param _target - The proxy's (unused) empty target object.
|
|
85
|
+
* @param prop - The accessed property name.
|
|
86
|
+
* @returns The resolved member.
|
|
87
|
+
*/
|
|
88
|
+
get(_target: object, prop: string | symbol): unknown {
|
|
89
|
+
if (prop === 'identifiedBy') {
|
|
90
|
+
return this.identifiedBy.bind(this);
|
|
91
|
+
}
|
|
92
|
+
if (prop === 'usingKey') {
|
|
93
|
+
return this.usingKey.bind(this);
|
|
94
|
+
}
|
|
95
|
+
return Reflect.get(this._pathProxy as object, prop);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
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 { describe, expect, it } from 'vitest';
|
|
6
|
+
import { eventType } from '../../events/eventTypeDecorator';
|
|
7
|
+
import { ProjectionBuilderFor } from './ProjectionBuilderFor';
|
|
8
|
+
|
|
9
|
+
// Decorators are applied as plain function calls (rather than `@decorator` syntax) so these
|
|
10
|
+
// fixtures don't depend on the test runner's decorator-syntax support.
|
|
11
|
+
|
|
12
|
+
class LineAdded {
|
|
13
|
+
productId!: string;
|
|
14
|
+
quantity!: number;
|
|
15
|
+
}
|
|
16
|
+
eventType()(LineAdded);
|
|
17
|
+
|
|
18
|
+
class TagAdded {
|
|
19
|
+
name!: string;
|
|
20
|
+
}
|
|
21
|
+
eventType()(TagAdded);
|
|
22
|
+
|
|
23
|
+
class SummaryUpdated {
|
|
24
|
+
total!: number;
|
|
25
|
+
}
|
|
26
|
+
eventType()(SummaryUpdated);
|
|
27
|
+
|
|
28
|
+
class SummaryCleared {}
|
|
29
|
+
eventType()(SummaryCleared);
|
|
30
|
+
|
|
31
|
+
class WholeLineReceived {
|
|
32
|
+
productId!: string;
|
|
33
|
+
}
|
|
34
|
+
eventType()(WholeLineReceived);
|
|
35
|
+
|
|
36
|
+
class OrderLine {
|
|
37
|
+
productId!: string;
|
|
38
|
+
quantity!: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class OrderSummary {
|
|
42
|
+
total!: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
class Order {
|
|
46
|
+
id!: string;
|
|
47
|
+
lines!: OrderLine[];
|
|
48
|
+
tags!: string[];
|
|
49
|
+
summary!: OrderSummary | undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface FromRecord {
|
|
53
|
+
Key: { Id: string };
|
|
54
|
+
Value: { Properties: Record<string, string>; Key: string; ParentKey: string };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface ChildrenDefinition {
|
|
58
|
+
IdentifiedBy: string;
|
|
59
|
+
From: FromRecord[];
|
|
60
|
+
RemovedWith: Array<{ Key: { Id: string } }>;
|
|
61
|
+
FromEventProperty?: { Event: { Id: string } | undefined; PropertyExpression: string };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface BuiltDefinition {
|
|
65
|
+
From: FromRecord[];
|
|
66
|
+
Children: Record<string, ChildrenDefinition>;
|
|
67
|
+
Nested: Record<string, ChildrenDefinition>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
describe('ChildrenBuilder and NestedBuilder', () => {
|
|
71
|
+
describe('when using children on the top-level builder', () => {
|
|
72
|
+
it('should produce a children definition keyed by the target property', () => {
|
|
73
|
+
const builder = new ProjectionBuilderFor<Order>();
|
|
74
|
+
builder.children<OrderLine>(order => order.lines, children => children
|
|
75
|
+
.identifiedBy(line => line.productId)
|
|
76
|
+
.from(LineAdded, from => from.set(line => line.quantity).to(event => event.quantity)));
|
|
77
|
+
|
|
78
|
+
const definition = builder.build('order', 'Order') as unknown as BuiltDefinition;
|
|
79
|
+
const linesDefinition = definition.Children.lines;
|
|
80
|
+
|
|
81
|
+
expect(linesDefinition.IdentifiedBy).toBe('productId');
|
|
82
|
+
const fromEntry = linesDefinition.From.find(candidate => candidate.Key.Id === 'LineAdded')!;
|
|
83
|
+
expect(fromEntry.Value.Properties.quantity).toBe('quantity');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('when using nested with clearWith on the top-level builder', () => {
|
|
88
|
+
it('should produce a nested definition with a RemovedWith entry', () => {
|
|
89
|
+
const builder = new ProjectionBuilderFor<Order>();
|
|
90
|
+
builder.nested<OrderSummary>(order => order.summary, nested => nested
|
|
91
|
+
.from(SummaryUpdated, from => from.set(summary => summary.total).to(event => event.total))
|
|
92
|
+
.clearWith(SummaryCleared));
|
|
93
|
+
|
|
94
|
+
const definition = builder.build('order', 'Order') as unknown as BuiltDefinition;
|
|
95
|
+
const summaryDefinition = definition.Nested.summary;
|
|
96
|
+
|
|
97
|
+
const fromEntry = summaryDefinition.From.find(candidate => candidate.Key.Id === 'SummaryUpdated')!;
|
|
98
|
+
expect(fromEntry.Value.Properties.total).toBe('total');
|
|
99
|
+
expect(summaryDefinition.RemovedWith[0].Key.Id).toBe('SummaryCleared');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('when using addChild with a builder callback', () => {
|
|
104
|
+
it('should produce a children definition keyed by identifiedBy and usingKey', () => {
|
|
105
|
+
const builder = new ProjectionBuilderFor<Order>();
|
|
106
|
+
builder.from(LineAdded, from => from.addChild<OrderLine>(order => order.lines, child => child
|
|
107
|
+
.identifiedBy(line => line.productId)
|
|
108
|
+
.usingKey(event => event.productId)));
|
|
109
|
+
|
|
110
|
+
const definition = builder.build('order', 'Order') as unknown as BuiltDefinition;
|
|
111
|
+
const linesDefinition = definition.Children.lines;
|
|
112
|
+
|
|
113
|
+
expect(linesDefinition.IdentifiedBy).toBe('productId');
|
|
114
|
+
const fromEntry = linesDefinition.From.find(candidate => candidate.Key.Id === 'LineAdded')!;
|
|
115
|
+
expect(fromEntry.Value.Key).toBe('productId');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('when using addChild with a plain event property accessor', () => {
|
|
120
|
+
it('should produce a children definition with a FromEventProperty expression', () => {
|
|
121
|
+
const builder = new ProjectionBuilderFor<Order>();
|
|
122
|
+
builder.from(TagAdded, from => from.addChild<string>(order => order.tags, event => event.name));
|
|
123
|
+
|
|
124
|
+
const definition = builder.build('order', 'Order') as unknown as BuiltDefinition;
|
|
125
|
+
const tagsDefinition = definition.Children.tags;
|
|
126
|
+
|
|
127
|
+
expect(tagsDefinition.FromEventProperty?.PropertyExpression).toBe('name');
|
|
128
|
+
expect(tagsDefinition.FromEventProperty?.Event?.Id).toBe('TagAdded');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('when using addChild on a join builder', () => {
|
|
133
|
+
it('should produce a children definition from the join clause', () => {
|
|
134
|
+
const builder = new ProjectionBuilderFor<Order>();
|
|
135
|
+
builder.join(WholeLineReceived, join => join.addChild<OrderLine>(order => order.lines, child => child
|
|
136
|
+
.identifiedBy(line => line.productId)));
|
|
137
|
+
|
|
138
|
+
const definition = builder.build('order', 'Order') as unknown as BuiltDefinition;
|
|
139
|
+
const linesDefinition = definition.Children.lines;
|
|
140
|
+
|
|
141
|
+
expect(linesDefinition.IdentifiedBy).toBe('productId');
|
|
142
|
+
expect(linesDefinition.From.some(candidate => candidate.Key.Id === 'WholeLineReceived')).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('when using setThisValue on a from builder', () => {
|
|
147
|
+
it('should map the whole event property onto the $this well-known expression', () => {
|
|
148
|
+
const builder = new ProjectionBuilderFor<Order>();
|
|
149
|
+
builder.from(TagAdded, from => from.setThisValue().to(event => event.name));
|
|
150
|
+
|
|
151
|
+
const definition = builder.build('order', 'Order') as unknown as BuiltDefinition;
|
|
152
|
+
const fromEntry = definition.From.find(candidate => candidate.Key.Id === 'TagAdded')!;
|
|
153
|
+
|
|
154
|
+
expect(fromEntry.Value.Properties.$this).toBe('name');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
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 { PropertyAccessor, PropertyPathResolverProxyHandler } from '@cratis/fundamentals';
|
|
5
|
+
import { ChildrenDefinitionLike, ProjectionBuilderCore } from './ProjectionBuilderCore';
|
|
6
|
+
import { IChildrenBuilder } from './IChildrenBuilder';
|
|
7
|
+
import { INestedBuilder } from './INestedBuilder';
|
|
8
|
+
import { NestedBuilder } from './NestedBuilder';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Concrete implementation of {@link IChildrenBuilder}, building the `ChildrenDefinition` for a
|
|
12
|
+
* children collection sub-projection reached through `.children()`.
|
|
13
|
+
* @template TParentReadModel - The parent read model type.
|
|
14
|
+
* @template TChildReadModel - The child read model type.
|
|
15
|
+
*/
|
|
16
|
+
export class ChildrenBuilder<TParentReadModel, TChildReadModel>
|
|
17
|
+
extends ProjectionBuilderCore<TChildReadModel, IChildrenBuilder<TParentReadModel, TChildReadModel>>
|
|
18
|
+
implements IChildrenBuilder<TParentReadModel, TChildReadModel> {
|
|
19
|
+
private _identifiedBy: string | undefined;
|
|
20
|
+
private _fromEventPropertyPath: string | undefined;
|
|
21
|
+
|
|
22
|
+
/** @inheritdoc */
|
|
23
|
+
identifiedBy(propertyAccessor: PropertyAccessor<TChildReadModel>): IChildrenBuilder<TParentReadModel, TChildReadModel> {
|
|
24
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
25
|
+
const proxy = new Proxy({}, handler);
|
|
26
|
+
propertyAccessor(proxy as TChildReadModel);
|
|
27
|
+
this._identifiedBy = handler.property;
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** @inheritdoc */
|
|
32
|
+
fromEventProperty<TEvent>(propertyAccessor: PropertyAccessor<TEvent>): IChildrenBuilder<TParentReadModel, TChildReadModel> {
|
|
33
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
34
|
+
const proxy = new Proxy({}, handler);
|
|
35
|
+
propertyAccessor(proxy as TEvent);
|
|
36
|
+
this._fromEventPropertyPath = handler.property;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** @inheritdoc */
|
|
41
|
+
children<TGrandchildModel>(
|
|
42
|
+
targetPropertyAccessor: PropertyAccessor<TChildReadModel>,
|
|
43
|
+
builderCallback: (builder: IChildrenBuilder<TChildReadModel, TGrandchildModel>) => void
|
|
44
|
+
): IChildrenBuilder<TParentReadModel, TChildReadModel> {
|
|
45
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
46
|
+
const proxy = new Proxy({}, handler);
|
|
47
|
+
targetPropertyAccessor(proxy as TChildReadModel);
|
|
48
|
+
|
|
49
|
+
const builder = new ChildrenBuilder<TChildReadModel, TGrandchildModel>();
|
|
50
|
+
builderCallback(builder);
|
|
51
|
+
this._children[handler.property] = builder.buildDefinition();
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** @inheritdoc */
|
|
56
|
+
nested<TNestedModel>(
|
|
57
|
+
targetPropertyAccessor: PropertyAccessor<TChildReadModel>,
|
|
58
|
+
builderCallback: (builder: INestedBuilder<TChildReadModel, TNestedModel>) => void
|
|
59
|
+
): IChildrenBuilder<TParentReadModel, TChildReadModel> {
|
|
60
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
61
|
+
const proxy = new Proxy({}, handler);
|
|
62
|
+
targetPropertyAccessor(proxy as TChildReadModel);
|
|
63
|
+
|
|
64
|
+
const builder = new NestedBuilder<TChildReadModel, TNestedModel>();
|
|
65
|
+
builderCallback(builder);
|
|
66
|
+
this._nested[handler.property] = builder.buildDefinition();
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Builds the {@link ChildrenDefinitionLike} representing this children collection.
|
|
72
|
+
* @returns The accumulated children definition.
|
|
73
|
+
*/
|
|
74
|
+
buildDefinition(): ChildrenDefinitionLike {
|
|
75
|
+
return {
|
|
76
|
+
IdentifiedBy: this._identifiedBy ?? '$eventSourceId',
|
|
77
|
+
From: this._from,
|
|
78
|
+
Join: this._join,
|
|
79
|
+
Children: this._children,
|
|
80
|
+
All: this._all,
|
|
81
|
+
FromEventProperty: this._fromEventPropertyPath === undefined
|
|
82
|
+
? undefined
|
|
83
|
+
: { Event: undefined, PropertyExpression: this._fromEventPropertyPath },
|
|
84
|
+
RemovedWith: this._removedWith,
|
|
85
|
+
RemovedWithJoin: this._removedWithJoin,
|
|
86
|
+
AutoMap: this._autoMap,
|
|
87
|
+
Nested: this._nested
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
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 { describe, expect, it } from 'vitest';
|
|
6
|
+
import { eventType } from '../../events/eventTypeDecorator';
|
|
7
|
+
import { ProjectionBuilderFor } from './ProjectionBuilderFor';
|
|
8
|
+
|
|
9
|
+
// Decorators are applied as plain function calls (rather than `@decorator` syntax) so these
|
|
10
|
+
// fixtures don't depend on the test runner's decorator-syntax support.
|
|
11
|
+
|
|
12
|
+
class OrderLineAdded {
|
|
13
|
+
orderId!: string;
|
|
14
|
+
lineNumber!: number;
|
|
15
|
+
quantity!: number;
|
|
16
|
+
}
|
|
17
|
+
eventType()(OrderLineAdded);
|
|
18
|
+
|
|
19
|
+
class OrderLineJoined {
|
|
20
|
+
orderId!: string;
|
|
21
|
+
lineNumber!: number;
|
|
22
|
+
description!: string;
|
|
23
|
+
}
|
|
24
|
+
eventType()(OrderLineJoined);
|
|
25
|
+
|
|
26
|
+
class CompositeKey {
|
|
27
|
+
orderId!: string;
|
|
28
|
+
lineNumber!: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class OrderLine {
|
|
32
|
+
id!: string;
|
|
33
|
+
quantity!: number;
|
|
34
|
+
description!: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface FromRecord {
|
|
38
|
+
Key: { Id: string };
|
|
39
|
+
Value: { Key: string };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface JoinRecord {
|
|
43
|
+
Key: { Id: string };
|
|
44
|
+
Value: { Key: string };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface JoinRecordWithParentKey {
|
|
48
|
+
Key: { Id: string };
|
|
49
|
+
Value: { Key: string; ParentKey?: string };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
describe('CompositeKeyBuilder', () => {
|
|
53
|
+
describe('when using a composite key on a from builder', () => {
|
|
54
|
+
it('should produce a $composite expression', () => {
|
|
55
|
+
const builder = new ProjectionBuilderFor<OrderLine>();
|
|
56
|
+
builder.from(OrderLineAdded, from => from.usingCompositeKey<CompositeKey>(key => key
|
|
57
|
+
.set(target => target.orderId, event => event.orderId)
|
|
58
|
+
.set(target => target.lineNumber, event => event.lineNumber)));
|
|
59
|
+
|
|
60
|
+
const definition = builder.build('orderLine', 'OrderLine') as unknown as { From: FromRecord[] };
|
|
61
|
+
const entry = definition.From.find(candidate => candidate.Key.Id === 'OrderLineAdded')!;
|
|
62
|
+
|
|
63
|
+
expect(entry.Value.Key).toBe('$composite(orderId=orderId,lineNumber=lineNumber)');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('when using a parent composite key on a from builder', () => {
|
|
68
|
+
it('should produce a $composite expression for the parent key', () => {
|
|
69
|
+
const builder = new ProjectionBuilderFor<OrderLine>();
|
|
70
|
+
builder.from(OrderLineAdded, from => from.usingParentCompositeKey<CompositeKey>(key => key
|
|
71
|
+
.set(target => target.orderId, event => event.orderId)
|
|
72
|
+
.set(target => target.lineNumber, event => event.lineNumber)));
|
|
73
|
+
|
|
74
|
+
const definition = builder.build('orderLine', 'OrderLine') as unknown as { From: Array<{ Key: { Id: string }; Value: { ParentKey: string } }> };
|
|
75
|
+
const entry = definition.From.find(candidate => candidate.Key.Id === 'OrderLineAdded')!;
|
|
76
|
+
|
|
77
|
+
expect(entry.Value.ParentKey).toBe('$composite(orderId=orderId,lineNumber=lineNumber)');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('when using a composite key on a join builder', () => {
|
|
82
|
+
it('should produce a $composite expression', () => {
|
|
83
|
+
const builder = new ProjectionBuilderFor<OrderLine>();
|
|
84
|
+
builder.join(OrderLineJoined, join => join
|
|
85
|
+
.on(model => model.id)
|
|
86
|
+
.usingCompositeKey<CompositeKey>(key => key
|
|
87
|
+
.set(target => target.orderId, event => event.orderId)
|
|
88
|
+
.set(target => target.lineNumber, event => event.lineNumber)));
|
|
89
|
+
|
|
90
|
+
const definition = builder.build('orderLine', 'OrderLine') as unknown as { Join: JoinRecord[] };
|
|
91
|
+
const entry = definition.Join.find(candidate => candidate.Key.Id === 'OrderLineJoined')!;
|
|
92
|
+
|
|
93
|
+
expect(entry.Value.Key).toBe('$composite(orderId=orderId,lineNumber=lineNumber)');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('when using parent-key methods on a join builder', () => {
|
|
98
|
+
it('should accept the calls without throwing, matching the C# client having no wire effect for Join', () => {
|
|
99
|
+
const builder = new ProjectionBuilderFor<OrderLine>();
|
|
100
|
+
|
|
101
|
+
expect(() => builder.join(OrderLineJoined, join => join
|
|
102
|
+
.on(model => model.id)
|
|
103
|
+
.usingParentKey(event => event.orderId)
|
|
104
|
+
.usingParentKeyFromContext('someContextProperty')
|
|
105
|
+
.usingParentCompositeKey<CompositeKey>(key => key.set(target => target.orderId, event => event.orderId))
|
|
106
|
+
.usingConstantParentKey('constant')
|
|
107
|
+
)).not.toThrow();
|
|
108
|
+
|
|
109
|
+
const definition = builder.build('orderLine', 'OrderLine') as unknown as { Join: JoinRecordWithParentKey[] };
|
|
110
|
+
const entry = definition.Join.find(candidate => candidate.Key.Id === 'OrderLineJoined')!;
|
|
111
|
+
|
|
112
|
+
// JoinDefinition has no ParentKey slot on the wire, so none of the calls above
|
|
113
|
+
// should have produced a ParentKey property.
|
|
114
|
+
expect(entry.Value.ParentKey).toBeUndefined();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
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 { PropertyAccessor, PropertyPathResolverProxyHandler } from '@cratis/fundamentals';
|
|
5
|
+
import { ICompositeKeyBuilder } from './ICompositeKeyBuilder';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Concrete implementation of {@link ICompositeKeyBuilder} that builds a `$composite(...)` key
|
|
9
|
+
* expression from multiple event properties mapped onto named parts of a key type.
|
|
10
|
+
* @template TKeyType - The composite key type.
|
|
11
|
+
* @template TEvent - The event type.
|
|
12
|
+
*/
|
|
13
|
+
export class CompositeKeyBuilder<TKeyType, TEvent> implements ICompositeKeyBuilder<TKeyType, TEvent> {
|
|
14
|
+
private readonly _parts: Array<{ property: string; expression: string }> = [];
|
|
15
|
+
|
|
16
|
+
/** @inheritdoc */
|
|
17
|
+
set(
|
|
18
|
+
targetPropertyAccessor: PropertyAccessor<TKeyType>,
|
|
19
|
+
sourcePropertyAccessor: PropertyAccessor<TEvent>
|
|
20
|
+
): ICompositeKeyBuilder<TKeyType, TEvent> {
|
|
21
|
+
const targetHandler = new PropertyPathResolverProxyHandler();
|
|
22
|
+
const targetProxy = new Proxy({}, targetHandler);
|
|
23
|
+
targetPropertyAccessor(targetProxy as TKeyType);
|
|
24
|
+
|
|
25
|
+
const sourceHandler = new PropertyPathResolverProxyHandler();
|
|
26
|
+
const sourceProxy = new Proxy({}, sourceHandler);
|
|
27
|
+
sourcePropertyAccessor(sourceProxy as TEvent);
|
|
28
|
+
|
|
29
|
+
this._parts.push({ property: targetHandler.property, expression: sourceHandler.property });
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** @inheritdoc */
|
|
34
|
+
build(): string {
|
|
35
|
+
const parts = this._parts.map(part => `${part.property}=${part.expression}`).join(',');
|
|
36
|
+
return `$composite(${parts})`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
4
|
import { PropertyAccessor, PropertyPathResolverProxyHandler } from '@cratis/fundamentals';
|
|
5
|
+
import { AddBuilder } from './AddBuilder';
|
|
6
|
+
import { AddChildBuilder, ChildAdditionEntry } from './AddChildBuilder';
|
|
7
|
+
import { CompositeKeyBuilder } from './CompositeKeyBuilder';
|
|
5
8
|
import { IAddBuilder } from './IAddBuilder';
|
|
6
9
|
import { IAddChildBuilder } from './IAddChildBuilder';
|
|
7
10
|
import { ICompositeKeyBuilder } from './ICompositeKeyBuilder';
|
|
@@ -9,6 +12,7 @@ import { IFromBuilder } from './IFromBuilder';
|
|
|
9
12
|
import { ISetBuilder } from './ISetBuilder';
|
|
10
13
|
import { ISubtractBuilder } from './ISubtractBuilder';
|
|
11
14
|
import { SetBuilder } from './SetBuilder';
|
|
15
|
+
import { SubtractBuilder } from './SubtractBuilder';
|
|
12
16
|
|
|
13
17
|
/**
|
|
14
18
|
* Accumulated property mapping for a from clause.
|
|
@@ -17,6 +21,7 @@ export interface FromEntry {
|
|
|
17
21
|
properties: Record<string, string>;
|
|
18
22
|
key: string;
|
|
19
23
|
parentKey: string;
|
|
24
|
+
children: ChildAdditionEntry[];
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
/**
|
|
@@ -28,7 +33,8 @@ export class FromBuilder<TReadModel, TEvent> implements IFromBuilder<TReadModel,
|
|
|
28
33
|
readonly entry: FromEntry = {
|
|
29
34
|
properties: {},
|
|
30
35
|
key: '$eventSourceId',
|
|
31
|
-
parentKey: ''
|
|
36
|
+
parentKey: '',
|
|
37
|
+
children: []
|
|
32
38
|
};
|
|
33
39
|
|
|
34
40
|
/** @inheritdoc */
|
|
@@ -75,13 +81,19 @@ export class FromBuilder<TReadModel, TEvent> implements IFromBuilder<TReadModel,
|
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
/** @inheritdoc */
|
|
78
|
-
usingCompositeKey<TKeyType>(
|
|
79
|
-
|
|
84
|
+
usingCompositeKey<TKeyType>(builderCallback: (builder: ICompositeKeyBuilder<TKeyType, TEvent>) => void): this {
|
|
85
|
+
const compositeKeyBuilder = new CompositeKeyBuilder<TKeyType, TEvent>();
|
|
86
|
+
builderCallback(compositeKeyBuilder);
|
|
87
|
+
this.entry.key = compositeKeyBuilder.build();
|
|
88
|
+
return this;
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
/** @inheritdoc */
|
|
83
|
-
usingParentCompositeKey<TKeyType>(
|
|
84
|
-
|
|
92
|
+
usingParentCompositeKey<TKeyType>(builderCallback: (builder: ICompositeKeyBuilder<TKeyType, TEvent>) => void): this {
|
|
93
|
+
const compositeKeyBuilder = new CompositeKeyBuilder<TKeyType, TEvent>();
|
|
94
|
+
builderCallback(compositeKeyBuilder);
|
|
95
|
+
this.entry.parentKey = compositeKeyBuilder.build();
|
|
96
|
+
return this;
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
/** @inheritdoc */
|
|
@@ -115,30 +127,63 @@ export class FromBuilder<TReadModel, TEvent> implements IFromBuilder<TReadModel,
|
|
|
115
127
|
}
|
|
116
128
|
|
|
117
129
|
/** @inheritdoc */
|
|
118
|
-
add(
|
|
119
|
-
|
|
130
|
+
add(readModelPropertyAccessor: PropertyAccessor<TReadModel>): IAddBuilder<TEvent, this> {
|
|
131
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
132
|
+
const proxy = new Proxy({}, handler);
|
|
133
|
+
readModelPropertyAccessor(proxy as TReadModel);
|
|
134
|
+
return new AddBuilder<TEvent, this>(
|
|
135
|
+
handler.property,
|
|
136
|
+
(property, expression) => { this.entry.properties[property] = expression; },
|
|
137
|
+
this
|
|
138
|
+
);
|
|
120
139
|
}
|
|
121
140
|
|
|
122
141
|
/** @inheritdoc */
|
|
123
|
-
subtract(
|
|
124
|
-
|
|
142
|
+
subtract(readModelPropertyAccessor: PropertyAccessor<TReadModel>): ISubtractBuilder<TEvent, this> {
|
|
143
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
144
|
+
const proxy = new Proxy({}, handler);
|
|
145
|
+
readModelPropertyAccessor(proxy as TReadModel);
|
|
146
|
+
return new SubtractBuilder<TEvent, this>(
|
|
147
|
+
handler.property,
|
|
148
|
+
(property, expression) => { this.entry.properties[property] = expression; },
|
|
149
|
+
this
|
|
150
|
+
);
|
|
125
151
|
}
|
|
126
152
|
|
|
127
153
|
/** @inheritdoc */
|
|
128
|
-
count(
|
|
129
|
-
|
|
154
|
+
count(readModelPropertyAccessor: PropertyAccessor<TReadModel>): this {
|
|
155
|
+
const handler = new PropertyPathResolverProxyHandler();
|
|
156
|
+
const proxy = new Proxy({}, handler);
|
|
157
|
+
readModelPropertyAccessor(proxy as TReadModel);
|
|
158
|
+
this.entry.properties[handler.property] = '$count';
|
|
159
|
+
return this;
|
|
130
160
|
}
|
|
131
161
|
|
|
132
162
|
/** @inheritdoc */
|
|
133
163
|
addChild<TChildModel>(
|
|
134
|
-
|
|
135
|
-
|
|
164
|
+
targetPropertyAccessor: PropertyAccessor<TReadModel>,
|
|
165
|
+
eventPropertyAccessorOrBuilderCallback: PropertyAccessor<TEvent> | ((builder: IAddChildBuilder<TChildModel, TEvent>) => void)
|
|
136
166
|
): this {
|
|
137
|
-
|
|
167
|
+
const targetHandler = new PropertyPathResolverProxyHandler();
|
|
168
|
+
const targetProxy = new Proxy({}, targetHandler);
|
|
169
|
+
targetPropertyAccessor(targetProxy as TReadModel);
|
|
170
|
+
|
|
171
|
+
const probe = new AddChildBuilder<TChildModel, TEvent>();
|
|
172
|
+
const probeProxy = new Proxy({}, probe);
|
|
173
|
+
(eventPropertyAccessorOrBuilderCallback as (value: unknown) => void)(probeProxy);
|
|
174
|
+
|
|
175
|
+
this.entry.children.push(probe.usedAsBuilder
|
|
176
|
+
? { targetProperty: targetHandler.property, identifiedBy: probe.identifiedByProperty, usingKey: probe.usingKeyProperty }
|
|
177
|
+
: { targetProperty: targetHandler.property, fromEventProperty: probe.capturedEventProperty });
|
|
178
|
+
return this;
|
|
138
179
|
}
|
|
139
180
|
|
|
140
181
|
/** @inheritdoc */
|
|
141
182
|
setThisValue(): ISetBuilder<TEvent, this> {
|
|
142
|
-
|
|
183
|
+
return new SetBuilder<TEvent, this>(
|
|
184
|
+
'$this',
|
|
185
|
+
(rp, expr) => { this.entry.properties[rp] = expr; },
|
|
186
|
+
this
|
|
187
|
+
);
|
|
143
188
|
}
|
|
144
189
|
}
|
|
@@ -19,4 +19,10 @@ export interface ICompositeKeyBuilder<TKeyType, TEvent> {
|
|
|
19
19
|
targetPropertyAccessor: PropertyAccessor<TKeyType>,
|
|
20
20
|
sourcePropertyAccessor: PropertyAccessor<TEvent>
|
|
21
21
|
): ICompositeKeyBuilder<TKeyType, TEvent>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Builds the composite key expression from the configured parts.
|
|
25
|
+
* @returns The `$composite(...)` property expression.
|
|
26
|
+
*/
|
|
27
|
+
build(): string;
|
|
22
28
|
}
|