@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.
- package/CHANGELOG.md +15 -0
- package/package.json +11 -11
- package/scripts/ProvisionIdentity.res +8 -3
- package/src/Platform.res +327 -328
- package/src/Platform.res.mjs +4 -2
- package/src/Platform_Casts.res +13 -4
- package/src/adapter/Api/AppSyncEventsSigner_Ops.res +8 -4
- package/src/adapter/Api/AppSync_EventsApi.res +12 -14
- package/src/adapter/Api/AppSync_Resolver_Native.res +3 -4
- package/src/adapter/Api/AppSync_Resolver_Retrying.res +78 -70
- package/src/adapter/Api/AppSync_SourceApiAssociation_Retrying.res +11 -8
- package/src/adapter/Api/Platform_AdminScan_Ops.res +15 -14
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +10 -2
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +40 -50
- package/src/adapter/Api/Platform_UIFragments_Lambda.res +39 -32
- package/src/adapter/Api/Platform_UIFragments_Lambda_Ops.res +5 -2
- package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res +0 -1
- package/src/adapter/Auth/Auth_ActiveRoleStore.res +1 -2
- package/src/adapter/Auth/Auth_ActiveRoleStore_Schema.res +1 -4
- package/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res +5 -2
- package/src/adapter/Auth/Auth_Cognito.res +3 -9
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync.res +1 -4
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_AppSync_NoOp.res +3 -1
- package/src/adapter/CommandGenerator/InboundTranslationResolvers_AppSync.res +1 -4
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS.res +7 -4
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Async.res +6 -1
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_FIFO.res +7 -4
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Runtime.res +24 -18
- package/src/adapter/CommandTopic/CommandTopicChannel_SQS_Sync.res +9 -4
- package/src/adapter/CommandTopic/CommandTopicRegistry.res +1 -4
- package/src/adapter/Counter/CounterHandler_DynamoDbStream.res +15 -15
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb.res +9 -5
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +179 -213
- package/src/adapter/EventCollector/EventCollectorChannel_DynamoDbStream.res +5 -5
- package/src/adapter/EventCollector/EventCollectorChannel_Helpers.res +6 -2
- package/src/adapter/EventCollector/EventCollectorChannel_SQS.res +14 -7
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_FIFO.res +14 -7
- package/src/adapter/EventCollector/EventCollectorChannel_SQS_Runtime.res +6 -3
- package/src/adapter/EventLog/EventLogStorage_DynamoDbStream.res +6 -1
- package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res +13 -17
- package/src/adapter/EventLog/EventLogStorage_Postgres.res +7 -4
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +12 -7
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync_Ops.res +4 -2
- package/src/adapter/EventTopic/EventTopicPublisher_DynamoDbStream.res +3 -2
- package/src/adapter/EventTopic/EventTopicPublisher_SNS.res +20 -12
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_FIFO.res +21 -9
- package/src/adapter/EventTopic/EventTopicPublisher_SNS_Runtime.res +5 -3
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res +6 -3
- package/src/adapter/Mcp/MCP_Lambda.res +31 -46
- package/src/adapter/Messaging/Messaging_Ses_Backend.res +11 -7
- package/src/adapter/Messaging/Messaging_Ses_Backend.res.mjs +2 -4
- package/src/adapter/Monitoring/Monitoring_CloudWatch.res +16 -16
- package/src/adapter/Postgres/PgChangeFeedRelay_Builder.res +5 -10
- package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res +4 -2
- package/src/adapter/Postgres/PgConnection.res +6 -5
- package/src/adapter/Postgres/PgMigration_Builder.res +4 -8
- package/src/adapter/Postgres/PgRuntime.res +4 -7
- package/src/adapter/QueryDb/PgQueryResolver_Builder.res +9 -11
- package/src/adapter/QueryDb/PgQueryResolver_Lambda.res +22 -21
- package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +114 -111
- package/src/adapter/QueryDb/QueryDbResolvers_Lambda.res +1 -7
- package/src/adapter/QueryDb/QueryDbStorage.res +4 -2
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb.res +23 -24
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDbStream.res +8 -2
- package/src/adapter/QueryDb/QueryDbStorage_DynamoDb_Runtime.res +71 -73
- package/src/adapter/QueryDb/QueryDbStorage_Postgres.res +5 -2
- package/src/adapter/QueryDb/QueryInterceptor_Provisioning.res +1 -4
- package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res +8 -2
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro.res +73 -81
- package/src/adapter/Runtime/AggregateRuntime_Builder_Micro_Async.res +72 -78
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate.res +44 -67
- package/src/adapter/Runtime/AggregateRuntime_Builder_PerAggregate_Async.res +44 -67
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single.res +53 -82
- package/src/adapter/Runtime/AggregateRuntime_Builder_Single_Async.res +47 -77
- package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +18 -11
- package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +80 -97
- package/src/adapter/Runtime/CounterEntryPoint_Ops.res +2 -7
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +16 -10
- package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +24 -15
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_PerEventCollector.res +17 -37
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +31 -57
- package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res +18 -24
- package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +1 -5
- package/src/adapter/Runtime/ExtensionPointRuntime_Builder_PerExtensionPoint.res +4 -3
- package/src/adapter/Runtime/HeartbeatEntryPoint.res +0 -1
- package/src/adapter/Runtime/PgChangeFeedRelayEntryPoint.res +4 -2
- package/src/adapter/Runtime/PgMigrationEntryPoint.res +0 -1
- package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +3 -2
- package/src/adapter/Runtime/PluginExtensionPointEntryPoint.res +1 -2
- package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +4 -5
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +22 -10
- package/src/adapter/Runtime/RuntimeExtensionEntryPoint_Ops.res +8 -2
- package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res +14 -31
- package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +16 -17
- package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +10 -9
- package/src/adapter/Runtime/StateViewSliceRuntime_Builder_Single.res +46 -52
- package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res +36 -41
- package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +31 -37
- package/src/adapter/Runtime/TaskRuntime_Builder_PerBucket.res +6 -7
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents.res +4 -6
- package/src/adapter/ScheduledPublisher/ScheduledPublisher_CloudWatchEvents_Runtime.res +2 -6
- package/src/adapter/StateTopic/StateTopic_AppSync.res +21 -16
- package/src/adapter/StateTopic/StateTopic_AppSync_Ops.res +36 -32
- package/src/adapter/Task/TaskBucket_S3.res +6 -1
- package/src/adapter/Upload/Upload_Claim_S3.res +17 -20
- package/src/adapter/Upload/Upload_Claim_S3_Ops.res +5 -2
- package/src/adapter/Upload/Upload_Presign_S3.res +51 -49
- package/src/capability/Capability_Geocoding_AwsLocation.res +4 -1
- package/src/capability/Capability_Messaging.res +4 -5
- package/src/capability/Capability_Messaging_Ses.res +3 -1
- package/src/capability/Capability_ObjectStore_S3.res +1 -7
- package/src/components/Api/AppSync_Adapter.res +28 -41
- package/src/components/Api/AppSync_SdlDecorate.res +38 -30
- package/src/components/AutomationSlice_Builder.res +6 -4
- package/src/components/ExtensionPoint_Builder.res +9 -10
- package/src/components/InboundTranslationSlice_Builder.res +7 -8
- package/src/components/OutboundTranslationSlice_Builder.res +14 -8
- package/src/components/OutboundTranslationSlice_Builder.res.mjs +1 -1
- package/src/components/SideEffectHandler_Single.res +4 -4
- package/src/components/StateViewSlice_Builder.res +6 -4
- package/src/components/StateViewSlice_Builder_Stream.res +6 -4
- package/src/components/Task_Builder_PerBucket.res +10 -11
- package/src/plugin/cloner/ClonerRunner_Fargate.res +3 -10
- package/src/plugin/cloner/ClonerRunner_Fargate_Runtime.res +1 -4
- package/src/plugin/heartbeat/HeartbeatRunner_CloudWatchEvents.res +5 -5
- package/src/plugin/runtime/PluginExtensionPointRuntime_Builder.res +19 -21
- package/src/plugin/runtime/PluginRuntime_Builder.res +167 -188
- package/src/plugin/runtime/Util_PluginMessage_Runtime.res +6 -5
- package/src/plugin/stack/Plugin_Stack.res +104 -103
- package/src/util/Util_AlarmSpec.res +2 -1
- package/src/util/Util_AppSync.res +8 -2
- package/src/util/Util_AppSync_Caller.res +15 -14
- package/src/util/Util_Bundle.res +144 -67
- package/src/util/Util_Bundle.res.mjs +64 -13
- package/src/util/Util_CognitoGroupUser_Runtime.res +32 -34
- package/src/util/Util_Cognito_Runtime.res +11 -7
- package/src/util/Util_DeadLetterQueue.res +12 -2
- package/src/util/Util_DynamoDb.res +5 -3
- package/src/util/Util_DynamoDbStream.res +7 -3
- package/src/util/Util_DynamoDbStream_Runtime.res +1 -2
- package/src/util/Util_DynamoDb_Runtime.res +23 -41
- package/src/util/Util_HostUiDomain.res +6 -1
- package/src/util/Util_Kinesis_Runtime.res +10 -11
- package/src/util/Util_Lambda.res +12 -5
- package/src/util/Util_LambdaEnvBudget.res +5 -5
- package/src/util/Util_LambdaLogging.res +1 -2
- package/src/util/Util_LogGroup_Adopting.res +1 -4
- package/src/util/Util_ResourceNaming.res +1 -2
- package/src/util/Util_SNS.res +8 -3
- package/src/util/Util_SNS_FIFO.res +1 -1
- package/src/util/Util_SNS_Runtime.res +11 -10
- package/src/util/Util_SQS.res +4 -2
- package/src/util/Util_SQS_FIFO.res +5 -2
- package/src/util/Util_SQS_Runtime.res +37 -36
- package/src/util/Util_ShellConfig.res +3 -2
- package/src/util/Util_StaticBundle.res +1 -3
- package/src/util/Util_StoreLayout.res +4 -1
- package/tests/AWS_TagsTest.res +16 -5
- package/tests/AppSyncEventsSigner_OpsTest.res +11 -2
- package/tests/AppSync_AdapterTest.res +203 -224
- package/tests/AppSync_Resolver_RetryingTest.res +64 -44
- package/tests/AppSync_RetirementNarrowingTest.res +59 -46
- package/tests/AppSync_SdlDecorateTest.res +22 -20
- package/tests/AppSync_SourceApiAssociation_RetryingTest.res +40 -22
- package/tests/Auth_ActiveRolePoolAttachmentTest.res +114 -107
- package/tests/Auth_ActiveRoleStoreTest.res +12 -9
- package/tests/Auth_ActiveRoleStore_SchemaTest.res +2 -1
- package/tests/Auth_ActiveRoleTrigger_OpsTest.res +20 -16
- package/tests/Auth_CognitoTest.res +31 -46
- package/tests/AutomationSliceEntryPoint_OpsTest.res +69 -67
- package/tests/BakeConvergenceTest.res +22 -25
- package/tests/Capability_MessagingTest.res +28 -12
- package/tests/CommandTopicQueuePolicyTest.res +1 -2
- package/tests/CounterEntryPoint_OpsTest.res +3 -7
- package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +306 -210
- package/tests/EventCollectorConnectLambdaPreviewTest.res +14 -7
- package/tests/EventCollectorEntryPoint_OpsTest.res +12 -4
- package/tests/EventCollectorPluginDefinitionAssetTest.res +18 -11
- package/tests/EventCollectorReadyGateTest.res +5 -4
- package/tests/EventLogStorage_DynamoDb_RuntimeTest.res +1 -2
- package/tests/EventMapperEntryPoint_OpsTest.res +1 -3
- package/tests/ExtensionPointEntryPoint_OpsTest.res +1 -4
- package/tests/HandlerFactoryDispatchTest.res +97 -70
- package/tests/MCP_LambdaTest.res +16 -27
- package/tests/PgChangeFeedRelay_IntegrationTest.res +123 -93
- package/tests/PgChangeFeedRelay_RuntimeTest.res +13 -10
- package/tests/PgMigrationEntryPoint_IntegrationTest.res +0 -1
- package/tests/PgPipeline_IntegrationTest.res +80 -66
- package/tests/PgQueryDbUnion_IntegrationTest.res +1 -2
- package/tests/PgQueryResolverEntryPoint_OpsTest.res +2 -6
- package/tests/PgQueryResolver_LambdaTest.res +41 -24
- package/tests/Platform_AdminScan_OpsTest.res +4 -1
- package/tests/Platform_ComponentDefinitions_Lambda_OpsTest.res +137 -129
- package/tests/ProjectionEntryPoint_DisplayNameTest.res +7 -3
- package/tests/ProjectionEntryPoint_UnionStampTest.res +3 -2
- package/tests/ProvisionIdentityTest.res +2 -6
- package/tests/QueryDbOwnerIndexTableTest.res +6 -4
- package/tests/QueryDbResolvers_AppSyncTest.res +23 -16
- package/tests/QueryInterceptor_LambdaTest.res +11 -13
- package/tests/ReadModelEntryPoint_OpsTest.res +43 -41
- package/tests/RuntimeExtensionEntryPoint_OpsTest.res +4 -3
- package/tests/SideEffectEntryPoint_OpsTest.res +23 -18
- package/tests/StateChangeDescriptorParityTest.res +28 -26
- package/tests/StateTopicKeySchemaTest.res +18 -15
- package/tests/StateViewSliceEntryPoint_OpsTest.res +55 -44
- package/tests/TaskBucketEntryPoint_OpsTest.res +13 -13
- package/tests/Upload_ClaimTest.res +3 -3
- package/tests/Util_AwsErrorTest.res +4 -7
- package/tests/Util_BundleDependencyClosureTest.res +41 -3
- package/tests/Util_BundleDependencyClosureTest.res.mjs +11 -0
- package/tests/Util_BundleEsmLoaderTest.res +3 -3
- package/tests/Util_BundleResolveTest.res +4 -6
- package/tests/Util_BundleRuntimeExtensionTest.res +17 -18
- package/tests/Util_DcbMetricsTest.res +6 -6
- package/tests/Util_DynamoDbStreamTest.res +4 -5
- package/tests/Util_DynamoDbTest.res +3 -2
- package/tests/Util_LambdaEnvBudgetTest.res +22 -18
- package/tests/Util_LambdaLoggingTest.res +9 -8
- package/tests/Util_LogGroup_AdoptingTest.res +10 -5
- package/tests/Util_LogRetentionTest.res +6 -2
- package/tests/Util_OwnerScopeEnvTest.res +10 -8
- package/tests/Util_SQS_RuntimeTest.res +5 -7
- package/tests/Util_ShellConfigTest.res +7 -17
- package/tests/Util_StaticBundleTest.res +3 -8
- package/tests/Util_StoreLayoutTest.res +17 -12
- package/tests/integration/AggregateEntryPoint_IntegrationTest.res +1 -4
- package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res +15 -15
- package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res +296 -232
- package/tests/integration/DcbIntegrationHarness.res +8 -8
- package/tests/integration/EpCompositeSlice.res +16 -8
- package/tests/integration/QueryDbUnion_DynamoDb_IntegrationTest.res +8 -10
- package/tests/integration/StateViewSliceEntryPoint_IntegrationTest.res +10 -10
- package/tests/integration/SvsTestSlice_Projection.res +1 -3
- package/tests/util/Util_AlarmSpecTest.res +62 -49
|
@@ -57,8 +57,7 @@ let lastRetiredScope: ref<option<Reventless.OwnerScope.retiredScope>> = ref(None
|
|
|
57
57
|
let pushdowns: PgQueryResolver_Lambda.pushdowns = {
|
|
58
58
|
indexLookup: async (~readModelName as _, field, value) =>
|
|
59
59
|
allItems()->Array.filter(i => fieldEq(i, field, value)),
|
|
60
|
-
byIds: async (~readModelName as _, ids) =>
|
|
61
|
-
ids->Array.filterMap(id => store->Dict.get(id)),
|
|
60
|
+
byIds: async (~readModelName as _, ids) => ids->Array.filterMap(id => store->Dict.get(id)),
|
|
62
61
|
listPage: async (
|
|
63
62
|
~readModelName as _,
|
|
64
63
|
~argsDict as _,
|
|
@@ -159,7 +158,11 @@ describe("PgQueryResolver_Lambda.dispatch", () => {
|
|
|
159
158
|
testPromise("getById miss → null", async () => {
|
|
160
159
|
let r = await PgQueryResolver_Lambda.dispatch(
|
|
161
160
|
~binding=makeBinding(),
|
|
162
|
-
~payload=mkPayload(
|
|
161
|
+
~payload=mkPayload(
|
|
162
|
+
~kind="getById",
|
|
163
|
+
~args=objArgs([("id", JSON.Encode.string("absent"))]),
|
|
164
|
+
(),
|
|
165
|
+
),
|
|
163
166
|
)
|
|
164
167
|
expect(r)->toBe(JSON.Encode.null)
|
|
165
168
|
})
|
|
@@ -231,7 +234,9 @@ describe("PgQueryResolver_Lambda.dispatch", () => {
|
|
|
231
234
|
~binding=makeBinding(),
|
|
232
235
|
~payload=mkPayload(~kind="items", ~args=objArgs([("id", JSON.Encode.string("p-2"))]), ()),
|
|
233
236
|
)
|
|
234
|
-
expect(
|
|
237
|
+
expect(
|
|
238
|
+
r->field("edges")->Option.flatMap(JSON.Decode.array)->Option.getOr([])->Array.length,
|
|
239
|
+
)->toBe(0)
|
|
235
240
|
})
|
|
236
241
|
|
|
237
242
|
testPromise("authorization DenyAll → empty shape per kind", async () => {
|
|
@@ -241,8 +246,13 @@ describe("PgQueryResolver_Lambda.dispatch", () => {
|
|
|
241
246
|
~payload=mkPayload(~kind="getById", ~args=objArgs([("id", JSON.Encode.string("p-1"))]), ()),
|
|
242
247
|
)
|
|
243
248
|
expect(single)->toBe(JSON.Encode.null)
|
|
244
|
-
let list = await PgQueryResolver_Lambda.dispatch(
|
|
245
|
-
|
|
249
|
+
let list = await PgQueryResolver_Lambda.dispatch(
|
|
250
|
+
~binding=b,
|
|
251
|
+
~payload=mkPayload(~kind="list", ()),
|
|
252
|
+
)
|
|
253
|
+
expect(
|
|
254
|
+
list->field("edges")->Option.flatMap(JSON.Decode.array)->Option.getOr([])->Array.length,
|
|
255
|
+
)->toBe(0)
|
|
246
256
|
let byIds = await PgQueryResolver_Lambda.dispatch(
|
|
247
257
|
~binding=b,
|
|
248
258
|
~payload=mkPayload(~kind="byIds", ~args=objArgs([("ids", JSON.Encode.array([]))]), ()),
|
|
@@ -251,8 +261,8 @@ describe("PgQueryResolver_Lambda.dispatch", () => {
|
|
|
251
261
|
})
|
|
252
262
|
|
|
253
263
|
testPromise("queryInterceptor hook Deny → empty shape (auth allowed)", async () => {
|
|
254
|
-
QueryDb_Callback.registerQueryInterceptor(
|
|
255
|
-
Deny("nope")
|
|
264
|
+
QueryDb_Callback.registerQueryInterceptor(
|
|
265
|
+
async (~identity as _, ~readModelName as _, ~args as _) => Deny("nope"),
|
|
256
266
|
)
|
|
257
267
|
let r = await PgQueryResolver_Lambda.dispatch(
|
|
258
268
|
~binding=makeBinding(),
|
|
@@ -473,10 +483,7 @@ describe("id form — the typed doors take either", () => {
|
|
|
473
483
|
~args=objArgs([
|
|
474
484
|
(
|
|
475
485
|
"ids",
|
|
476
|
-
JSON.Encode.array([
|
|
477
|
-
JSON.Encode.string("p-1"),
|
|
478
|
-
JSON.Encode.string(globalIdFor("p-3")),
|
|
479
|
-
]),
|
|
486
|
+
JSON.Encode.array([JSON.Encode.string("p-1"), JSON.Encode.string(globalIdFor("p-3"))]),
|
|
480
487
|
),
|
|
481
488
|
]),
|
|
482
489
|
(),
|
|
@@ -492,9 +499,7 @@ describe("id form — the typed doors take either", () => {
|
|
|
492
499
|
~binding=makeBinding(),
|
|
493
500
|
~payload=mkPayload(
|
|
494
501
|
~kind="byIds",
|
|
495
|
-
~args=objArgs([
|
|
496
|
-
("ids", JSON.Encode.array(["p-1", "p-3"]->Array.map(JSON.Encode.string))),
|
|
497
|
-
]),
|
|
502
|
+
~args=objArgs([("ids", JSON.Encode.array(["p-1", "p-3"]->Array.map(JSON.Encode.string)))]),
|
|
498
503
|
(),
|
|
499
504
|
),
|
|
500
505
|
)
|
|
@@ -704,13 +709,13 @@ let geoBinding = (): PgQueryResolver_Lambda.binding => {
|
|
|
704
709
|
|
|
705
710
|
// The member type of the first row a door answers with, whatever shape it took.
|
|
706
711
|
let memberOf = (r: JSON.t): option<string> => {
|
|
707
|
-
let fromRow = row =>
|
|
708
|
-
row->field("geolocation")->Option.flatMap(g => g->str("__typename"))
|
|
712
|
+
let fromRow = row => row->field("geolocation")->Option.flatMap(g => g->str("__typename"))
|
|
709
713
|
switch r->JSON.Decode.array {
|
|
710
714
|
| Some(rows) => rows->Array.get(0)->Option.flatMap(fromRow)
|
|
711
715
|
| None =>
|
|
712
716
|
switch r->field("edges")->Option.flatMap(JSON.Decode.array) {
|
|
713
|
-
| Some(edges) =>
|
|
717
|
+
| Some(edges) =>
|
|
718
|
+
edges->Array.get(0)->Option.flatMap(e => e->field("node"))->Option.flatMap(fromRow)
|
|
714
719
|
| None => fromRow(r)
|
|
715
720
|
}
|
|
716
721
|
}
|
|
@@ -721,11 +726,20 @@ describe("PgQueryResolver — a nested union survives every door", () => {
|
|
|
721
726
|
("getById", mkPayload(~kind="getById", ~args=objArgs([("id", JSON.Encode.string("g-1"))]), ())),
|
|
722
727
|
(
|
|
723
728
|
"byIds",
|
|
724
|
-
mkPayload(
|
|
729
|
+
mkPayload(
|
|
730
|
+
~kind="byIds",
|
|
731
|
+
~args=objArgs([("ids", JSON.Encode.array([JSON.Encode.string("g-1")]))]),
|
|
732
|
+
(),
|
|
733
|
+
),
|
|
725
734
|
),
|
|
726
735
|
(
|
|
727
736
|
"index",
|
|
728
|
-
mkPayload(
|
|
737
|
+
mkPayload(
|
|
738
|
+
~kind="index",
|
|
739
|
+
~index="byStatus",
|
|
740
|
+
~args=objArgs([("byStatus", JSON.Encode.string("active"))]),
|
|
741
|
+
(),
|
|
742
|
+
),
|
|
729
743
|
),
|
|
730
744
|
("list", mkPayload(~kind="list", ())),
|
|
731
745
|
("items", mkPayload(~kind="items", ~args=objArgs([("id", JSON.Encode.string("g-1"))]), ())),
|
|
@@ -759,10 +773,13 @@ describe("PgQueryResolver — a nested union survives every door", () => {
|
|
|
759
773
|
]
|
|
760
774
|
|
|
761
775
|
doors->Array.forEach(((label, payload)) =>
|
|
762
|
-
testPromise(
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
776
|
+
testPromise(
|
|
777
|
+
label ++ " hands the member type back as stored",
|
|
778
|
+
async () => {
|
|
779
|
+
let r = await PgQueryResolver_Lambda.dispatch(~binding=geoBinding(), ~payload)
|
|
780
|
+
expect(memberOf(r))->toEqual(Some("GeolocationLocated"))
|
|
781
|
+
},
|
|
782
|
+
)
|
|
766
783
|
)
|
|
767
784
|
|
|
768
785
|
// `node` is the one door that writes a `__typename` of its own, at the top
|
|
@@ -52,7 +52,10 @@ describe("Platform_AdminScan_Ops.latestByName", () => {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
let pluginIdOf = json =>
|
|
55
|
-
json
|
|
55
|
+
json
|
|
56
|
+
->JSON.Decode.object
|
|
57
|
+
->Option.flatMap(o => o->Dict.get("pluginId"))
|
|
58
|
+
->Option.flatMap(JSON.Decode.string)
|
|
56
59
|
|
|
57
60
|
testSync("keeps only the highest version per bare plugin name", () => {
|
|
58
61
|
let items = [
|
|
@@ -38,9 +38,8 @@ let preErrorsSlice = JSON.parseOrThrow(`{
|
|
|
38
38
|
"events": []
|
|
39
39
|
}`)
|
|
40
40
|
|
|
41
|
-
let preErrorsStructure =
|
|
42
|
-
("stateChangeSlices", JSON.Encode.array([preErrorsSlice]))
|
|
43
|
-
])->JSON.Encode.object
|
|
41
|
+
let preErrorsStructure =
|
|
42
|
+
Dict.fromArray([("stateChangeSlices", JSON.Encode.array([preErrorsSlice]))])->JSON.Encode.object
|
|
44
43
|
|
|
45
44
|
describe("toEntryWith heals a structure persisted before a required list existed", () => {
|
|
46
45
|
testSync("fills the absent list on the component", () => {
|
|
@@ -48,9 +47,7 @@ describe("toEntryWith heals a structure persisted before a required list existed
|
|
|
48
47
|
entry(~filter=false, preErrorsStructure)
|
|
49
48
|
->Option.map(members(_, "stateChangeSlices"))
|
|
50
49
|
->Option.flatMap(Array.get(_, 0))
|
|
51
|
-
expect(slice->Option.flatMap(s => s->Dict.get("errors")))->toEqual(
|
|
52
|
-
Some(JSON.Encode.array([])),
|
|
53
|
-
)
|
|
50
|
+
expect(slice->Option.flatMap(s => s->Dict.get("errors")))->toEqual(Some(JSON.Encode.array([])))
|
|
54
51
|
})
|
|
55
52
|
|
|
56
53
|
testSync("fills the absent list one level down, on a command's references", () => {
|
|
@@ -69,9 +66,7 @@ describe("toEntryWith heals a structure persisted before a required list existed
|
|
|
69
66
|
|
|
70
67
|
testSync("fills an absent collection, which is a non-null list of its own", () => {
|
|
71
68
|
let e = entry(~filter=false, preErrorsStructure)
|
|
72
|
-
expect(e->Option.flatMap(o => o->Dict.get("aggregates")))->toEqual(
|
|
73
|
-
Some(JSON.Encode.array([])),
|
|
74
|
-
)
|
|
69
|
+
expect(e->Option.flatMap(o => o->Dict.get("aggregates")))->toEqual(Some(JSON.Encode.array([])))
|
|
75
70
|
})
|
|
76
71
|
|
|
77
72
|
testSync("leaves a present list untouched", () => {
|
|
@@ -89,21 +84,20 @@ describe("toEntryWith heals a structure persisted before a required list existed
|
|
|
89
84
|
entry(~filter=true, preErrorsStructure)
|
|
90
85
|
->Option.map(members(_, "stateChangeSlices"))
|
|
91
86
|
->Option.flatMap(Array.get(_, 0))
|
|
92
|
-
expect(slice->Option.flatMap(s => s->Dict.get("errors")))->toEqual(
|
|
93
|
-
Some(JSON.Encode.array([])),
|
|
94
|
-
)
|
|
87
|
+
expect(slice->Option.flatMap(s => s->Dict.get("errors")))->toEqual(Some(JSON.Encode.array([])))
|
|
95
88
|
})
|
|
96
89
|
|
|
97
90
|
testSync("still drops Internal read models when filtering", () => {
|
|
98
|
-
let structure =
|
|
99
|
-
(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
JSON.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
91
|
+
let structure =
|
|
92
|
+
Dict.fromArray([
|
|
93
|
+
(
|
|
94
|
+
"readModels",
|
|
95
|
+
JSON.Encode.array([
|
|
96
|
+
JSON.parseOrThrow(`{"name": "Orders", "visibility": "Internal"}`),
|
|
97
|
+
JSON.parseOrThrow(`{"name": "Products"}`),
|
|
98
|
+
]),
|
|
99
|
+
),
|
|
100
|
+
])->JSON.Encode.object
|
|
107
101
|
let names =
|
|
108
102
|
entry(~filter=true, structure)
|
|
109
103
|
->Option.map(members(_, "readModels"))
|
|
@@ -120,18 +114,19 @@ describe("toEntryWith heals a structure persisted before a required list existed
|
|
|
120
114
|
// sections, progress trackers and state diagrams all go quiet. Asserted because
|
|
121
115
|
// the shim is the one part of the rename with nothing to fail at compile time.
|
|
122
116
|
describe("toEntryWith reads a pre-rename structure's lifecycle field", () => {
|
|
123
|
-
let legacyStructure =
|
|
124
|
-
(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
JSON.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
117
|
+
let legacyStructure =
|
|
118
|
+
Dict.fromArray([
|
|
119
|
+
(
|
|
120
|
+
"readModels",
|
|
121
|
+
JSON.Encode.array([
|
|
122
|
+
JSON.parseOrThrow(`{"name": "Customers", "statusField": "locationStatus"}`),
|
|
123
|
+
]),
|
|
124
|
+
),
|
|
125
|
+
(
|
|
126
|
+
"stateViewSlices",
|
|
127
|
+
JSON.Encode.array([JSON.parseOrThrow(`{"name": "Orders", "statusField": "status"}`)]),
|
|
128
|
+
),
|
|
129
|
+
])->JSON.Encode.object
|
|
135
130
|
|
|
136
131
|
let fieldOf = (~collection) =>
|
|
137
132
|
entry(~filter=false, legacyStructure)
|
|
@@ -140,9 +135,7 @@ describe("toEntryWith reads a pre-rename structure's lifecycle field", () => {
|
|
|
140
135
|
->Option.flatMap(c => c->Dict.get("lifecycleField"))
|
|
141
136
|
|
|
142
137
|
testSync("a read model's legacy key answers on the new name", () =>
|
|
143
|
-
expect(fieldOf(~collection="readModels"))->toEqual(
|
|
144
|
-
Some(JSON.Encode.string("locationStatus")),
|
|
145
|
-
)
|
|
138
|
+
expect(fieldOf(~collection="readModels"))->toEqual(Some(JSON.Encode.string("locationStatus")))
|
|
146
139
|
)
|
|
147
140
|
|
|
148
141
|
testSync("so does a state view slice's", () =>
|
|
@@ -150,14 +143,15 @@ describe("toEntryWith reads a pre-rename structure's lifecycle field", () => {
|
|
|
150
143
|
)
|
|
151
144
|
|
|
152
145
|
testSync("a post-rename structure is left alone", () => {
|
|
153
|
-
let current =
|
|
154
|
-
(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
JSON.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
146
|
+
let current =
|
|
147
|
+
Dict.fromArray([
|
|
148
|
+
(
|
|
149
|
+
"readModels",
|
|
150
|
+
JSON.Encode.array([
|
|
151
|
+
JSON.parseOrThrow(`{"name": "Orders", "lifecycleField": "lifecycle", "statusField": "stale"}`),
|
|
152
|
+
]),
|
|
153
|
+
),
|
|
154
|
+
])->JSON.Encode.object
|
|
161
155
|
let field =
|
|
162
156
|
entry(~filter=false, current)
|
|
163
157
|
->Option.map(members(_, "readModels"))
|
|
@@ -167,9 +161,10 @@ describe("toEntryWith reads a pre-rename structure's lifecycle field", () => {
|
|
|
167
161
|
})
|
|
168
162
|
|
|
169
163
|
testSync("a structure declaring neither still answers nothing", () => {
|
|
170
|
-
let neither =
|
|
171
|
-
|
|
172
|
-
|
|
164
|
+
let neither =
|
|
165
|
+
Dict.fromArray([
|
|
166
|
+
("readModels", JSON.Encode.array([JSON.parseOrThrow(`{"name": "Products"}`)])),
|
|
167
|
+
])->JSON.Encode.object
|
|
173
168
|
let component =
|
|
174
169
|
entry(~filter=false, neither)
|
|
175
170
|
->Option.map(members(_, "readModels"))
|
|
@@ -184,21 +179,22 @@ describe("toEntryWith reads a pre-rename structure's lifecycle field", () => {
|
|
|
184
179
|
// transport gets working pickers locally and silent text inputs when deployed —
|
|
185
180
|
// which is why the split is asserted here as well as in core.
|
|
186
181
|
describe("toEntryWith carries Internal queryables on the filtered field", () => {
|
|
187
|
-
let mixed =
|
|
188
|
-
(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
JSON.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
JSON.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
182
|
+
let mixed =
|
|
183
|
+
Dict.fromArray([
|
|
184
|
+
(
|
|
185
|
+
"readModels",
|
|
186
|
+
JSON.Encode.array([
|
|
187
|
+
JSON.parseOrThrow(`{"name": "AvailableProducts", "visibility": "Internal"}`),
|
|
188
|
+
JSON.parseOrThrow(`{"name": "Products"}`),
|
|
189
|
+
]),
|
|
190
|
+
),
|
|
191
|
+
(
|
|
192
|
+
"stateViewSlices",
|
|
193
|
+
JSON.Encode.array([
|
|
194
|
+
JSON.parseOrThrow(`{"name": "PendingShipments", "visibility": "Internal"}`),
|
|
195
|
+
]),
|
|
196
|
+
),
|
|
197
|
+
])->JSON.Encode.object
|
|
202
198
|
|
|
203
199
|
let namesAt = (~filter, collection) =>
|
|
204
200
|
entry(~filter, mixed)
|
|
@@ -229,10 +225,11 @@ describe("toEntryWith carries Internal queryables on the filtered field", () =>
|
|
|
229
225
|
// A structure persisted before the field existed has no key for it, and must not
|
|
230
226
|
// grow one from its own contents — the complement is always recomputed.
|
|
231
227
|
testSync("computes the complement rather than reading it off the structure", () => {
|
|
232
|
-
let stale =
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
228
|
+
let stale =
|
|
229
|
+
Dict.fromArray([
|
|
230
|
+
("internalQueryables", JSON.parseOrThrow(`[{"name": "Stale"}]`)),
|
|
231
|
+
("readModels", JSON.parseOrThrow(`[{"name": "Products"}]`)),
|
|
232
|
+
])->JSON.Encode.object
|
|
236
233
|
let names =
|
|
237
234
|
entry(~filter=true, stale)
|
|
238
235
|
->Option.map(members(_, "internalQueryables"))
|
|
@@ -272,10 +269,9 @@ describe("bakeTargetOf", () => {
|
|
|
272
269
|
|
|
273
270
|
testSync("takes an explicit key", () =>
|
|
274
271
|
expect(
|
|
275
|
-
target(`{"bake": true, "bucket": "host-ui", "key": "storefront.json"}`)->Option.map(
|
|
276
|
-
t.bucket,
|
|
277
|
-
|
|
278
|
-
)),
|
|
272
|
+
target(`{"bake": true, "bucket": "host-ui", "key": "storefront.json"}`)->Option.map(
|
|
273
|
+
t => (t.bucket, t.key),
|
|
274
|
+
),
|
|
279
275
|
)->toEqual(Some(("host-ui", "storefront.json")))
|
|
280
276
|
)
|
|
281
277
|
})
|
|
@@ -319,9 +315,9 @@ describe("bakeJourney", () => {
|
|
|
319
315
|
"key": "component-manifest-fulfilment.json",
|
|
320
316
|
"components": [{"plugin": "Ordering", "views": ["Orders"], "derived": ["lifecycles"]}]
|
|
321
317
|
}`)
|
|
322
|
-
expect(
|
|
323
|
-
|
|
324
|
-
)
|
|
318
|
+
expect(
|
|
319
|
+
decoded->Option.map(j => (j.group, j.key, j.selections->Array.map(s => s.plugin))),
|
|
320
|
+
)->toEqual(Some(("Fulfilment", "component-manifest-fulfilment.json", ["Ordering"])))
|
|
325
321
|
expect(
|
|
326
322
|
decoded->Option.flatMap(j => j.selections->Array.get(0))->Option.flatMap(s => s.derived),
|
|
327
323
|
)->toEqual(Some(["lifecycles"]))
|
|
@@ -439,10 +435,11 @@ describe("registrations", () => {
|
|
|
439
435
|
// the failure used to report a name and nothing else, and the four causes it
|
|
440
436
|
// could have had were told apart by reading the read model out of band.
|
|
441
437
|
testSync("reports the expected key, the found key and when the row was written", () => {
|
|
442
|
-
let r =
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
438
|
+
let r =
|
|
439
|
+
regs(
|
|
440
|
+
[row(~name="Ordering", ~key="sha256/old", ~at="2026-08-27T09:00:00Z", ())],
|
|
441
|
+
[("Ordering", "sha256/new")],
|
|
442
|
+
)->Array.get(0)
|
|
446
443
|
expect((
|
|
447
444
|
r->Option.map(r => r.expected),
|
|
448
445
|
r->Option.flatMap(r => r.found),
|
|
@@ -456,79 +453,92 @@ describe("registrations", () => {
|
|
|
456
453
|
let after = "2026-08-27T10:05:00Z"
|
|
457
454
|
|
|
458
455
|
// The distinction §4 exists for: this plugin proves the chain works.
|
|
459
|
-
testSync(
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
456
|
+
testSync(
|
|
457
|
+
"a matching key on a row this deploy wrote is registered",
|
|
458
|
+
() =>
|
|
459
|
+
expect(
|
|
460
|
+
stateOf(
|
|
461
|
+
[row(~name="Ordering", ~key="sha256/a", ~at=after, ())],
|
|
462
|
+
[("Ordering", "sha256/a")],
|
|
463
|
+
~since,
|
|
464
|
+
),
|
|
465
|
+
)->toEqual(Some("registered")),
|
|
467
466
|
)
|
|
468
467
|
|
|
469
468
|
// Correct, and vacuous — an unchanged structure converges against a
|
|
470
469
|
// completely broken chain, which is why it is not counted as evidence.
|
|
471
|
-
testSync(
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
470
|
+
testSync(
|
|
471
|
+
"a matching key on a row that predates the deploy is unchanged",
|
|
472
|
+
() =>
|
|
473
|
+
expect(
|
|
474
|
+
stateOf(
|
|
475
|
+
[row(~name="Ordering", ~key="sha256/a", ~at=before, ())],
|
|
476
|
+
[("Ordering", "sha256/a")],
|
|
477
|
+
~since,
|
|
478
|
+
),
|
|
479
|
+
)->toEqual(Some("unchanged")),
|
|
479
480
|
)
|
|
480
481
|
|
|
481
|
-
testSync(
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
482
|
+
testSync(
|
|
483
|
+
"a matching key with no deploy instant to date it against is matched",
|
|
484
|
+
() =>
|
|
485
|
+
expect(
|
|
486
|
+
stateOf(
|
|
487
|
+
[row(~name="Ordering", ~key="sha256/a", ~at=after, ())],
|
|
488
|
+
[("Ordering", "sha256/a")],
|
|
489
|
+
),
|
|
490
|
+
)->toEqual(Some("matched")),
|
|
488
491
|
)
|
|
489
492
|
|
|
490
493
|
// Retrying is for this one.
|
|
491
|
-
testSync(
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
494
|
+
testSync(
|
|
495
|
+
"a stale row that predates the deploy is behind",
|
|
496
|
+
() =>
|
|
497
|
+
expect(
|
|
498
|
+
stateOf(
|
|
499
|
+
[row(~name="Ordering", ~key="sha256/old", ~at=before, ())],
|
|
500
|
+
[("Ordering", "sha256/new")],
|
|
501
|
+
~since,
|
|
502
|
+
),
|
|
503
|
+
)->toEqual(Some("behind")),
|
|
499
504
|
)
|
|
500
505
|
|
|
501
506
|
// And never for this one: the plugin answered during this deploy and produced
|
|
502
507
|
// a structure other than the one the deploy hashed, so the keys cannot
|
|
503
508
|
// converge and every remaining attempt is spent on something that cannot happen.
|
|
504
|
-
testSync(
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
509
|
+
testSync(
|
|
510
|
+
"a stale row this deploy wrote is diverged",
|
|
511
|
+
() =>
|
|
512
|
+
expect(
|
|
513
|
+
stateOf(
|
|
514
|
+
[row(~name="Ordering", ~key="sha256/other", ~at=after, ())],
|
|
515
|
+
[("Ordering", "sha256/new")],
|
|
516
|
+
~since,
|
|
517
|
+
),
|
|
518
|
+
)->toEqual(Some("diverged")),
|
|
512
519
|
)
|
|
513
520
|
|
|
514
521
|
// The scan filters on Connected, so a version that dropped out mid-deploy
|
|
515
522
|
// leaves no row to compare against — indistinguishable, before this, from a
|
|
516
523
|
// projection that had merely not landed yet, and waited on for the full
|
|
517
524
|
// retry budget either way.
|
|
518
|
-
testSync(
|
|
519
|
-
|
|
525
|
+
testSync(
|
|
526
|
+
"no Connected row at all is missing, not behind",
|
|
527
|
+
() => expect(stateOf([], [("Ordering", "sha256/new")], ~since))->toEqual(Some("missing")),
|
|
520
528
|
)
|
|
521
529
|
|
|
522
530
|
// An unparseable stamp must not read as fresh: reporting `registered` off a
|
|
523
531
|
// date nobody could read would credit the chain for work it may not have done.
|
|
524
|
-
testSync(
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
+
testSync(
|
|
533
|
+
"an unreadable row date does not count as written by this deploy",
|
|
534
|
+
() =>
|
|
535
|
+
expect(
|
|
536
|
+
stateOf(
|
|
537
|
+
[row(~name="Ordering", ~key="sha256/a", ~at="not-a-date", ())],
|
|
538
|
+
[("Ordering", "sha256/a")],
|
|
539
|
+
~since,
|
|
540
|
+
),
|
|
541
|
+
)->toEqual(Some("unchanged")),
|
|
532
542
|
)
|
|
533
543
|
})
|
|
534
544
|
})
|
|
@@ -562,9 +572,7 @@ describe("resolveStructure", () => {
|
|
|
562
572
|
item(offloaded),
|
|
563
573
|
)
|
|
564
574
|
->Promise.thenResolve(_ => None)
|
|
565
|
-
->Promise.catch(e =>
|
|
566
|
-
Promise.resolve(e->JsExn.fromException->Option.flatMap(JsExn.message))
|
|
567
|
-
)
|
|
575
|
+
->Promise.catch(e => Promise.resolve(e->JsExn.fromException->Option.flatMap(JsExn.message)))
|
|
568
576
|
expect(failed)->toEqual(
|
|
569
577
|
Some("offloaded structure for plugin Ordering is unreadable at sha256/abc: AccessDenied"),
|
|
570
578
|
)
|
|
@@ -53,8 +53,9 @@ let labelOf = (json: JSON.t) =>
|
|
|
53
53
|
->Option.flatMap(JSON.Decode.string)
|
|
54
54
|
|
|
55
55
|
let row = (~placedAt="2026-09-07T13:57:46.593Z"): JSON.t =>
|
|
56
|
-
(
|
|
57
|
-
|
|
56
|
+
(
|
|
57
|
+
{orderId: "o1", placedAt, shippedAt: "", displayName: None}: rowState
|
|
58
|
+
)->ReventlessCore.Message.encode(rowStateSchema)
|
|
58
59
|
|
|
59
60
|
describe("ProjectionEntryPoint_Ops.withDisplayName", () => {
|
|
60
61
|
testPromise("composes the label on save", async () => {
|
|
@@ -75,7 +76,10 @@ describe("ProjectionEntryPoint_Ops.withDisplayName", () => {
|
|
|
75
76
|
base->ProjectionEntryPoint_Ops.withDisplayName(
|
|
76
77
|
~stateSchema=Some(rowStateSchema->S.castToUnknown),
|
|
77
78
|
)
|
|
78
|
-
let _ = await ops.saveBatch([
|
|
79
|
+
let _ = await ops.saveBatch([
|
|
80
|
+
("o1", row(), None),
|
|
81
|
+
("o2", row(~placedAt="2026-09-08T09:00:00Z"), None),
|
|
82
|
+
])
|
|
79
83
|
expect(saved->Array.map(labelOf))->toEqual([
|
|
80
84
|
Some("2026-09-07T13:57:46.593Z"),
|
|
81
85
|
Some("2026-09-08T09:00:00Z"),
|
|
@@ -49,8 +49,9 @@ let memberOf = (json: JSON.t) =>
|
|
|
49
49
|
->Option.flatMap(JSON.Decode.string)
|
|
50
50
|
|
|
51
51
|
let row = (): JSON.t =>
|
|
52
|
-
(
|
|
53
|
-
|
|
52
|
+
(
|
|
53
|
+
{customerId: "c1", geolocation: Located({lat: 1.0, lng: 2.0})}: rowState
|
|
54
|
+
)->ReventlessCore.Message.encode(rowStateSchema)
|
|
54
55
|
|
|
55
56
|
describe("ProjectionEntryPoint_Ops.withUnionMemberTypes", () => {
|
|
56
57
|
testPromise("stamps the member type on save", async () => {
|
|
@@ -55,9 +55,7 @@ describe("ProvisionIdentity.parseArgs", () => {
|
|
|
55
55
|
// Same hazard from the other direction: a flag whose value was left off must
|
|
56
56
|
// not read as "no id given".
|
|
57
57
|
testSync("a flag with no value is refused", () =>
|
|
58
|
-
expect(Provision.parseArgs(["--provider-id"]))->toEqual(
|
|
59
|
-
Error("--provider-id needs a value"),
|
|
60
|
-
)
|
|
58
|
+
expect(Provision.parseArgs(["--provider-id"]))->toEqual(Error("--provider-id needs a value"))
|
|
61
59
|
)
|
|
62
60
|
|
|
63
61
|
testSync("--name with no value is refused too", () =>
|
|
@@ -87,9 +85,7 @@ describe("ProvisionIdentity.parseArgs", () => {
|
|
|
87
85
|
describe("ProvisionIdentity.poolSettings", () => {
|
|
88
86
|
let settings = Provision.poolSettings(~poolName="MyIdentity")
|
|
89
87
|
|
|
90
|
-
testSync("carries the name it was asked for", () =>
|
|
91
|
-
expect(settings.poolName)->toBe("MyIdentity")
|
|
92
|
-
)
|
|
88
|
+
testSync("carries the name it was asked for", () => expect(settings.poolName)->toBe("MyIdentity"))
|
|
93
89
|
|
|
94
90
|
testSync("matches what auto mode declares: email sign-in, no MFA, admin-only", () =>
|
|
95
91
|
expect((
|
|
@@ -26,10 +26,12 @@ describe("the derived owner index", () => {
|
|
|
26
26
|
testSync("is provisioned projecting every attribute", () => {
|
|
27
27
|
let gsis = QueryDbStorage_DynamoDb.globalSecondaryIndexes([ownerIndex])->unwrap
|
|
28
28
|
expect(
|
|
29
|
-
gsis->Array.map(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
gsis->Array.map(
|
|
30
|
+
g => {
|
|
31
|
+
let g = g->unwrap
|
|
32
|
+
(g.name, g.hashKey, g.rangeKey, g.projectionType)
|
|
33
|
+
},
|
|
34
|
+
),
|
|
33
35
|
)->toEqual([("_owner", "customerId", Some("id"), PulumiAws.DynamoDb.Table.ALL)])
|
|
34
36
|
})
|
|
35
37
|
|