@reventlessdev/reventless-aws 3.0.0-alpha.343 → 3.0.0-alpha.345

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 (234) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +11 -11
  3. package/scripts/ProvisionIdentity.res +8 -3
  4. package/src/Platform.res +327 -328
  5. package/src/Platform.res.mjs +4 -2
  6. package/src/Platform_Casts.res +13 -4
  7. package/src/adapter/Api/AppSyncEventsSigner_Ops.res +8 -4
  8. package/src/adapter/Api/AppSync_EventsApi.res +12 -14
  9. package/src/adapter/Api/AppSync_Resolver_Native.res +3 -4
  10. package/src/adapter/Api/AppSync_Resolver_Retrying.res +78 -70
  11. package/src/adapter/Api/AppSync_SourceApiAssociation_Retrying.res +11 -8
  12. package/src/adapter/Api/Platform_AdminScan_Ops.res +15 -14
  13. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +10 -2
  14. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +40 -50
  15. package/src/adapter/Api/Platform_UIFragments_Lambda.res +39 -32
  16. package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res +5 -2
  17. package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res +0 -1
  18. package/src/adapter/Auth/Auth_ActiveRoleStore.res +1 -2
  19. package/src/adapter/Auth/Auth_ActiveRoleStore_Schema.res +1 -4
  20. package/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res +5 -2
  21. package/src/adapter/Auth/Auth_Cognito.res +3 -9
  22. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res +1 -4
  23. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_NoOp.res +3 -1
  24. package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res +1 -4
  25. package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +7 -4
  26. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +6 -1
  27. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +7 -4
  28. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res +24 -18
  29. package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +9 -4
  30. package/src/adapter/CommandTopic/CommandTopicRegistry.res +1 -4
  31. package/src/adapter/Counter/CounterHandler_DynamoDbStream.res +15 -15
  32. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res +9 -5
  33. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +179 -213
  34. package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res +5 -5
  35. package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res +6 -2
  36. package/src/adapter/EventCollector/EventCollectorChannel_SQS.res +14 -7
  37. package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res +14 -7
  38. package/src/adapter/EventCollector/EventCollectorChannel_SQS_Runtime.res +6 -3
  39. package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res +6 -1
  40. package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res +13 -17
  41. package/src/adapter/EventLog/EventLogStorage_Postgres.res +7 -4
  42. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +12 -7
  43. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res +4 -2
  44. package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res +3 -2
  45. package/src/adapter/EventTopic/EventTopicPublisher_SNS.res +20 -12
  46. package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res +21 -9
  47. package/src/adapter/EventTopic/EventTopicPublisher_SNS_Runtime.res +5 -3
  48. package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res +6 -3
  49. package/src/adapter/Mcp/MCP_Lambda.res +31 -46
  50. package/src/adapter/Messaging/Messaging_Ses_Backend.res +11 -7
  51. package/src/adapter/Messaging/Messaging_Ses_Backend.res.mjs +2 -4
  52. package/src/adapter/Monitoring/Monitoring_CloudWatch.res +16 -16
  53. package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res +5 -10
  54. package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res +4 -2
  55. package/src/adapter/Postgres/PgConnection.res +6 -5
  56. package/src/adapter/Postgres/PgMigration_Builder.res +4 -8
  57. package/src/adapter/Postgres/PgRuntime.res +4 -7
  58. package/src/adapter/QueryDb/PgQueryResolver_Builder.res +9 -11
  59. package/src/adapter/QueryDb/PgQueryResolver_Lambda.res +22 -21
  60. package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +114 -111
  61. package/src/adapter/QueryDb/QueryDbResolvers_Lambda.res +1 -7
  62. package/src/adapter/QueryDb/QueryDbStorage.res +4 -2
  63. package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res +23 -24
  64. package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res +8 -2
  65. package/src/adapter/QueryDb/QueryDbStorage_DynamoDb_Runtime.res +71 -73
  66. package/src/adapter/QueryDb/QueryDbStorage_Postgres.res +5 -2
  67. package/src/adapter/QueryDb/QueryInterceptor_Provisioning.res +1 -4
  68. package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res +8 -2
  69. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +73 -81
  70. package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +72 -78
  71. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +44 -67
  72. package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res +44 -67
  73. package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +53 -82
  74. package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res +47 -77
  75. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +18 -11
  76. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +80 -97
  77. package/src/adapter/Runtime/CounterEntryPoint_Ops.res +2 -7
  78. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +16 -10
  79. package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +24 -15
  80. package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +17 -37
  81. package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +31 -57
  82. package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res +18 -24
  83. package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +1 -5
  84. package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +4 -3
  85. package/src/adapter/Runtime/HeartbeatEntryPoint.res +0 -1
  86. package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res +4 -2
  87. package/src/adapter/Runtime/PgMigrationEntryPoint.res +0 -1
  88. package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +3 -2
  89. package/src/adapter/Runtime/PluginExtensionPointEntryPoint.res +1 -2
  90. package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +4 -5
  91. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +22 -10
  92. package/src/adapter/Runtime/RuntimeExtensionEntryPoint_Ops.res +8 -2
  93. package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res +14 -31
  94. package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +16 -17
  95. package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +10 -9
  96. package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res +46 -52
  97. package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res +36 -41
  98. package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +31 -37
  99. package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res +6 -7
  100. package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res +4 -6
  101. package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents_Runtime.res +2 -6
  102. package/src/adapter/StateTopic/StateTopic_AppSync.res +21 -16
  103. package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res +36 -32
  104. package/src/adapter/Task/TaskBucket_S3.res +6 -1
  105. package/src/adapter/Upload/Upload_Claim_S3.res +17 -20
  106. package/src/adapter/Upload/Upload_Claim_S3_Ops.res +5 -2
  107. package/src/adapter/Upload/Upload_Presign_S3.res +51 -49
  108. package/src/capability/Capability_Geocoding_AwsLocation.res +4 -1
  109. package/src/capability/Capability_Messaging.res +4 -5
  110. package/src/capability/Capability_Messaging_Ses.res +3 -1
  111. package/src/capability/Capability_ObjectStore_S3.res +1 -7
  112. package/src/components/Api/AppSync_Adapter.res +28 -41
  113. package/src/components/Api/AppSync_SdlDecorate.res +38 -30
  114. package/src/components/AutomationSlice_Builder.res +6 -4
  115. package/src/components/ExtensionPoint_Builder.res +9 -10
  116. package/src/components/InboundTranslationSlice_Builder.res +7 -8
  117. package/src/components/OutboundTranslationSlice_Builder.res +14 -8
  118. package/src/components/OutboundTranslationSlice_Builder.res.mjs +1 -1
  119. package/src/components/SideEffectHandler_Single.res +4 -4
  120. package/src/components/StateViewSlice_Builder.res +6 -4
  121. package/src/components/StateViewSlice_Builder_Stream.res +6 -4
  122. package/src/components/Task_Builder_PerBucket.res +10 -11
  123. package/src/plugin/cloner/ClonerRunner_Fargate.res +3 -10
  124. package/src/plugin/cloner/ClonerRunner_Fargate_Runtime.res +1 -4
  125. package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res +5 -5
  126. package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +19 -21
  127. package/src/plugin/runtime/PluginRuntime_Builder.res +167 -188
  128. package/src/plugin/runtime/Util_PluginMessage_Runtime.res +6 -5
  129. package/src/plugin/stack/Plugin_Stack.res +104 -103
  130. package/src/util/Util_AlarmSpec.res +2 -1
  131. package/src/util/Util_AppSync.res +8 -2
  132. package/src/util/Util_AppSync_Caller.res +15 -14
  133. package/src/util/Util_Bundle.res +144 -67
  134. package/src/util/Util_Bundle.res.mjs +64 -13
  135. package/src/util/Util_CognitoGroupUser_Runtime.res +32 -34
  136. package/src/util/Util_Cognito_Runtime.res +11 -7
  137. package/src/util/Util_DeadLetterQueue.res +12 -2
  138. package/src/util/Util_DynamoDb.res +5 -3
  139. package/src/util/Util_DynamoDbStream.res +7 -3
  140. package/src/util/Util_DynamoDbStream_Runtime.res +1 -2
  141. package/src/util/Util_DynamoDb_Runtime.res +23 -41
  142. package/src/util/Util_HostUiDomain.res +6 -1
  143. package/src/util/Util_Kinesis_Runtime.res +10 -11
  144. package/src/util/Util_Lambda.res +12 -5
  145. package/src/util/Util_LambdaEnvBudget.res +5 -5
  146. package/src/util/Util_LambdaLogging.res +1 -2
  147. package/src/util/Util_LogGroup_Adopting.res +1 -4
  148. package/src/util/Util_ResourceNaming.res +1 -2
  149. package/src/util/Util_SNS.res +8 -3
  150. package/src/util/Util_SNS_FIFO.res +1 -1
  151. package/src/util/Util_SNS_Runtime.res +11 -10
  152. package/src/util/Util_SQS.res +4 -2
  153. package/src/util/Util_SQS_FIFO.res +5 -2
  154. package/src/util/Util_SQS_Runtime.res +37 -36
  155. package/src/util/Util_ShellConfig.res +3 -2
  156. package/src/util/Util_StaticBundle.res +1 -3
  157. package/src/util/Util_StoreLayout.res +4 -1
  158. package/tests/AWS_TagsTest.res +16 -5
  159. package/tests/AppSyncEventsSigner_OpsTest.res +11 -2
  160. package/tests/AppSync_AdapterTest.res +203 -224
  161. package/tests/AppSync_Resolver_RetryingTest.res +64 -44
  162. package/tests/AppSync_RetirementNarrowingTest.res +59 -46
  163. package/tests/AppSync_SdlDecorateTest.res +22 -20
  164. package/tests/AppSync_SourceApiAssociation_RetryingTest.res +40 -22
  165. package/tests/Auth_ActiveRolePoolAttachmentTest.res +114 -107
  166. package/tests/Auth_ActiveRoleStoreTest.res +12 -9
  167. package/tests/Auth_ActiveRoleStore_SchemaTest.res +2 -1
  168. package/tests/Auth_ActiveRoleTrigger_OpsTest.res +20 -16
  169. package/tests/Auth_CognitoTest.res +31 -46
  170. package/tests/AutomationSliceEntryPoint_OpsTest.res +69 -67
  171. package/tests/BakeConvergenceTest.res +22 -25
  172. package/tests/Capability_MessagingTest.res +28 -12
  173. package/tests/CommandTopicQueuePolicyTest.res +1 -2
  174. package/tests/CounterEntryPoint_OpsTest.res +3 -7
  175. package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +306 -210
  176. package/tests/EventCollectorConnectLambdaPreviewTest.res +14 -7
  177. package/tests/EventCollectorEntryPoint_OpsTest.res +12 -4
  178. package/tests/EventCollectorPluginDefinitionAssetTest.res +18 -11
  179. package/tests/EventCollectorReadyGateTest.res +5 -4
  180. package/tests/EventLogStorage_DynamoDb_RuntimeTest.res +1 -2
  181. package/tests/EventMapperEntryPoint_OpsTest.res +1 -3
  182. package/tests/ExtensionPointEntryPoint_OpsTest.res +1 -4
  183. package/tests/HandlerFactoryDispatchTest.res +97 -70
  184. package/tests/MCP_LambdaTest.res +16 -27
  185. package/tests/PgChangeFeedRelay_IntegrationTest.res +123 -93
  186. package/tests/PgChangeFeedRelay_RuntimeTest.res +13 -10
  187. package/tests/PgMigrationEntryPoint_IntegrationTest.res +0 -1
  188. package/tests/PgPipeline_IntegrationTest.res +80 -66
  189. package/tests/PgQueryDbUnion_IntegrationTest.res +1 -2
  190. package/tests/PgQueryResolverEntryPoint_OpsTest.res +2 -6
  191. package/tests/PgQueryResolver_LambdaTest.res +41 -24
  192. package/tests/Platform_AdminScan_OpsTest.res +4 -1
  193. package/tests/Platform_ComponentDefinitions_Lambda_OpsTest.res +137 -129
  194. package/tests/ProjectionEntryPoint_DisplayNameTest.res +7 -3
  195. package/tests/ProjectionEntryPoint_UnionStampTest.res +3 -2
  196. package/tests/ProvisionIdentityTest.res +2 -6
  197. package/tests/QueryDbOwnerIndexTableTest.res +6 -4
  198. package/tests/QueryDbResolvers_AppSyncTest.res +23 -16
  199. package/tests/QueryInterceptor_LambdaTest.res +11 -13
  200. package/tests/ReadModelEntryPoint_OpsTest.res +43 -41
  201. package/tests/RuntimeExtensionEntryPoint_OpsTest.res +4 -3
  202. package/tests/SideEffectEntryPoint_OpsTest.res +23 -18
  203. package/tests/StateChangeDescriptorParityTest.res +28 -26
  204. package/tests/StateTopicKeySchemaTest.res +18 -15
  205. package/tests/StateViewSliceEntryPoint_OpsTest.res +55 -44
  206. package/tests/TaskBucketEntryPoint_OpsTest.res +13 -13
  207. package/tests/Upload_ClaimTest.res +3 -3
  208. package/tests/Util_AwsErrorTest.res +4 -7
  209. package/tests/Util_BundleDependencyClosureTest.res +41 -3
  210. package/tests/Util_BundleDependencyClosureTest.res.mjs +11 -0
  211. package/tests/Util_BundleEsmLoaderTest.res +3 -3
  212. package/tests/Util_BundleResolveTest.res +4 -6
  213. package/tests/Util_BundleRuntimeExtensionTest.res +17 -18
  214. package/tests/Util_DcbMetricsTest.res +6 -6
  215. package/tests/Util_DynamoDbStreamTest.res +4 -5
  216. package/tests/Util_DynamoDbTest.res +3 -2
  217. package/tests/Util_LambdaEnvBudgetTest.res +22 -18
  218. package/tests/Util_LambdaLoggingTest.res +9 -8
  219. package/tests/Util_LogGroup_AdoptingTest.res +10 -5
  220. package/tests/Util_LogRetentionTest.res +6 -2
  221. package/tests/Util_OwnerScopeEnvTest.res +10 -8
  222. package/tests/Util_SQS_RuntimeTest.res +5 -7
  223. package/tests/Util_ShellConfigTest.res +7 -17
  224. package/tests/Util_StaticBundleTest.res +3 -8
  225. package/tests/Util_StoreLayoutTest.res +17 -12
  226. package/tests/integration/AggregateEntryPoint_IntegrationTest.res +1 -4
  227. package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res +15 -15
  228. package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res +296 -232
  229. package/tests/integration/DcbIntegrationHarness.res +8 -8
  230. package/tests/integration/EpCompositeSlice.res +16 -8
  231. package/tests/integration/QueryDbUnion_DynamoDb_IntegrationTest.res +8 -10
  232. package/tests/integration/StateViewSliceEntryPoint_IntegrationTest.res +10 -10
  233. package/tests/integration/SvsTestSlice_Projection.res +1 -3
  234. package/tests/util/Util_AlarmSpecTest.res +62 -49
