@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.
Files changed (319) hide show
  1. package/EventStore.ts +17 -1
  2. package/IEventStore.ts +16 -0
  3. package/auditing/CausationType.ts +10 -0
  4. package/compliance/ComplianceContracts.ts +84 -0
  5. package/compliance/IPIIManager.ts +17 -0
  6. package/compliance/PIIManager.ts +31 -0
  7. package/compliance/index.ts +2 -0
  8. package/connection/ChronicleConnection.ts +7 -1
  9. package/connection/ChronicleServices.ts +2 -0
  10. package/connection/Guid.ts +18 -0
  11. package/dist/EventStore.d.ts +8 -0
  12. package/dist/EventStore.d.ts.map +1 -1
  13. package/dist/EventStore.js +13 -1
  14. package/dist/EventStore.js.map +1 -1
  15. package/dist/IEventStore.d.ts +12 -0
  16. package/dist/IEventStore.d.ts.map +1 -1
  17. package/dist/auditing/CausationType.d.ts +8 -0
  18. package/dist/auditing/CausationType.d.ts.map +1 -1
  19. package/dist/auditing/CausationType.js +8 -0
  20. package/dist/auditing/CausationType.js.map +1 -1
  21. package/dist/compliance/ComplianceContracts.d.ts +40 -0
  22. package/dist/compliance/ComplianceContracts.d.ts.map +1 -1
  23. package/dist/compliance/ComplianceContracts.js +71 -0
  24. package/dist/compliance/ComplianceContracts.js.map +1 -1
  25. package/dist/compliance/IPIIManager.d.ts +15 -0
  26. package/dist/compliance/IPIIManager.d.ts.map +1 -0
  27. package/dist/compliance/IPIIManager.js +4 -0
  28. package/dist/compliance/IPIIManager.js.map +1 -0
  29. package/dist/compliance/PIIManager.d.ts +20 -0
  30. package/dist/compliance/PIIManager.d.ts.map +1 -0
  31. package/dist/compliance/PIIManager.js +30 -0
  32. package/dist/compliance/PIIManager.js.map +1 -0
  33. package/dist/compliance/index.d.ts +2 -0
  34. package/dist/compliance/index.d.ts.map +1 -1
  35. package/dist/compliance/index.js +1 -0
  36. package/dist/compliance/index.js.map +1 -1
  37. package/dist/connection/ChronicleConnection.d.ts +1 -0
  38. package/dist/connection/ChronicleConnection.d.ts.map +1 -1
  39. package/dist/connection/ChronicleConnection.js +6 -1
  40. package/dist/connection/ChronicleConnection.js.map +1 -1
  41. package/dist/connection/ChronicleServices.d.ts +2 -0
  42. package/dist/connection/ChronicleServices.d.ts.map +1 -1
  43. package/dist/connection/Guid.d.ts +5 -0
  44. package/dist/connection/Guid.d.ts.map +1 -1
  45. package/dist/connection/Guid.js +15 -0
  46. package/dist/connection/Guid.js.map +1 -1
  47. package/dist/eventSequences/AppendOperationsBroadcaster.d.ts +16 -0
  48. package/dist/eventSequences/AppendOperationsBroadcaster.d.ts.map +1 -0
  49. package/dist/eventSequences/AppendOperationsBroadcaster.js +77 -0
  50. package/dist/eventSequences/AppendOperationsBroadcaster.js.map +1 -0
  51. package/dist/eventSequences/AppendOptions.d.ts +7 -0
  52. package/dist/eventSequences/AppendOptions.d.ts.map +1 -1
  53. package/dist/eventSequences/AppendResult.d.ts +14 -0
  54. package/dist/eventSequences/AppendResult.d.ts.map +1 -1
  55. package/dist/eventSequences/AppendedEventWithResult.d.ts +13 -0
  56. package/dist/eventSequences/AppendedEventWithResult.d.ts.map +1 -0
  57. package/dist/eventSequences/AppendedEventWithResult.js +4 -0
  58. package/dist/eventSequences/AppendedEventWithResult.js.map +1 -0
  59. package/dist/eventSequences/CompleteStreamError.d.ts +17 -0
  60. package/dist/eventSequences/CompleteStreamError.d.ts.map +1 -0
  61. package/dist/eventSequences/CompleteStreamError.js +20 -0
  62. package/dist/eventSequences/CompleteStreamError.js.map +1 -0
  63. package/dist/eventSequences/CompleteStreamResult.d.ts +14 -0
  64. package/dist/eventSequences/CompleteStreamResult.d.ts.map +1 -0
  65. package/dist/eventSequences/CompleteStreamResult.js +4 -0
  66. package/dist/eventSequences/CompleteStreamResult.js.map +1 -0
  67. package/dist/eventSequences/ConcurrencyViolation.d.ts +13 -0
  68. package/dist/eventSequences/ConcurrencyViolation.d.ts.map +1 -0
  69. package/dist/eventSequences/ConcurrencyViolation.js +4 -0
  70. package/dist/eventSequences/ConcurrencyViolation.js.map +1 -0
  71. package/dist/eventSequences/EventForEventSourceId.d.ts +8 -0
  72. package/dist/eventSequences/EventForEventSourceId.d.ts.map +1 -1
  73. package/dist/eventSequences/EventSequence.d.ts +35 -1
  74. package/dist/eventSequences/EventSequence.d.ts.map +1 -1
  75. package/dist/eventSequences/EventSequence.js +350 -19
  76. package/dist/eventSequences/EventSequence.js.map +1 -1
  77. package/dist/eventSequences/IEventSequence.d.ts +85 -1
  78. package/dist/eventSequences/IEventSequence.d.ts.map +1 -1
  79. package/dist/eventSequences/WaitForCompletionResult.d.ts +11 -0
  80. package/dist/eventSequences/WaitForCompletionResult.d.ts.map +1 -0
  81. package/dist/eventSequences/WaitForCompletionResult.js +4 -0
  82. package/dist/eventSequences/WaitForCompletionResult.js.map +1 -0
  83. package/dist/eventSequences/index.d.ts +5 -0
  84. package/dist/eventSequences/index.d.ts.map +1 -1
  85. package/dist/eventSequences/index.js +1 -0
  86. package/dist/eventSequences/index.js.map +1 -1
  87. package/dist/eventStoreSubscriptions/EventStoreSubscriptions.d.ts +3 -0
  88. package/dist/eventStoreSubscriptions/EventStoreSubscriptions.d.ts.map +1 -1
  89. package/dist/eventStoreSubscriptions/EventStoreSubscriptions.js +9 -0
  90. package/dist/eventStoreSubscriptions/EventStoreSubscriptions.js.map +1 -1
  91. package/dist/eventStoreSubscriptions/IEventStoreSubscriptions.d.ts +6 -0
  92. package/dist/eventStoreSubscriptions/IEventStoreSubscriptions.d.ts.map +1 -1
  93. package/dist/eventStoreSubscriptions/contracts.d.ts +18 -0
  94. package/dist/eventStoreSubscriptions/contracts.d.ts.map +1 -1
  95. package/dist/eventStoreSubscriptions/contracts.js +106 -0
  96. package/dist/eventStoreSubscriptions/contracts.js.map +1 -1
  97. package/dist/events/constraints/Constraints.js +1 -1
  98. package/dist/events/constraints/Constraints.js.map +1 -1
  99. package/dist/externalServices/ExternalServiceBuilder.d.ts +42 -0
  100. package/dist/externalServices/ExternalServiceBuilder.d.ts.map +1 -0
  101. package/dist/externalServices/ExternalServiceBuilder.js +110 -0
  102. package/dist/externalServices/ExternalServiceBuilder.js.map +1 -0
  103. package/dist/externalServices/ExternalServices.d.ts +19 -0
  104. package/dist/externalServices/ExternalServices.d.ts.map +1 -0
  105. package/dist/externalServices/ExternalServices.js +30 -0
  106. package/dist/externalServices/ExternalServices.js.map +1 -0
  107. package/dist/externalServices/ExternalServicesContracts.d.ts +137 -0
  108. package/dist/externalServices/ExternalServicesContracts.d.ts.map +1 -0
  109. package/dist/externalServices/ExternalServicesContracts.js +654 -0
  110. package/dist/externalServices/ExternalServicesContracts.js.map +1 -0
  111. package/dist/externalServices/IExternalServiceBuilder.d.ts +67 -0
  112. package/dist/externalServices/IExternalServiceBuilder.d.ts.map +1 -0
  113. package/dist/externalServices/IExternalServiceBuilder.js +4 -0
  114. package/dist/externalServices/IExternalServiceBuilder.js.map +1 -0
  115. package/dist/externalServices/IExternalServices.d.ts +13 -0
  116. package/dist/externalServices/IExternalServices.d.ts.map +1 -0
  117. package/dist/externalServices/IExternalServices.js +4 -0
  118. package/dist/externalServices/IExternalServices.js.map +1 -0
  119. package/dist/externalServices/index.d.ts +5 -0
  120. package/dist/externalServices/index.d.ts.map +1 -0
  121. package/dist/externalServices/index.js +5 -0
  122. package/dist/externalServices/index.js.map +1 -0
  123. package/dist/identities/IIdentityManager.d.ts +17 -0
  124. package/dist/identities/IIdentityManager.d.ts.map +1 -0
  125. package/dist/identities/IIdentityManager.js +4 -0
  126. package/dist/identities/IIdentityManager.js.map +1 -0
  127. package/dist/identities/IdentityManager.d.ts +20 -0
  128. package/dist/identities/IdentityManager.d.ts.map +1 -0
  129. package/dist/identities/IdentityManager.js +31 -0
  130. package/dist/identities/IdentityManager.js.map +1 -0
  131. package/dist/identities/index.d.ts +3 -0
  132. package/dist/identities/index.d.ts.map +1 -0
  133. package/dist/identities/index.js +4 -0
  134. package/dist/identities/index.js.map +1 -0
  135. package/dist/index.d.ts +5 -1
  136. package/dist/index.d.ts.map +1 -1
  137. package/dist/index.js +5 -1
  138. package/dist/index.js.map +1 -1
  139. package/dist/observation/FailedPartition.d.ts +15 -0
  140. package/dist/observation/FailedPartition.d.ts.map +1 -0
  141. package/dist/observation/FailedPartition.js +4 -0
  142. package/dist/observation/FailedPartition.js.map +1 -0
  143. package/dist/observation/FailedPartitionAttempt.d.ts +15 -0
  144. package/dist/observation/FailedPartitionAttempt.d.ts.map +1 -0
  145. package/dist/observation/FailedPartitionAttempt.js +4 -0
  146. package/dist/observation/FailedPartitionAttempt.js.map +1 -0
  147. package/dist/observation/FailedPartitions.d.ts +24 -0
  148. package/dist/observation/FailedPartitions.d.ts.map +1 -0
  149. package/dist/observation/FailedPartitions.js +39 -0
  150. package/dist/observation/FailedPartitions.js.map +1 -0
  151. package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.d.ts +19 -0
  152. package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.d.ts.map +1 -0
  153. package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.js +4 -0
  154. package/dist/observation/ICanBeNotifiedWhenPartitionReplayed.js.map +1 -0
  155. package/dist/observation/ICanBeNotifiedWhenReplay.d.ts +17 -0
  156. package/dist/observation/ICanBeNotifiedWhenReplay.d.ts.map +1 -0
  157. package/dist/observation/ICanBeNotifiedWhenReplay.js +4 -0
  158. package/dist/observation/ICanBeNotifiedWhenReplay.js.map +1 -0
  159. package/dist/observation/IFailedPartitions.d.ts +18 -0
  160. package/dist/observation/IFailedPartitions.d.ts.map +1 -0
  161. package/dist/observation/IFailedPartitions.js +4 -0
  162. package/dist/observation/IFailedPartitions.js.map +1 -0
  163. package/dist/observation/index.d.ts +6 -0
  164. package/dist/observation/index.d.ts.map +1 -1
  165. package/dist/observation/index.js +1 -0
  166. package/dist/observation/index.js.map +1 -1
  167. package/dist/observation/notifyReplayLifecycle.d.ts +13 -0
  168. package/dist/observation/notifyReplayLifecycle.d.ts.map +1 -0
  169. package/dist/observation/notifyReplayLifecycle.js +54 -0
  170. package/dist/observation/notifyReplayLifecycle.js.map +1 -0
  171. package/dist/observation/toClientFailedPartition.d.ts +9 -0
  172. package/dist/observation/toClientFailedPartition.d.ts.map +1 -0
  173. package/dist/observation/toClientFailedPartition.js +23 -0
  174. package/dist/observation/toClientFailedPartition.js.map +1 -0
  175. package/dist/projections/Projections.d.ts +0 -4
  176. package/dist/projections/Projections.d.ts.map +1 -1
  177. package/dist/projections/Projections.js +25 -103
  178. package/dist/projections/Projections.js.map +1 -1
  179. package/dist/projections/declarative/AddBuilder.d.ts +17 -0
  180. package/dist/projections/declarative/AddBuilder.d.ts.map +1 -0
  181. package/dist/projections/declarative/AddBuilder.js +28 -0
  182. package/dist/projections/declarative/AddBuilder.js.map +1 -0
  183. package/dist/projections/declarative/AddChildBuilder.d.ts +56 -0
  184. package/dist/projections/declarative/AddChildBuilder.d.ts.map +1 -0
  185. package/dist/projections/declarative/AddChildBuilder.js +72 -0
  186. package/dist/projections/declarative/AddChildBuilder.js.map +1 -0
  187. package/dist/projections/declarative/ChildrenBuilder.d.ts +28 -0
  188. package/dist/projections/declarative/ChildrenBuilder.d.ts.map +1 -0
  189. package/dist/projections/declarative/ChildrenBuilder.js +72 -0
  190. package/dist/projections/declarative/ChildrenBuilder.js.map +1 -0
  191. package/dist/projections/declarative/CompositeKeyBuilder.d.ts +16 -0
  192. package/dist/projections/declarative/CompositeKeyBuilder.d.ts.map +1 -0
  193. package/dist/projections/declarative/CompositeKeyBuilder.js +29 -0
  194. package/dist/projections/declarative/CompositeKeyBuilder.js.map +1 -0
  195. package/dist/projections/declarative/FromBuilder.d.ts +8 -6
  196. package/dist/projections/declarative/FromBuilder.d.ts.map +1 -1
  197. package/dist/projections/declarative/FromBuilder.js +44 -14
  198. package/dist/projections/declarative/FromBuilder.js.map +1 -1
  199. package/dist/projections/declarative/ICompositeKeyBuilder.d.ts +5 -0
  200. package/dist/projections/declarative/ICompositeKeyBuilder.d.ts.map +1 -1
  201. package/dist/projections/declarative/JoinBuilder.d.ts +7 -5
  202. package/dist/projections/declarative/JoinBuilder.d.ts.map +1 -1
  203. package/dist/projections/declarative/JoinBuilder.js +50 -16
  204. package/dist/projections/declarative/JoinBuilder.js.map +1 -1
  205. package/dist/projections/declarative/NestedBuilder.d.ts +24 -0
  206. package/dist/projections/declarative/NestedBuilder.d.ts.map +1 -0
  207. package/dist/projections/declarative/NestedBuilder.js +60 -0
  208. package/dist/projections/declarative/NestedBuilder.js.map +1 -0
  209. package/dist/projections/declarative/ProjectionBuilderCore.d.ts +127 -0
  210. package/dist/projections/declarative/ProjectionBuilderCore.d.ts.map +1 -0
  211. package/dist/projections/declarative/ProjectionBuilderCore.js +180 -0
  212. package/dist/projections/declarative/ProjectionBuilderCore.js.map +1 -0
  213. package/dist/projections/declarative/ProjectionBuilderFor.d.ts +6 -32
  214. package/dist/projections/declarative/ProjectionBuilderFor.d.ts.map +1 -1
  215. package/dist/projections/declarative/ProjectionBuilderFor.js +24 -118
  216. package/dist/projections/declarative/ProjectionBuilderFor.js.map +1 -1
  217. package/dist/projections/declarative/SubtractBuilder.d.ts +17 -0
  218. package/dist/projections/declarative/SubtractBuilder.d.ts.map +1 -0
  219. package/dist/projections/declarative/SubtractBuilder.js +28 -0
  220. package/dist/projections/declarative/SubtractBuilder.js.map +1 -0
  221. package/dist/projections/declarative/index.d.ts +9 -0
  222. package/dist/projections/declarative/index.d.ts.map +1 -1
  223. package/dist/projections/declarative/index.js +8 -0
  224. package/dist/projections/declarative/index.js.map +1 -1
  225. package/dist/projections/modelBound/childrenAndNestedBuilder.d.ts +90 -0
  226. package/dist/projections/modelBound/childrenAndNestedBuilder.d.ts.map +1 -0
  227. package/dist/projections/modelBound/childrenAndNestedBuilder.js +290 -0
  228. package/dist/projections/modelBound/childrenAndNestedBuilder.js.map +1 -0
  229. package/dist/reactors/ReactorSideEffects.d.ts +29 -0
  230. package/dist/reactors/ReactorSideEffects.d.ts.map +1 -0
  231. package/dist/reactors/ReactorSideEffects.js +70 -0
  232. package/dist/reactors/ReactorSideEffects.js.map +1 -0
  233. package/dist/reactors/Reactors.d.ts +4 -1
  234. package/dist/reactors/Reactors.d.ts.map +1 -1
  235. package/dist/reactors/Reactors.js +23 -4
  236. package/dist/reactors/Reactors.js.map +1 -1
  237. package/dist/reducers/Reducers.d.ts.map +1 -1
  238. package/dist/reducers/Reducers.js +15 -3
  239. package/dist/reducers/Reducers.js.map +1 -1
  240. package/dist/reducers/reducer.d.ts +9 -1
  241. package/dist/reducers/reducer.d.ts.map +1 -1
  242. package/dist/reducers/reducer.js +4 -2
  243. package/dist/reducers/reducer.js.map +1 -1
  244. package/dist/transactions/IUnitOfWork.d.ts +18 -0
  245. package/dist/transactions/IUnitOfWork.d.ts.map +1 -1
  246. package/dist/transactions/UnitOfWork.d.ts +9 -0
  247. package/dist/transactions/UnitOfWork.d.ts.map +1 -1
  248. package/dist/transactions/UnitOfWork.js +14 -0
  249. package/dist/transactions/UnitOfWork.js.map +1 -1
  250. package/dist/tsconfig.tsbuildinfo +1 -1
  251. package/eventSequences/AppendOperationsBroadcaster.ts +83 -0
  252. package/eventSequences/AppendOptions.ts +8 -0
  253. package/eventSequences/AppendResult.ts +16 -0
  254. package/eventSequences/AppendedEventWithResult.ts +17 -0
  255. package/eventSequences/CompleteStreamError.ts +20 -0
  256. package/eventSequences/CompleteStreamResult.ts +13 -0
  257. package/eventSequences/ConcurrencyViolation.ts +18 -0
  258. package/eventSequences/EventForEventSourceId.ts +12 -0
  259. package/eventSequences/EventSequence.spec.ts +588 -0
  260. package/eventSequences/EventSequence.ts +406 -20
  261. package/eventSequences/IEventSequence.ts +109 -1
  262. package/eventSequences/WaitForCompletionResult.ts +15 -0
  263. package/eventSequences/index.ts +5 -0
  264. package/eventStoreSubscriptions/EventStoreSubscriptions.spec.ts +52 -0
  265. package/eventStoreSubscriptions/EventStoreSubscriptions.ts +19 -1
  266. package/eventStoreSubscriptions/IEventStoreSubscriptions.ts +7 -0
  267. package/eventStoreSubscriptions/contracts.ts +126 -0
  268. package/events/constraints/Constraints.ts +1 -1
  269. package/externalServices/ExternalServiceBuilder.ts +128 -0
  270. package/externalServices/ExternalServices.ts +34 -0
  271. package/externalServices/ExternalServicesContracts.ts +709 -0
  272. package/externalServices/IExternalServiceBuilder.ts +76 -0
  273. package/externalServices/IExternalServices.ts +16 -0
  274. package/externalServices/index.ts +7 -0
  275. package/identities/IIdentityManager.ts +19 -0
  276. package/identities/IdentityManager.ts +32 -0
  277. package/identities/index.ts +5 -0
  278. package/index.ts +6 -0
  279. package/observation/FailedPartition.ts +21 -0
  280. package/observation/FailedPartitionAttempt.ts +21 -0
  281. package/observation/FailedPartitions.spec.ts +75 -0
  282. package/observation/FailedPartitions.ts +44 -0
  283. package/observation/ICanBeNotifiedWhenPartitionReplayed.ts +22 -0
  284. package/observation/ICanBeNotifiedWhenReplay.ts +20 -0
  285. package/observation/IFailedPartitions.ts +22 -0
  286. package/observation/index.ts +6 -0
  287. package/observation/notifyReplayLifecycle.spec.ts +98 -0
  288. package/observation/notifyReplayLifecycle.ts +61 -0
  289. package/observation/toClientFailedPartition.ts +26 -0
  290. package/package.json +12 -2
  291. package/projections/Projections.childrenAndNested.spec.ts +188 -0
  292. package/projections/Projections.spec.ts +131 -0
  293. package/projections/Projections.ts +37 -119
  294. package/projections/declarative/AddBuilder.ts +28 -0
  295. package/projections/declarative/AddChildBuilder.ts +97 -0
  296. package/projections/declarative/ChildrenBuilder.spec.ts +157 -0
  297. package/projections/declarative/ChildrenBuilder.ts +90 -0
  298. package/projections/declarative/CompositeKeyBuilder.spec.ts +117 -0
  299. package/projections/declarative/CompositeKeyBuilder.ts +38 -0
  300. package/projections/declarative/FromBuilder.ts +60 -15
  301. package/projections/declarative/ICompositeKeyBuilder.ts +6 -0
  302. package/projections/declarative/JoinBuilder.ts +66 -17
  303. package/projections/declarative/NestedBuilder.ts +76 -0
  304. package/projections/declarative/ProjectionBuilderCore.ts +257 -0
  305. package/projections/declarative/ProjectionBuilderFor.spec.ts +115 -0
  306. package/projections/declarative/ProjectionBuilderFor.ts +29 -168
  307. package/projections/declarative/SubtractBuilder.ts +28 -0
  308. package/projections/declarative/index.ts +9 -0
  309. package/projections/modelBound/childrenAndNestedBuilder.ts +354 -0
  310. package/reactors/ReactorSideEffects.spec.ts +182 -0
  311. package/reactors/ReactorSideEffects.ts +97 -0
  312. package/reactors/Reactors.ts +29 -4
  313. package/reducers/Reducers.spec.ts +87 -0
  314. package/reducers/Reducers.ts +15 -3
  315. package/reducers/reducer.spec.ts +40 -0
  316. package/reducers/reducer.ts +11 -2
  317. package/transactions/IUnitOfWork.ts +21 -0
  318. package/transactions/UnitOfWork.spec.ts +82 -0
  319. 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>(_builderCallback: (builder: ICompositeKeyBuilder<TKeyType, TEvent>) => void): this {
79
- throw new Error('usingCompositeKey is not implemented yet.');
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>(_builderCallback: (builder: ICompositeKeyBuilder<TKeyType, TEvent>) => void): this {
84
- throw new Error('usingParentCompositeKey is not implemented yet.');
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(_readModelPropertyAccessor: PropertyAccessor<TReadModel>): IAddBuilder<TEvent, this> {
119
- throw new Error('add is not implemented yet.');
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(_readModelPropertyAccessor: PropertyAccessor<TReadModel>): ISubtractBuilder<TEvent, this> {
124
- throw new Error('subtract is not implemented yet.');
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(_readModelPropertyAccessor: PropertyAccessor<TReadModel>): this {
129
- throw new Error('count is not implemented yet.');
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
- _targetPropertyAccessor: PropertyAccessor<TReadModel>,
135
- _eventPropertyAccessorOrBuilderCallback: PropertyAccessor<TEvent> | ((builder: IAddChildBuilder<TChildModel, TEvent>) => void)
164
+ targetPropertyAccessor: PropertyAccessor<TReadModel>,
165
+ eventPropertyAccessorOrBuilderCallback: PropertyAccessor<TEvent> | ((builder: IAddChildBuilder<TChildModel, TEvent>) => void)
136
166
  ): this {
137
- throw new Error('addChild is not implemented yet.');
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
- throw new Error('setThisValue is not implemented yet.');
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
  }