@@ -44,9 +44,7 @@ describe("Runtime.collectQueryTags", () => {
44
44
  })
45
45
 
46
46
  testSync("collects tags from a single queryItem", () => {
47
- let q: Reventless.DcbTag.query = [
48
- {tags: [tag("orderId", "o1"), tag("customerId", "c1")]},
49
- ]
47
+ let q: Reventless.DcbTag.query = [{tags: [tag("orderId", "o1"), tag("customerId", "c1")]}]
50
48
  let result = Runtime.collectQueryTags(q)
51
49
  expect(result->Array.length)->toBe(2)
52
50
  })
@@ -62,10 +60,7 @@ describe("Runtime.collectQueryTags", () => {
62
60
  })
63
61
 
64
62
  testSync("ignores queryItems without tags but keeps others", () => {
65
- let q: Reventless.DcbTag.query = [
66
- {eventTypes: ["Foo"]},
67
- {tags: [tag("orderId", "o1")]},
68
- ]
63
+ let q: Reventless.DcbTag.query = [{eventTypes: ["Foo"]}, {tags: [tag("orderId", "o1")]}]
69
64
  let result = Runtime.collectQueryTags(q)
70
65
  expect(result->Array.length)->toBe(1)
71
66
  })
@@ -139,8 +134,7 @@ describe("Runtime.buildConditionalFenceUpdate", () => {
139
134
  ~newPosition="100",
140
135
  ~after=Some("50"),
141
136
  )
142
- let referenced =
143
- update.expressionAttributeNames->Option.getOr(Dict.make())->Dict.valuesToArray
137
+ let referenced = update.expressionAttributeNames->Option.getOr(Dict.make())->Dict.valuesToArray
144
138
  expect(referenced->Array.includes("pos#ProductPriceChanged"))->toBe(false)
145
139
  })
146
140
 
@@ -207,29 +201,17 @@ describe("Runtime.buildQueryByPartitionKeyInput", () => {
207
201
  })
208
202
 
209
203
  testSync("omits consistentRead when ~strongConsistency=false", () => {
210
- let input = Runtime.buildQueryByPartitionKeyInput(
211
- table,
212
- "orderId:o1",
213
- ~strongConsistency=false,
214
- )
204
+ let input = Runtime.buildQueryByPartitionKeyInput(table, "orderId:o1", ~strongConsistency=false)
215
205
  expect(input.consistentRead)->toEqual(None)
216
206
  })
217
207
 
218
208
  testSync("sets consistentRead=true when ~strongConsistency=true", () => {
219
- let input = Runtime.buildQueryByPartitionKeyInput(
220
- table,
221
- "orderId:o1",
222
- ~strongConsistency=true,
223
- )
209
+ let input = Runtime.buildQueryByPartitionKeyInput(table, "orderId:o1", ~strongConsistency=true)
224
210
  expect(input.consistentRead)->toEqual(Some(true))
225
211
  })
226
212
 
227
213
  testSync("does not target a GSI (uses base table)", () => {
228
- let input = Runtime.buildQueryByPartitionKeyInput(
229
- table,
230
- "orderId:o1",
231
- ~strongConsistency=true,
232
- )
214
+ let input = Runtime.buildQueryByPartitionKeyInput(table, "orderId:o1", ~strongConsistency=true)
233
215
  expect(input.indexName)->toEqual(None)
234
216
  })
235
217
 
@@ -333,7 +315,10 @@ describe("Runtime.buildConditionalTransactItems — fence-scope = read-scope", (
333
315
  }
334
316
 
335
317
  // Locate the fence transact item (Update or ConditionCheck) targeting `fenceId`.
336
- let findFence = (items: array<AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.transactWriteItem>, fenceId) =>
318
+ let findFence = (
319
+ items: array<AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.transactWriteItem>,
320
+ fenceId,
321
+ ) =>
337
322
  items->Array.find(it => {
338
323
  let idOf = key => key->Dict.get("id") == Some(fenceId->JSON.Encode.string)
339
324
  switch (it.update, it.conditionCheck) {
@@ -342,38 +327,62 @@ describe("Runtime.buildConditionalTransactItems — fence-scope = read-scope", (
342
327
  | _ => false
343
328
  }
344
329
  })
345
- let isUpdate = it => it->Option.flatMap(i => i.AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.update)->Option.isSome
346
- let isCheck = it => it->Option.flatMap(i => i.AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.conditionCheck)->Option.isSome
347
-
348
- describe("PlaceOrder shape: OrderPlaced partitioned by orderId, reads orderId + productId", () => {
349
- let orderPlaced = event(
350
- "OrderPlaced",
351
- [tag("orderId", "o1"), tag("customerId", "c1"), tag("productId", "p5")],
352
- )
353
- let partitionTag = Some(Reventless.DcbTag.Simple({key: "orderId"}))
354
- let cond: Reventless.DcbTag.appendCondition = {
355
- query: [
356
- {tags: [tag("orderId", "o1")], eventTypes: ["OrderPlaced"]},
357
- {tags: [tag("productId", "p5")], eventTypes: ["OrderPlaced", "CatalogProductSynced"]},
358
- ],
359
- after: "50",
360
- }
361
- let items = Runtime.buildConditionalTransactItems(table, [orderPlaced], cond, "100", ~partitionTag?)
330
+ let isUpdate = it =>
331
+ it
332
+ ->Option.flatMap(i => i.AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.update)
333
+ ->Option.isSome
334
+ let isCheck = it =>
335
+ it
336
+ ->Option.flatMap(i => i.AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.conditionCheck)
337
+ ->Option.isSome
338
+
339
+ describe(
340
+ "PlaceOrder shape: OrderPlaced partitioned by orderId, reads orderId + productId",
341
+ () => {
342
+ let orderPlaced = event(
343
+ "OrderPlaced",
344
+ [tag("orderId", "o1"), tag("customerId", "c1"), tag("productId", "p5")],
345
+ )
346
+ let partitionTag = Some(Reventless.DcbTag.Simple({key: "orderId"}))
347
+ let cond: Reventless.DcbTag.appendCondition = {
348
+ query: [
349
+ {tags: [tag("orderId", "o1")], eventTypes: ["OrderPlaced"]},
350
+ {tags: [tag("productId", "p5")], eventTypes: ["OrderPlaced", "CatalogProductSynced"]},
351
+ ],
352
+ after: "50",
353
+ }
354
+ let items = Runtime.buildConditionalTransactItems(
355
+ table,
356
+ [orderPlaced],
357
+ cond,
358
+ "100",
359
+ ~partitionTag?,
360
+ )
362
361
 
363
- testSync("partition tag (orderId) is a conditional Update that bumps the fence", () => {
364
- expect(isUpdate(findFence(items, "fence#orderId:o1")))->toBe(true)
365
- })
362
+ testSync(
363
+ "partition tag (orderId) is a conditional Update that bumps the fence",
364
+ () => {
365
+ expect(isUpdate(findFence(items, "fence#orderId:o1")))->toBe(true)
366
+ },
367
+ )
366
368
 
367
- testSync("non-partition read tag (productId) is a ConditionCheck, not a bump", () => {
368
- let it = findFence(items, "fence#productId:p5")
369
- expect(isCheck(it))->toBe(true)
370
- expect(isUpdate(it))->toBe(false)
371
- })
369
+ testSync(
370
+ "non-partition read tag (productId) is a ConditionCheck, not a bump",
371
+ () => {
372
+ let it = findFence(items, "fence#productId:p5")
373
+ expect(isCheck(it))->toBe(true)
374
+ expect(isUpdate(it))->toBe(false)
375
+ },
376
+ )
372
377
 
373
- testSync("secondary event tag (customerId) is not fenced at all", () => {
374
- expect(findFence(items, "fence#customerId:c1")->Option.isSome)->toBe(false)
375
- })
376
- })
378
+ testSync(
379
+ "secondary event tag (customerId) is not fenced at all",
380
+ () => {
381
+ expect(findFence(items, "fence#customerId:c1")->Option.isSome)->toBe(false)
382
+ },
383
+ )
384
+ },
385
+ )
377
386
 
378
387
  describe("composite (multi-tag) read keeps check+bump on all its tags", () => {
379
388
  // RecordProductDemand-style: one multi-tag clause => composite GSI read.
@@ -381,19 +390,28 @@ describe("Runtime.buildConditionalTransactItems — fence-scope = read-scope", (
381
390
  let partitionTag = Some(Reventless.DcbTag.Simple({key: "productId"}))
382
391
  let cond: Reventless.DcbTag.appendCondition = {
383
392
  query: [
384
- {tags: [tag("productId", "p1"), tag("orderId", "o1")], eventTypes: ["ProductDemandRecorded"]},
393
+ {
394
+ tags: [tag("productId", "p1"), tag("orderId", "o1")],
395
+ eventTypes: ["ProductDemandRecorded"],
396
+ },
385
397
  ],
386
398
  after: "50",
387
399
  }
388
400
  let items = Runtime.buildConditionalTransactItems(table, [demand], cond, "100", ~partitionTag?)
389
401
 
390
- testSync("partition tag (productId) is a conditional Update", () => {
391
- expect(isUpdate(findFence(items, "fence#productId:p1")))->toBe(true)
392
- })
402
+ testSync(
403
+ "partition tag (productId) is a conditional Update",
404
+ () => {
405
+ expect(isUpdate(findFence(items, "fence#productId:p1")))->toBe(true)
406
+ },
407
+ )
393
408
 
394
- testSync("other composite tag (orderId) is also a conditional Update — OCC preserved", () => {
395
- expect(isUpdate(findFence(items, "fence#orderId:o1")))->toBe(true)
396
- })
409
+ testSync(
410
+ "other composite tag (orderId) is also a conditional Update — OCC preserved",
411
+ () => {
412
+ expect(isUpdate(findFence(items, "fence#orderId:o1")))->toBe(true)
413
+ },
414
+ )
397
415
  })
398
416
 
399
417
  // Cross-partition tag: fence bumped by every carrier (Issue 13 / Phase 7).
@@ -412,119 +430,171 @@ describe("Runtime.buildConditionalTransactItems — fence-scope = read-scope", (
412
430
  after: "50",
413
431
  }
414
432
 
415
- testSync("with studentId cross-partition, its fence is a conditional Update (bump)", () => {
433
+ testSync(
434
+ "with studentId cross-partition, its fence is a conditional Update (bump)",
435
+ () => {
436
+ let items = Runtime.buildConditionalTransactItems(
437
+ table,
438
+ [subscribed],
439
+ cond,
440
+ "100",
441
+ ~partitionTag?,
442
+ ~crossPartitionTagKeys=["studentId"],
443
+ )
444
+ // courseId (partition) bumps as usual; studentId (cross-partition secondary) also bumps.
445
+ expect(isUpdate(findFence(items, "fence#courseId:C1")))->toBe(true)
446
+ expect(isUpdate(findFence(items, "fence#studentId:S1")))->toBe(true)
447
+ },
448
+ )
449
+
450
+ testSync(
451
+ "without the cross-partition flag, studentId is only a read-only ConditionCheck",
452
+ () => {
453
+ let items = Runtime.buildConditionalTransactItems(
454
+ table,
455
+ [subscribed],
456
+ cond,
457
+ "100",
458
+ ~partitionTag?,
459
+ )
460
+ let it = findFence(items, "fence#studentId:S1")
461
+ expect(isCheck(it))->toBe(true)
462
+ expect(isUpdate(it))->toBe(false)
463
+ },
464
+ )
465
+ })
466
+ })
467
+
468
+ describe(
469
+ "Runtime.buildConditionalTransactItems — composite partition fences on ONE composite key",
470
+ () => {
471
+ // SyncResource-style: @compositePartitionTag over {environment, platformName,
472
+ // pluginName}. The read is one exact `tag_composite` match, so the fence must be
473
+ // a SINGLE composite-key fence — not one per member. Per-member fencing made the
474
+ // low-cardinality prefix (`environment`, `platformName`) hot under a deploy
475
+ // fan-out. Plan: docs/plans/done/dcb-hot-tag-fence-contention.md.
476
+ let event = (eventType, tags): ReventlessCore.DcbEventLog_Adapter.rawStoredEvent => {
477
+ eventType,
478
+ data: JSON.Object(Dict.make()),
479
+ tags,
480
+ meta: testMeta(),
481
+ }
482
+ let findFence = (
483
+ items: array<AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.transactWriteItem>,
484
+ fenceId,
485
+ ) =>
486
+ items->Array.find(it => {
487
+ let idOf = key => key->Dict.get("id") == Some(fenceId->JSON.Encode.string)
488
+ switch (it.update, it.conditionCheck) {
489
+ | (Some(u), _) => idOf(u.key)
490
+ | (_, Some(c)) => idOf(c.key)
491
+ | _ => false
492
+ }
493
+ })
494
+ let isUpdate = it =>
495
+ it
496
+ ->Option.flatMap(i => i.AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.update)
497
+ ->Option.isSome
498
+ let fenceIds = (
499
+ items: array<AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.transactWriteItem>,
500
+ ) =>
501
+ items
502
+ ->Array.filterMap(it => {
503
+ let idOf = key => key->Dict.get("id")->Option.flatMap(JSON.Decode.string)
504
+ switch (it.update, it.conditionCheck) {
505
+ | (Some(u), _) => idOf(u.key)
506
+ | (_, Some(c)) => idOf(c.key)
507
+ | _ => None
508
+ }
509
+ })
510
+ ->Array.filter(s => s->String.startsWith("fence#"))
511
+
512
+ let spec: Reventless.DcbTag.compositePartitionSpec = {
513
+ keys: ["environment", "platformName", "pluginName"],
514
+ seps: ["/", "/"],
515
+ }
516
+ let partitionTag = Some(Reventless.DcbTag.Composite(spec))
517
+ let members = [
518
+ tag("environment", "prod"),
519
+ tag("platformName", "plat"),
520
+ tag("pluginName", "plug"),
521
+ ]
522
+ let compositeFence = "fence#__dcb_composite__:prod/plat/plug"
523
+
524
+ describe("at after=Some (entity exists)", () => {
525
+ let resource = event("ResourceAdded", members)
526
+ let cond: Reventless.DcbTag.appendCondition = {
527
+ query: [{tags: members, eventTypes: ["ResourceAdded"]}],
528
+ after: "50",
529
+ }
416
530
  let items = Runtime.buildConditionalTransactItems(
417
531
  table,
418
- [subscribed],
532
+ [resource],
419
533
  cond,
420
534
  "100",
421
535
  ~partitionTag?,
422
- ~crossPartitionTagKeys=["studentId"],
423
536
  )
424
- // courseId (partition) bumps as usual; studentId (cross-partition secondary) also bumps.
425
- expect(isUpdate(findFence(items, "fence#courseId:C1")))->toBe(true)
426
- expect(isUpdate(findFence(items, "fence#studentId:S1")))->toBe(true)
427
- })
428
-
429
- testSync("without the cross-partition flag, studentId is only a read-only ConditionCheck", () => {
430
- let items = Runtime.buildConditionalTransactItems(table, [subscribed], cond, "100", ~partitionTag?)
431
- let it = findFence(items, "fence#studentId:S1")
432
- expect(isCheck(it))->toBe(true)
433
- expect(isUpdate(it))->toBe(false)
434
- })
435
- })
436
- })
437
537
 
438
- describe("Runtime.buildConditionalTransactItems — composite partition fences on ONE composite key", () => {
439
- // SyncResource-style: @compositePartitionTag over {environment, platformName,
440
- // pluginName}. The read is one exact `tag_composite` match, so the fence must be
441
- // a SINGLE composite-key fence — not one per member. Per-member fencing made the
442
- // low-cardinality prefix (`environment`, `platformName`) hot under a deploy
443
- // fan-out. Plan: docs/plans/done/dcb-hot-tag-fence-contention.md.
444
- let event = (eventType, tags): ReventlessCore.DcbEventLog_Adapter.rawStoredEvent => {
445
- eventType,
446
- data: JSON.Object(Dict.make()),
447
- tags,
448
- meta: testMeta(),
449
- }
450
- let findFence = (
451
- items: array<AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.transactWriteItem>,
452
- fenceId,
453
- ) =>
454
- items->Array.find(it => {
455
- let idOf = key => key->Dict.get("id") == Some(fenceId->JSON.Encode.string)
456
- switch (it.update, it.conditionCheck) {
457
- | (Some(u), _) => idOf(u.key)
458
- | (_, Some(c)) => idOf(c.key)
459
- | _ => false
460
- }
461
- })
462
- let isUpdate = it =>
463
- it->Option.flatMap(i => i.AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.update)->Option.isSome
464
- let fenceIds = (items: array<AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.transactWriteItem>) =>
465
- items
466
- ->Array.filterMap(it => {
467
- let idOf = key => key->Dict.get("id")->Option.flatMap(JSON.Decode.string)
468
- switch (it.update, it.conditionCheck) {
469
- | (Some(u), _) => idOf(u.key)
470
- | (_, Some(c)) => idOf(c.key)
471
- | _ => None
472
- }
473
- })
474
- ->Array.filter(s => s->String.startsWith("fence#"))
475
-
476
- let spec: Reventless.DcbTag.compositePartitionSpec = {
477
- keys: ["environment", "platformName", "pluginName"],
478
- seps: ["/", "/"],
479
- }
480
- let partitionTag = Some(Reventless.DcbTag.Composite(spec))
481
- let members = [tag("environment", "prod"), tag("platformName", "plat"), tag("pluginName", "plug")]
482
- let compositeFence = "fence#__dcb_composite__:prod/plat/plug"
483
-
484
- describe("at after=Some (entity exists)", () => {
485
- let resource = event("ResourceAdded", members)
486
- let cond: Reventless.DcbTag.appendCondition = {
487
- query: [{tags: members, eventTypes: ["ResourceAdded"]}],
488
- after: "50",
489
- }
490
- let items = Runtime.buildConditionalTransactItems(table, [resource], cond, "100", ~partitionTag?)
538
+ testSync(
539
+ "the whole composite key is a single conditional Update",
540
+ () => {
541
+ expect(isUpdate(findFence(items, compositeFence)))->toBe(true)
542
+ },
543
+ )
491
544
 
492
- testSync("the whole composite key is a single conditional Update", () => {
493
- expect(isUpdate(findFence(items, compositeFence)))->toBe(true)
494
- })
545
+ testSync(
546
+ "no per-member fence is emitted (the hot-fence regression)",
547
+ () => {
548
+ expect(findFence(items, "fence#environment:prod")->Option.isSome)->toBe(false)
549
+ expect(findFence(items, "fence#platformName:plat")->Option.isSome)->toBe(false)
550
+ expect(findFence(items, "fence#pluginName:plug")->Option.isSome)->toBe(false)
551
+ },
552
+ )
495
553
 
496
- testSync("no per-member fence is emitted (the hot-fence regression)", () => {
497
- expect(findFence(items, "fence#environment:prod")->Option.isSome)->toBe(false)
498
- expect(findFence(items, "fence#platformName:plat")->Option.isSome)->toBe(false)
499
- expect(findFence(items, "fence#pluginName:plug")->Option.isSome)->toBe(false)
554
+ testSync(
555
+ "exactly one fence item total (the composite fence, no members)",
556
+ () => {
557
+ expect(fenceIds(items))->toEqual([compositeFence])
558
+ },
559
+ )
500
560
  })
501
561
 
502
- testSync("exactly one fence item total (the composite fence, no members)", () => {
503
- expect(fenceIds(items))->toEqual([compositeFence])
504
- })
505
- })
562
+ describe("at after=None (folded create guard)", () => {
563
+ let resource = event("ResourceAdded", members)
564
+ let cond: Reventless.DcbTag.appendCondition = {
565
+ query: [{tags: members, eventTypes: ["ResourceAdded"]}],
566
+ }
567
+ let items = Runtime.buildConditionalTransactItems(
568
+ table,
569
+ [resource],
570
+ cond,
571
+ "100",
572
+ ~partitionTag?,
573
+ )
506
574
 
507
- describe("at after=None (folded create guard)", () => {
508
- let resource = event("ResourceAdded", members)
509
- let cond: Reventless.DcbTag.appendCondition = {
510
- query: [{tags: members, eventTypes: ["ResourceAdded"]}],
511
- }
512
- let items = Runtime.buildConditionalTransactItems(table, [resource], cond, "100", ~partitionTag?)
513
-
514
- testSync("the composite fence is a create-guard Update gated on attribute_not_exists", () => {
515
- let u =
516
- findFence(items, compositeFence)
517
- ->Option.flatMap(i => i.AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.update)
518
- ->Option.getOrThrow
519
- expect(u.conditionExpression)->toEqual(Some("attribute_not_exists(#c0)"))
520
- expect(u.expressionAttributeValues->Option.flatMap(v => v->Dict.get(":after")))->toEqual(None)
521
- })
575
+ testSync(
576
+ "the composite fence is a create-guard Update gated on attribute_not_exists",
577
+ () => {
578
+ let u =
579
+ findFence(items, compositeFence)
580
+ ->Option.flatMap(i => i.AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.update)
581
+ ->Option.getOrThrow
582
+ expect(u.conditionExpression)->toEqual(Some("attribute_not_exists(#c0)"))
583
+ expect(u.expressionAttributeValues->Option.flatMap(v => v->Dict.get(":after")))->toEqual(
584
+ None,
585
+ )
586
+ },
587
+ )
522
588
 
523
- testSync("still exactly one composite fence (no per-member create guards)", () => {
524
- expect(fenceIds(items))->toEqual([compositeFence])
589
+ testSync(
590
+ "still exactly one composite fence (no per-member create guards)",
591
+ () => {
592
+ expect(fenceIds(items))->toEqual([compositeFence])
593
+ },
594
+ )
525
595
  })
526
- })
527
- })
596
+ },
597
+ )
528
598
 
529
599
  describe("Runtime.toItem — tag_composite is keyed on the event's entity tags", () => {
530
600
  // Guards the composite write/read key alignment a composite-partition slice's OCC
@@ -597,13 +667,16 @@ describe("Runtime.toItem — an empty tag value skips its GSI attribute", () =>
597
667
  ->Dict.get("tags")
598
668
  ->Option.flatMap(JSON.Decode.array)
599
669
  ->Option.getOrThrow
600
- ->Array.filterMap(t =>
601
- t
602
- ->JSON.Decode.object
603
- ->Option.map(o => (
604
- o->Dict.get("key")->Option.flatMap(JSON.Decode.string)->Option.getOr(""),
605
- o->Dict.get("value")->Option.flatMap(JSON.Decode.string)->Option.getOr("!missing"),
606
- ))
670
+ ->Array.filterMap(
671
+ t =>
672
+ t
673
+ ->JSON.Decode.object
674
+ ->Option.map(
675
+ o => (
676
+ o->Dict.get("key")->Option.flatMap(JSON.Decode.string)->Option.getOr(""),
677
+ o->Dict.get("value")->Option.flatMap(JSON.Decode.string)->Option.getOr("!missing"),
678
+ ),
679
+ ),
607
680
  )
608
681
  expect(payloadTags)->toEqual([("environment", "prod"), ("componentName", "")])
609
682
  })
@@ -630,7 +703,9 @@ describe("Runtime.buildConditionalTransactItems — folded create guard (after=N
630
703
  )
631
704
 
632
705
  // True if any item targets a legacy `create#…` sentinel row (must be none now).
633
- let hasCreateRow = (items: array<AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.transactWriteItem>) =>
706
+ let hasCreateRow = (
707
+ items: array<AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.transactWriteItem>,
708
+ ) =>
634
709
  items->Array.some(it =>
635
710
  switch it.AwsSdk.DynamoDb.DocumentClient.TransactWriteCommand.update {
636
711
  | Some(u) =>
@@ -653,23 +728,34 @@ describe("Runtime.buildConditionalTransactItems — folded create guard (after=N
653
728
  }
654
729
  let items = Runtime.buildConditionalTransactItems(table, [added], cond, "100", ~partitionTag?)
655
730
 
656
- testSync("no separate create# row is emitted (guard folded into the fence)", () => {
657
- expect(hasCreateRow(items))->toBe(false)
658
- })
731
+ testSync(
732
+ "no separate create# row is emitted (guard folded into the fence)",
733
+ () => {
734
+ expect(hasCreateRow(items))->toBe(false)
735
+ },
736
+ )
659
737
 
660
- testSync("the partition fence is a conditional Update gated on attribute_not_exists", () => {
661
- let u = fenceUpdate(items, "fence#productId:p1")->Option.getOrThrow
662
- expect(u.conditionExpression)->toEqual(Some("attribute_not_exists(#c0)"))
663
- expect(u.updateExpression)->toBe("SET #p0 = :new")
664
- expect(u.expressionAttributeValues->Option.flatMap(v => v->Dict.get(":after")))->toEqual(None)
665
- })
738
+ testSync(
739
+ "the partition fence is a conditional Update gated on attribute_not_exists",
740
+ () => {
741
+ let u = fenceUpdate(items, "fence#productId:p1")->Option.getOrThrow
742
+ expect(u.conditionExpression)->toEqual(Some("attribute_not_exists(#c0)"))
743
+ expect(u.updateExpression)->toBe("SET #p0 = :new")
744
+ expect(u.expressionAttributeValues->Option.flatMap(v => v->Dict.get(":after")))->toEqual(
745
+ None,
746
+ )
747
+ },
748
+ )
666
749
 
667
- testSync("the guard references only the produced/consumed type", () => {
668
- let u = fenceUpdate(items, "fence#productId:p1")->Option.getOrThrow
669
- let referenced = referencedAttrs(u)
670
- expect(referenced->Array.includes("pos#ProductAdded"))->toBe(true)
671
- expect(referenced->Array.includes("pos#ProductPriceChanged"))->toBe(false)
672
- })
750
+ testSync(
751
+ "the guard references only the produced/consumed type",
752
+ () => {
753
+ let u = fenceUpdate(items, "fence#productId:p1")->Option.getOrThrow
754
+ let referenced = referencedAttrs(u)
755
+ expect(referenced->Array.includes("pos#ProductAdded"))->toBe(true)
756
+ expect(referenced->Array.includes("pos#ProductPriceChanged"))->toBe(false)
757
+ },
758
+ )
673
759
  })
674
760
 
675
761
  describe("produced-not-consumed (the double-create gate — analysis con #1)", () => {
@@ -682,45 +768,55 @@ describe("Runtime.buildConditionalTransactItems — folded create guard (after=N
682
768
  }
683
769
  let items = Runtime.buildConditionalTransactItems(table, [started], cond, "100", ~partitionTag?)
684
770
 
685
- testSync("the produced type is in the guard even though it is not consumed", () => {
686
- let u = fenceUpdate(items, "fence#orderId:o1")->Option.getOrThrow
687
- let referenced = referencedAttrs(u)
688
- // guard set = consumed ∪ produced = {OrderDrafted, OrderStarted}
689
- expect(referenced->Array.includes("pos#OrderStarted"))->toBe(true)
690
- expect(referenced->Array.includes("pos#OrderDrafted"))->toBe(true)
691
- })
771
+ testSync(
772
+ "the produced type is in the guard even though it is not consumed",
773
+ () => {
774
+ let u = fenceUpdate(items, "fence#orderId:o1")->Option.getOrThrow
775
+ let referenced = referencedAttrs(u)
776
+ // guard set = consumed ∪ produced = {OrderDrafted, OrderStarted}
777
+ expect(referenced->Array.includes("pos#OrderStarted"))->toBe(true)
778
+ expect(referenced->Array.includes("pos#OrderDrafted"))->toBe(true)
779
+ },
780
+ )
692
781
 
693
- testSync("the bump advances the produced type", () => {
694
- let u = fenceUpdate(items, "fence#orderId:o1")->Option.getOrThrow
695
- expect(u.updateExpression)->toBe("SET #p0 = :new")
696
- expect(u.expressionAttributeNames->Option.flatMap(n => n->Dict.get("#p0")))->toEqual(
697
- Some("pos#OrderStarted"),
698
- )
699
- })
782
+ testSync(
783
+ "the bump advances the produced type",
784
+ () => {
785
+ let u = fenceUpdate(items, "fence#orderId:o1")->Option.getOrThrow
786
+ expect(u.updateExpression)->toBe("SET #p0 = :new")
787
+ expect(u.expressionAttributeNames->Option.flatMap(n => n->Dict.get("#p0")))->toEqual(
788
+ Some("pos#OrderStarted"),
789
+ )
790
+ },
791
+ )
700
792
  })
701
793
 
702
794
  describe("at after=Some (entity exists)", () => {
703
795
  let changed = event("ProductNameChanged", [tag("productId", "p1")])
704
796
  let partitionTag = Some(Reventless.DcbTag.Simple({key: "productId"}))
705
797
  let cond: Reventless.DcbTag.appendCondition = {
706
- query: [
707
- {tags: [tag("productId", "p1")], eventTypes: ["ProductAdded", "ProductNameChanged"]},
708
- ],
798
+ query: [{tags: [tag("productId", "p1")], eventTypes: ["ProductAdded", "ProductNameChanged"]}],
709
799
  after: "50",
710
800
  }
711
801
  let items = Runtime.buildConditionalTransactItems(table, [changed], cond, "100", ~partitionTag?)
712
802
 
713
- testSync("emits no create# row", () => {
714
- expect(hasCreateRow(items))->toBe(false)
715
- })
803
+ testSync(
804
+ "emits no create# row",
805
+ () => {
806
+ expect(hasCreateRow(items))->toBe(false)
807
+ },
808
+ )
716
809
 
717
- testSync("the fence check covers consumed types but not unrelated ones (Issue 4 fix)", () => {
718
- let u = fenceUpdate(items, "fence#productId:p1")->Option.getOrThrow
719
- let referenced = referencedAttrs(u)
720
- expect(referenced->Array.includes("pos#ProductAdded"))->toBe(true)
721
- expect(referenced->Array.includes("pos#ProductNameChanged"))->toBe(true)
722
- expect(referenced->Array.includes("pos#ProductPriceChanged"))->toBe(false)
723
- })
810
+ testSync(
811
+ "the fence check covers consumed types but not unrelated ones (Issue 4 fix)",
812
+ () => {
813
+ let u = fenceUpdate(items, "fence#productId:p1")->Option.getOrThrow
814
+ let referenced = referencedAttrs(u)
815
+ expect(referenced->Array.includes("pos#ProductAdded"))->toBe(true)
816
+ expect(referenced->Array.includes("pos#ProductNameChanged"))->toBe(true)
817
+ expect(referenced->Array.includes("pos#ProductPriceChanged"))->toBe(false)
818
+ },
819
+ )
724
820
  })
725
821
  })
726
822