@reventlessdev/reventless-core 3.0.0-alpha.259 → 3.0.0-alpha.261
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/src/Behavior.res +1 -4
- package/src/Message.res +17 -14
- package/src/Projection.res +51 -25
- package/src/RequestContext.res +8 -9
- package/src/ResourceAttribution.res +28 -14
- package/src/adapter/Adapter.res +48 -4
- package/src/adapter/EventLogProvisioning/EventLogProvisioning.res +5 -5
- package/src/adapter/Messaging/Messaging_Log_Backend.res +10 -7
- package/src/adapter/Messaging/Messaging_Log_Backend.res.mjs +2 -4
- package/src/adapter/Monitoring/Monitoring.res +16 -17
- package/src/adapter/QueryInterception/QueryInterception.res +0 -1
- package/src/adapter/Runtime/AggregateRuntime_Builder_Common.res +12 -5
- package/src/adapter/Runtime/EventCollectorRuntime_Builder_Single.res +11 -7
- package/src/adapter/Runtime/PluginRuntime_Builder_Micro.res +1 -7
- package/src/adapter/Runtime/PluginRuntime_Builder_Single.res +1 -7
- package/src/adapter/RuntimeExtension/RuntimeExtension.res +0 -1
- package/src/admin/Platform_Admin.res +17 -6
- package/src/admin/Platform_AdminApi.res +14 -9
- package/src/admin/Platform_Admin_Callback.res +1 -1
- package/src/admin/Platform_BakedManifest.res +34 -34
- package/src/admin/Platform_ComponentDefinitionsApi.res +9 -21
- package/src/admin/Platform_PluginStructuresApi.res +15 -12
- package/src/admin/UiFragmentRegistry/StateChange/UiFragmentRegistry.res +1 -1
- package/src/components/Aggregate/Aggregate.res +13 -12
- package/src/components/Aggregate/Aggregate_Builder.res +22 -21
- package/src/components/Aggregate/Aggregate_Callback.res +91 -86
- package/src/components/Api/ApiNoApiHelpers.res +1 -3
- package/src/components/Api/Api_Ids.res +0 -1
- package/src/components/Api/Api_Naming.res +41 -18
- package/src/components/Api/GraphQL_FragmentGenerator.res +42 -52
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +11 -4
- package/src/components/Api/GraphQL_SchemaInspector.res +5 -3
- package/src/components/Api/GraphQL_Stitcher.res +9 -10
- package/src/components/Api/MCP_SchemaGenerator.res +8 -12
- package/src/components/Api/OwnerScopeDiagnostics.res +1 -2
- package/src/components/Api/QueryDbListQuery.res +13 -6
- package/src/components/Api/SchemaType.res +40 -20
- package/src/components/Api/SchemaType.res.mjs +16 -0
- package/src/components/Api/SuryToJsonSchema.res +18 -10
- package/src/components/Api/SuryToJsonSchema.res.mjs +135 -121
- package/src/components/AutomationSlice/AutomationSlice.res +4 -4
- package/src/components/AutomationSlice/AutomationSlice_Builder.res +15 -14
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +3 -3
- package/src/components/Builder_Helpers.res +12 -23
- package/src/components/CommandGenerator/CommandGenerator.res +6 -1
- package/src/components/CommandGenerator/CommandGenerator_Builder.res +29 -21
- package/src/components/CommandGenerator/CommandGenerator_Callback.res +17 -21
- package/src/components/CommandTopic/CommandTopic.res +3 -3
- package/src/components/CommandTopic/CommandTopic_Builder.res +10 -10
- package/src/components/CommandTopic/CommandTopic_Callback.res +1 -4
- package/src/components/CommandTopic/CommandTopic_Helpers.res +1 -2
- package/src/components/Counter/Counter_Builder.res +1 -6
- package/src/components/Counter/Counter_Callback.res +3 -3
- package/src/components/Dcb/Dcb_Builder.res +970 -956
- package/src/components/DcbEventLog/DcbEventLog.res +4 -4
- package/src/components/DcbEventLog/DcbEventLog_Builder.res +0 -1
- package/src/components/DcbEventLog/DcbEventLog_Operations.res +17 -18
- package/src/components/EventCollector/EventCollector_Builder.res +2 -1
- package/src/components/EventLog/EventLog.res +5 -1
- package/src/components/EventLog/EventLog_Operations.res +12 -8
- package/src/components/EventMapper/EventMapper.res +8 -10
- package/src/components/EventMapper/EventMapper_Builder.res +4 -1
- package/src/components/EventMapper/EventMapper_Callback.res +46 -31
- package/src/components/EventTopic/EventTopic.res +3 -3
- package/src/components/EventTopic/EventTopic_Builder.res +1 -1
- package/src/components/Extension/Extension.res +4 -1
- package/src/components/Extension/Extension_Operations.res +11 -3
- package/src/components/ExtensionPoint/ExtensionPoint.res +3 -3
- package/src/components/ExtensionPoint/ExtensionPoint_Builder.res +9 -10
- package/src/components/ExtensionPoint/ExtensionPoint_Callback.res +2 -6
- package/src/components/ExtensionPoint/ExtensionPoint_Operations.res +13 -5
- package/src/components/Heartbeat/Heartbeat_Callback.res +3 -3
- package/src/components/InboundTranslationSlice/InboundTranslationSlice.res +4 -4
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res +7 -10
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice.res +4 -4
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res +15 -14
- package/src/components/QueryDb/QueryDb_Adapter.res +1 -3
- package/src/components/QueryDb/QueryDb_Operations.res +10 -10
- package/src/components/ReadModel/ReadModel.res +3 -3
- package/src/components/ReadModel/ReadModel_Builder.res +1 -2
- package/src/components/ReadModel/ReadModel_Callback.res +2 -1
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +5 -2
- package/src/components/StateChangeSlice/StateChangeSlice.res +3 -3
- package/src/components/StateChangeSlice/StateChangeSlice_Builder.res +23 -4
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +22 -6
- package/src/components/StateTopic.res +1 -3
- package/src/components/StateViewSlice/StateViewSlice.res +4 -4
- package/src/components/StateViewSlice/StateViewSlice_Builder.res +79 -68
- package/src/components/StateViewSlice/StateViewSlice_Callback.res +3 -1
- package/src/components/Task/Task.res +3 -3
- package/src/components/Task/Task_Adapter.res +4 -1
- package/src/components/Task/Task_Builder.res +24 -21
- package/src/plugin/api/PluginBaseFragment.res +9 -3
- package/src/plugin/component/Capability_Inference.res +8 -10
- package/src/plugin/component/Plugin.res +6 -6
- package/src/plugin/component/Plugin_Builder.res +54 -50
- package/src/plugin/component/Plugin_Callback.res +10 -6
- package/src/plugin/component/Plugin_Helpers.res +264 -230
- package/src/plugin/component/Plugin_Structure.res +370 -324
- package/src/plugin/component/Plugin_SubscriptionSchema.res +8 -6
- package/src/plugin/component/SchemaWalker.res +11 -12
- package/src/plugin/connect/PluginConnectExtension_Mapping.res +45 -50
- package/src/plugin/lifecycle/PluginBehavior.res +3 -4
- package/src/plugin/lifecycle/PluginSpec.res +1 -2
- package/src/plugin/lifecycle/PluginsProjection.res +16 -5
- package/src/plugin/lifecycle/PluginsReadModelSpec.res +0 -2
- package/src/util/CommandPublisher.res +9 -2
- package/src/util/CsvStream.res +3 -3
- package/src/util/Interstack.res +7 -15
- package/src/util/Interstack.resi +3 -3
- package/src/util/LogFormat.res +5 -9
- package/src/util/Logger.res +1 -2
- package/src/util/Lru.res +2 -1
- package/src/util/Lru.resi +2 -3
- package/src/util/ScheduleOps.res +24 -27
- package/src/util/StorePrefixCollision.res +6 -9
- package/src/util/Util_Promise.res +4 -1
- package/src/util/Util_Promise.res.mjs +1 -1
- package/tests/IdentityTest.res +166 -113
- package/tests/ResourceAttributionTest.res +28 -25
- package/tests/StorePrefixCollisionTest.res +2 -1
- package/tests/TaskBucketNamingTest.res +3 -2
- package/tests/adapter/EventLogProvisioningTest.res +51 -48
- package/tests/adapter/MonitoringTest.res +81 -38
- package/tests/adapter/QueryInterceptionTest.res +2 -2
- package/tests/adapter/RefusalVocabularyTest.res +31 -23
- package/tests/adapter/RuntimeExtensionHookReachTest.res +9 -8
- package/tests/adapter/RuntimeExtensionTest.res +5 -3
- package/tests/admin/AdminApiSchemaDriftTest.res +22 -16
- package/tests/admin/Platform_Admin_StructureTest.res +10 -11
- package/tests/admin/Platform_BakedManifestTest.res +31 -35
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +18 -15
- package/tests/admin/Platform_PluginStructuresApiTest.res +5 -3
- package/tests/admin/Platform_UIFragmentsApiTest.res +6 -3
- package/tests/aggregate/AggregateCacheTest.res +10 -12
- package/tests/aggregate/AggregateCallbackTest.res +75 -46
- package/tests/aggregate/AggregateCausationTest.res +19 -20
- package/tests/aggregate/AggregateConflictTest.res +41 -19
- package/tests/aggregate/AggregateFixtures.res +15 -5
- package/tests/aggregate/AggregateRejectionTest.res +97 -80
- package/tests/aggregate/AggregateSnapshotTest.res +44 -16
- package/tests/api/Api_IdsTest.res +10 -4
- package/tests/api/BrandedMarkerCompositionTest.res +48 -36
- package/tests/api/GeolocationSemanticTest.res +3 -3
- package/tests/api/GraphQL_FragmentGeneratorTest.res +66 -54
- package/tests/api/OwnerScopeDiagnosticsTest.res +31 -27
- package/tests/api/StorageRefFieldsTest.res +30 -18
- package/tests/api/SuryToJsonSchemaTest.res +1338 -981
- package/tests/api/SuryToJsonSchemaTest.res.mjs +31 -0
- package/tests/api/TaggedUnionSchemaTest.res +17 -24
- package/tests/commandgenerator/CommandGeneratorCallbackTest.res +235 -179
- package/tests/commandgenerator/CommandGeneratorFixtures.res +8 -13
- package/tests/commandgenerator/OwnerStampingTest.res +91 -76
- package/tests/commandtopic/CommandOutcomeHookTest.res +198 -155
- package/tests/commandtopic/CommandTopicCallbackFixtures.res +5 -4
- package/tests/commandtopic/CommandTopicCallbackTest.res +61 -43
- package/tests/commandtopic/CommandTopicHelpersRejectionTest.res +70 -55
- package/tests/counter/CounterCallbackTest.res +40 -34
- package/tests/counter/CounterFixtures.res +4 -4
- package/tests/dcb/DcbDecodeTest.res +115 -84
- package/tests/dcb/DcbEventLogOperationsTest.res +194 -143
- package/tests/dcb/DcbEventLogSchemaTest.res +13 -13
- package/tests/dcb/DcbFixtures.res +4 -5
- package/tests/dcb/DcbScopeInferenceTest.res +173 -114
- package/tests/dcb/DcbStateChangeSliceTest.res +391 -262
- package/tests/dcb/DcbTagTest.res +22 -11
- package/tests/dcb/DcbValidationTest.res +288 -218
- package/tests/eventlog/EventLogFixtures.res +4 -4
- package/tests/eventlog/EventLogOperationsTest.res +102 -67
- package/tests/eventlog/EventLogRetryTest.res +104 -65
- package/tests/eventmapper/EventMapperCallbackTest.res +118 -83
- package/tests/eventmapper/EventMapperFixtures.res +15 -23
- package/tests/eventmapper/EventMapperTest.res +54 -38
- package/tests/eventtopic/EventTopicFixtures.res +3 -4
- package/tests/eventtopic/EventTopicOperationsTest.res +41 -29
- package/tests/extensionpoint/ExtensionPointCallbackTest.res +58 -45
- package/tests/extensionpoint/ExtensionPointFixtures.res +16 -20
- package/tests/extensionpoint/ExtensionPointOperationsTest.res +70 -49
- package/tests/extensionpoint/PluginDisconnectScheduleTest.res +2 -1
- package/tests/logger/LogFormatTest.res +104 -82
- package/tests/logger/LoggerLazyTest.res +21 -12
- package/tests/message/MessageTest.res +96 -93
- package/tests/message/MetaEnvelopeTest.res +26 -30
- package/tests/plugin/HeartbeatDisconnectGraceTest.res +31 -25
- package/tests/plugin/ManifestVisibilityTest.res +20 -12
- package/tests/plugin/PluginDefinitionScalars.res +1 -2
- package/tests/plugin/PluginLifecycleCorpusTest.res +15 -12
- package/tests/plugin/PluginSpecExperiment.res +0 -1
- package/tests/plugin/PluginStructureTest.res +1533 -1030
- package/tests/plugin/PluginStructureTest.res.mjs +6 -0
- package/tests/plugin/Plugin_EventQuerySchemaTest.res +21 -10
- package/tests/plugin/SchemaWalkerTest.res +116 -70
- package/tests/plugin/StateChange/PsReserveStock.res +4 -4
- package/tests/plugin/StateView/PsAnnotatedView.res +6 -4
- package/tests/plugin/StateView/PsAnnotatedView.res.mjs +7 -3
- package/tests/plugin/StateView/PsCustomersView.res +4 -4
- package/tests/plugin/StateView/PsShipmentsView.res +3 -2
- package/tests/projection/LifecycleTrailTest.res +1 -4
- package/tests/projection/ProjectionOptimizeTest.res +13 -9
- package/tests/querydb/QueryDbFixtures.res +0 -1
- package/tests/querydb/QueryDbOperationsTest.res +99 -64
- package/tests/querydb/TaggedUnionStampTest.res +10 -8
- package/tests/sideeffecthandler/SideEffectHandlerCallbackTest.res +50 -35
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +4 -10
- package/tests/util/CommandPublisherTest.res +0 -1
- package/tests/util/CsvStreamTest.res +3 -3
- package/tests/util/LruTest.res +84 -56
|
@@ -69,43 +69,47 @@ module Make = (
|
|
|
69
69
|
//
|
|
70
70
|
// `~seq` is the replayed sequence number the batch decides from, carried in so
|
|
71
71
|
// the line below can name the state rather than serialise it.
|
|
72
|
-
let processCommand = (~seq: int) =>
|
|
73
|
-
(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
| Ok(generatedEvents) =>
|
|
91
|
-
let newState = generatedEvents->Array.reduce(state, Behavior.evolve)
|
|
92
|
-
(newState, Array.concat(outcomes, [(reference, CmdOk(generatedEvents), meta)]))
|
|
93
|
-
| Error(error) =>
|
|
94
|
-
let errorJson = error->Message.encode(Spec.errorSchema)
|
|
95
|
-
let errorCode = errorJson->Message.variantNameOfJson
|
|
96
|
-
// Strip the TAG so detail carries only the rejection payload (empty for unit errors).
|
|
97
|
-
let (_, payloadDict) = errorJson->Message.splitMessage
|
|
98
|
-
let errorDetail =
|
|
99
|
-
payloadDict->Dict.toArray->Array.length == 0
|
|
100
|
-
? ""
|
|
101
|
-
: payloadDict->JSON.Encode.object->JSON.stringify
|
|
102
|
-
EffectLogger.logError(
|
|
72
|
+
let processCommand = (~seq: int) =>
|
|
73
|
+
(
|
|
74
|
+
(state, outcomes): (Behavior.state, array<(string, cmdOutcome, Message.meta)>),
|
|
75
|
+
topicItem: CommandTopic.topicItem<Message.command'<Spec.Id.t, Spec.command>>,
|
|
76
|
+
) => {
|
|
77
|
+
let {reference, command: command'} = topicItem
|
|
78
|
+
let meta = command'->updateMeta
|
|
79
|
+
let id = command'.id->Spec.Id.toString
|
|
80
|
+
// Identity, not content: the folded state grows with the entity's whole
|
|
81
|
+
// history, so serialising it here makes the line's size a function of how
|
|
82
|
+
// long the system has been in use. The state at decision time is a
|
|
83
|
+
// debugger's subject, not a log's.
|
|
84
|
+
let cmdName =
|
|
85
|
+
command'.command
|
|
86
|
+
->Message.encode(Spec.commandSchema)
|
|
87
|
+
->Message.variantNameOfJson
|
|
88
|
+
->LogFormat.bold
|
|
89
|
+
EffectLogger.logDebug(
|
|
103
90
|
~comp,
|
|
104
|
-
`
|
|
91
|
+
`deciding: id=${id} seq=${seq->Int.toString} cmd=${cmdName}`,
|
|
105
92
|
)->Effect.runSync
|
|
106
|
-
(state,
|
|
93
|
+
switch Behavior.decide(state, command'.command) {
|
|
94
|
+
| Ok(generatedEvents) =>
|
|
95
|
+
let newState = generatedEvents->Array.reduce(state, Behavior.evolve)
|
|
96
|
+
(newState, Array.concat(outcomes, [(reference, CmdOk(generatedEvents), meta)]))
|
|
97
|
+
| Error(error) =>
|
|
98
|
+
let errorJson = error->Message.encode(Spec.errorSchema)
|
|
99
|
+
let errorCode = errorJson->Message.variantNameOfJson
|
|
100
|
+
// Strip the TAG so detail carries only the rejection payload (empty for unit errors).
|
|
101
|
+
let (_, payloadDict) = errorJson->Message.splitMessage
|
|
102
|
+
let errorDetail =
|
|
103
|
+
payloadDict->Dict.toArray->Array.length == 0
|
|
104
|
+
? ""
|
|
105
|
+
: payloadDict->JSON.Encode.object->JSON.stringify
|
|
106
|
+
EffectLogger.logError(
|
|
107
|
+
~comp,
|
|
108
|
+
`decide rejected: ${errorCode} ${errorDetail} id=${id}`,
|
|
109
|
+
)->Effect.runSync
|
|
110
|
+
(state, Array.concat(outcomes, [(reference, CmdRejected({errorCode, errorDetail}), meta)]))
|
|
111
|
+
}
|
|
107
112
|
}
|
|
108
|
-
}
|
|
109
113
|
|
|
110
114
|
let maxConflictRetries = 3
|
|
111
115
|
|
|
@@ -125,9 +129,7 @@ module Make = (
|
|
|
125
129
|
// the fixed capacity (a per-aggregate knob is a future refinement — see
|
|
126
130
|
// docs/plans/done/aggregate-snapshotting.md).
|
|
127
131
|
let replayCacheCapacity = 100
|
|
128
|
-
let replayCache: Lru.t<string, (Behavior.state, int)> = Lru.make(
|
|
129
|
-
~capacity=replayCacheCapacity,
|
|
130
|
-
)
|
|
132
|
+
let replayCache: Lru.t<string, (Behavior.state, int)> = Lru.make(~capacity=replayCacheCapacity)
|
|
131
133
|
|
|
132
134
|
let resetCache = () => replayCache->Lru.clear
|
|
133
135
|
|
|
@@ -188,8 +190,7 @@ module Make = (
|
|
|
188
190
|
let seedEffect = switch snapshotConfig {
|
|
189
191
|
| None => Effect.succeed((Behavior.initialState, 0))
|
|
190
192
|
| Some(_) =>
|
|
191
|
-
Effect.promise(() => Ops.eventLog.latestSnapshot(id))
|
|
192
|
-
->Effect.map(snapResult =>
|
|
193
|
+
Effect.promise(() => Ops.eventLog.latestSnapshot(id))->Effect.map(snapResult =>
|
|
193
194
|
switch snapResult {
|
|
194
195
|
| Ok(Some(snap)) if snap.EventLog.schemaHash == stateSchemaHash =>
|
|
195
196
|
switch decodeState(snap.state) {
|
|
@@ -269,7 +270,11 @@ module Make = (
|
|
|
269
270
|
| Some({interval}) if interval > 0 && newSeq / interval > oldSeq / interval =>
|
|
270
271
|
switch encodeState(state) {
|
|
271
272
|
| Some(stateJson) =>
|
|
272
|
-
fireSnapshotWrite(
|
|
273
|
+
fireSnapshotWrite(
|
|
274
|
+
id,
|
|
275
|
+
idStr,
|
|
276
|
+
{EventLog.seqNr: newSeq, state: stateJson, schemaHash: stateSchemaHash},
|
|
277
|
+
)
|
|
273
278
|
| None =>
|
|
274
279
|
EffectLogger.logWarn(
|
|
275
280
|
~comp,
|
|
@@ -342,8 +347,7 @@ module Make = (
|
|
|
342
347
|
| None => coldReadState(id)
|
|
343
348
|
}
|
|
344
349
|
|
|
345
|
-
readState
|
|
346
|
-
->Effect.flatMap(((initialState, sequenceNr)) => {
|
|
350
|
+
readState->Effect.flatMap(((initialState, sequenceNr)) => {
|
|
347
351
|
let (finalState, outcomes) =
|
|
348
352
|
topicItemsForId->Array.reduce((initialState, []), processCommand(~seq=sequenceNr))
|
|
349
353
|
|
|
@@ -379,51 +383,52 @@ module Make = (
|
|
|
379
383
|
~detail=eventJsons,
|
|
380
384
|
`produced ${eventCount} event(s): [${eventDetails}]`,
|
|
381
385
|
)
|
|
382
|
-
->Effect.flatMap(
|
|
383
|
-
|
|
386
|
+
->Effect.flatMap(_ =>
|
|
387
|
+
Effect.promise(() => Ops.eventLog.append(sequenceNr, id, generatedEvents'))
|
|
384
388
|
)
|
|
385
|
-
->Effect.flatMap(
|
|
386
|
-
appendResult
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
389
|
+
->Effect.flatMap(appendResult =>
|
|
390
|
+
switch appendResult {
|
|
391
|
+
| Ok(_) =>
|
|
392
|
+
// The post-decide fold state IS the post-append replay result;
|
|
393
|
+
// cache it so the next command for this id skips the replay.
|
|
394
|
+
let newSeq = sequenceNr + generatedEvents'->Array.length
|
|
395
|
+
replayCache->Lru.put(idStr, (finalState, newSeq))
|
|
396
|
+
// Persist a snapshot if this append crossed an interval boundary
|
|
397
|
+
// (fire-and-forget — never blocks or fails the command).
|
|
398
|
+
maybeWriteSnapshot(id, idStr, ~oldSeq=sequenceNr, ~newSeq, finalState)
|
|
399
|
+
let perRef = reportFinalOutcomes(
|
|
400
|
+
outcomes,
|
|
401
|
+
~entityId=idStr,
|
|
402
|
+
~appendSucceeded=true,
|
|
403
|
+
~appendedEventCount=generatedEvents'->Array.length,
|
|
404
|
+
)
|
|
405
|
+
EffectLogger.logInfo(~comp, `append: id=${idStr}`)->Effect.map(_ => Ok(perRef))
|
|
406
|
+
| Error(EventLog.Conflict) =>
|
|
407
|
+
// Another writer advanced the stream past our (possibly cached)
|
|
408
|
+
// sequenceNr — drop the entry so the retry replays cold.
|
|
409
|
+
replayCache->Lru.invalidate(idStr)
|
|
410
|
+
// Signal the outer replay+re-decide retry loop (which matches
|
|
411
|
+
// Error(_)); the string is an internal marker, no longer a
|
|
412
|
+
// cross-component substring sentinel.
|
|
413
|
+
EffectLogger.logWarn(~comp, `conflict: id=${idStr}, will retry`)->Effect.map(
|
|
414
|
+
_ => Error("conflict"),
|
|
415
|
+
)
|
|
416
|
+
| Error(EventLog.StorageFailure(msg)) =>
|
|
417
|
+
// Appends are atomic, so the read snapshot is likely still valid —
|
|
418
|
+
// but a storage error means we can't be sure what committed;
|
|
419
|
+
// drop the entry so the next attempt reads authoritative state.
|
|
420
|
+
replayCache->Lru.invalidate(idStr)
|
|
421
|
+
let perRef = reportFinalOutcomes(
|
|
422
|
+
outcomes,
|
|
423
|
+
~entityId=idStr,
|
|
424
|
+
~appendSucceeded=false,
|
|
425
|
+
~appendedEventCount=0,
|
|
426
|
+
~appendErrorDetail=msg,
|
|
427
|
+
)
|
|
428
|
+
EffectLogger.logError(~comp, `append failed: id=${idStr}: ${msg}`)->Effect.map(
|
|
429
|
+
_ => Ok(perRef),
|
|
430
|
+
)
|
|
431
|
+
}
|
|
427
432
|
)
|
|
428
433
|
}
|
|
429
434
|
})
|
|
@@ -10,9 +10,7 @@ let excludedByMembers = (commandSchema: S.t<unknown>): array<string> =>
|
|
|
10
10
|
switch commandSchema {
|
|
11
11
|
| AnyOf({anyOf}) =>
|
|
12
12
|
anyOf->Array.filterMap(member =>
|
|
13
|
-
member->S.Metadata.get(~id=noApiVariantId)->Option.getOr(false)
|
|
14
|
-
? variantNameOf(member)
|
|
15
|
-
: None
|
|
13
|
+
member->S.Metadata.get(~id=noApiVariantId)->Option.getOr(false) ? variantNameOf(member) : None
|
|
16
14
|
)
|
|
17
15
|
| _ => []
|
|
18
16
|
}
|
|
@@ -12,7 +12,6 @@ door applies it, and so provider adapters share one definition rather than three
|
|
|
12
12
|
Provider-neutral on purpose: the contract belongs to neither the local platform
|
|
13
13
|
nor AWS.
|
|
14
14
|
*/
|
|
15
|
-
|
|
16
15
|
@val external btoa: string => string = "btoa"
|
|
17
16
|
@val external atob: string => string = "atob"
|
|
18
17
|
|
|
@@ -12,9 +12,15 @@ type queryNames = {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
let pluralize = (n: string) =>
|
|
15
|
-
if RegExp.test(
|
|
15
|
+
if RegExp.test(/[^aeiou]y$/i, n) {
|
|
16
16
|
n->String.slice(~start=0, ~end=String.length(n) - 1) ++ "ies"
|
|
17
|
-
} else if
|
|
17
|
+
} else if (
|
|
18
|
+
n->String.endsWith("s") ||
|
|
19
|
+
n->String.endsWith("x") ||
|
|
20
|
+
n->String.endsWith("z") ||
|
|
21
|
+
n->String.endsWith("ch") ||
|
|
22
|
+
n->String.endsWith("sh")
|
|
23
|
+
) {
|
|
18
24
|
n ++ "es"
|
|
19
25
|
} else {
|
|
20
26
|
n ++ "s"
|
|
@@ -23,7 +29,13 @@ let pluralize = (n: string) =>
|
|
|
23
29
|
let singularize = (n: string) =>
|
|
24
30
|
if n->String.endsWith("ies") {
|
|
25
31
|
n->String.slice(~start=0, ~end=n->String.length - 3) ++ "y"
|
|
26
|
-
} else if
|
|
32
|
+
} else if (
|
|
33
|
+
n->String.endsWith("ses") ||
|
|
34
|
+
n->String.endsWith("xes") ||
|
|
35
|
+
n->String.endsWith("zes") ||
|
|
36
|
+
n->String.endsWith("ches") ||
|
|
37
|
+
n->String.endsWith("shes")
|
|
38
|
+
) {
|
|
27
39
|
n->String.slice(~start=0, ~end=n->String.length - 2)
|
|
28
40
|
} else if n->String.endsWith("s") {
|
|
29
41
|
n->String.slice(~start=0, ~end=n->String.length - 1)
|
|
@@ -76,16 +88,17 @@ let assertSubscriptionNameFits = (~fieldName: string) => {
|
|
|
76
88
|
// expect that shape (not aggregate-style `${plugin}_${slice}_${command}`). @noApi
|
|
77
89
|
// variants are filtered out. Every emitted name is guarded against the 50-char AppSync
|
|
78
90
|
// subscription cap at build time. Returns [(fieldName, constructorName)] in declaration order.
|
|
79
|
-
let sliceMutationFields = (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
): array<(string, string)> => {
|
|
91
|
+
let sliceMutationFields = (~plugin: string, ~slice: string, ~commandSchema: S.t<unknown>): array<(
|
|
92
|
+
string,
|
|
93
|
+
string,
|
|
94
|
+
)> => {
|
|
84
95
|
let allNames = Reventless.DcbTag.extractAllVariantNames(commandSchema->Obj.magic)
|
|
85
96
|
let filtered = ApiNoApiHelpers.filterNoApiVariants(allNames, commandSchema)
|
|
86
97
|
switch filtered {
|
|
87
98
|
| [] => []
|
|
88
|
-
| [single] => [
|
|
99
|
+
| [single] => [
|
|
100
|
+
(assertSubscriptionNameFits(~fieldName=sliceMutationField(~plugin, ~slice)), single),
|
|
101
|
+
]
|
|
89
102
|
| _ =>
|
|
90
103
|
filtered->Array.map(ctor => (
|
|
91
104
|
assertSubscriptionNameFits(~fieldName=dcbCommandMutationField(~plugin, ~command=ctor)),
|
|
@@ -115,7 +128,11 @@ let sliceMutationFieldFor = (
|
|
|
115
128
|
// "ProductDemand" the singularize is a no-op and pluralize behaves as usual.
|
|
116
129
|
let canonicalPlural = (n: string) => pluralize(singularize(n))
|
|
117
130
|
|
|
118
|
-
let queryFieldNamesForReadModel = (
|
|
131
|
+
let queryFieldNamesForReadModel = (
|
|
132
|
+
~plugin: string,
|
|
133
|
+
~name: string,
|
|
134
|
+
~connectionSpec: bool=true,
|
|
135
|
+
): queryNames => {
|
|
119
136
|
let singular = singularize(name)
|
|
120
137
|
let plural = canonicalPlural(name)
|
|
121
138
|
{
|
|
@@ -144,18 +161,16 @@ returning a type the plugin does not define fails the merge — and on AWS the
|
|
|
144
161
|
target table's `dynamodb:*` grant is attached to the *declaring* plugin's API
|
|
145
162
|
role, so even a schema that merged would be refused at read time.
|
|
146
163
|
*/
|
|
147
|
-
let resolvedFieldsOfConfig = (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
): array<ReventlessInfra.Api.resolvedFieldEntry> => {
|
|
164
|
+
let resolvedFieldsOfConfig = (~plugin: string, config: Reventless.ReadModel.config): array<
|
|
165
|
+
ReventlessInfra.Api.resolvedFieldEntry,
|
|
166
|
+
> => {
|
|
151
167
|
let assertSamePlugin = (~pluginName: option<string>, ~tableName: string, ~fieldName: string) =>
|
|
152
168
|
switch pluginName {
|
|
153
169
|
| Some(p) if p != plugin =>
|
|
154
170
|
JsError.throwWithMessage(
|
|
155
171
|
`Field \`${fieldName}\` resolves to "${tableName}" in plugin "${p}", but cross-plugin ` ++
|
|
156
172
|
`resolvers are not supported: a plugin's GraphQL document must be valid standalone, and ` ++
|
|
157
|
-
`"${p}"'s table is not readable by "${plugin}"'s API role. Query the other view directly, ` ++
|
|
158
|
-
`or project the fields you need into this one.`,
|
|
173
|
+
`"${p}"'s table is not readable by "${plugin}"'s API role. Query the other view directly, ` ++ `or project the fields you need into this one.`,
|
|
159
174
|
)
|
|
160
175
|
| _ => ()
|
|
161
176
|
}
|
|
@@ -186,7 +201,11 @@ let resolvedFieldsOfConfig = (
|
|
|
186
201
|
Array.concat(single, many)
|
|
187
202
|
}
|
|
188
203
|
|
|
189
|
-
let queryFieldNamesForStateView = (
|
|
204
|
+
let queryFieldNamesForStateView = (
|
|
205
|
+
~plugin: string,
|
|
206
|
+
~viewName: string,
|
|
207
|
+
~connectionSpec: bool=true,
|
|
208
|
+
): queryNames => {
|
|
190
209
|
let entity = stripViewSuffix(viewName)
|
|
191
210
|
let singular = singularize(entity)
|
|
192
211
|
let plural = canonicalPlural(entity)
|
|
@@ -206,7 +225,11 @@ let queryFieldNamesForStateView = (~plugin: string, ~viewName: string, ~connecti
|
|
|
206
225
|
// the resolver path (`GetItem` instead of `Scan`), and the `*ByIds` batch
|
|
207
226
|
// resolver all line up. StateViewSlice uses `queryFieldNamesForStateView`
|
|
208
227
|
// instead and keeps its own (id-free) shape.
|
|
209
|
-
let queryFieldNamesForSliceQueryDb = (
|
|
228
|
+
let queryFieldNamesForSliceQueryDb = (
|
|
229
|
+
~plugin: string,
|
|
230
|
+
~queryDbName: string,
|
|
231
|
+
~connectionSpec: bool=true,
|
|
232
|
+
): queryNames => {
|
|
210
233
|
{
|
|
211
234
|
singleFieldName: `${plugin}_${queryDbName}`,
|
|
212
235
|
listFieldName: `${plugin}_${canonicalPlural(queryDbName)}`,
|
|
@@ -89,6 +89,9 @@ let rec fromSchemaType = (
|
|
|
89
89
|
// reaches the UI through the field's JSON Schema, which is the channel that
|
|
90
90
|
// can express it.
|
|
91
91
|
| Semantic(_, inner) => fromSchemaType(~required, ~asInput, inner, collectedTypes, seenTypes)
|
|
92
|
+
// The SDL type is the wrapped shape's. A GraphQL default value here instead
|
|
93
|
+
// would make the field optional on the wire — a different claim.
|
|
94
|
+
| Defaulted(_, inner) => fromSchemaType(~required, ~asInput, inner, collectedTypes, seenTypes)
|
|
92
95
|
// A union declares one object type per arm and a `union` naming them. Both
|
|
93
96
|
// names come from the schema — see `Reventless.TaggedUnion` — so the same union
|
|
94
97
|
// is the same type wherever it appears, which is what lets AppSync merge each
|
|
@@ -234,7 +237,9 @@ let deriveObjectTypeWithNested = (
|
|
|
234
237
|
// — for every plugin in the merge, not just this one. Refuse at build time,
|
|
235
238
|
// naming both halves.
|
|
236
239
|
resolvedFields->Array.forEach(({fieldName}) =>
|
|
237
|
-
if
|
|
240
|
+
if (
|
|
241
|
+
filteredFields->Dict.get(fieldName)->Option.isSome || (includeIdParam && fieldName == "id")
|
|
242
|
+
) {
|
|
238
243
|
JsError.throwWithMessage(
|
|
239
244
|
`${typeName}.${fieldName} is declared by @resolves/@resolvesMany and is already a field of the state record. Name the resolved field something the state does not use.`,
|
|
240
245
|
)
|
|
@@ -292,7 +297,7 @@ let rec scalarOfSchemaType = (st: SchemaType.schemaType): string =>
|
|
|
292
297
|
| ScalarBoolean => "Boolean"
|
|
293
298
|
| ScalarBigInt => "String"
|
|
294
299
|
| EntityId => "ID"
|
|
295
|
-
| Semantic(_, inner) => scalarOfSchemaType(inner)
|
|
300
|
+
| Semantic(_, inner) | Defaulted(_, inner) => scalarOfSchemaType(inner)
|
|
296
301
|
| _ => "String"
|
|
297
302
|
}
|
|
298
303
|
|
|
@@ -300,16 +305,15 @@ let rec scalarOfSchemaType = (st: SchemaType.schemaType): string =>
|
|
|
300
305
|
// `SchemaType.isIdFieldName`, which lowercases before testing the suffix and so
|
|
301
306
|
// accepts `paid` and `valid` — harmless where it is used, but here it would
|
|
302
307
|
// nominate an ordinary word as a row's key.
|
|
303
|
-
let isKeyFieldName = (name: string): bool =>
|
|
304
|
-
name->String.length > 2 && name->String.endsWith("Id")
|
|
308
|
+
let isKeyFieldName = (name: string): bool => name->String.length > 2 && name->String.endsWith("Id")
|
|
305
309
|
|
|
306
310
|
/** What the ladder below concluded. The two ways to have no key are opposite
|
|
307
311
|
mistakes, so they are kept apart rather than collapsed into `None`. */
|
|
308
312
|
type keyFieldResolution =
|
|
309
313
|
| Resolved({field: string, rung: string})
|
|
310
|
-
|
|
314
|
+
/** Several `*Id` fields and none matching the name — usually a field
|
|
311
315
|
somebody added to a view that used to have exactly one. */
|
|
312
|
-
Ambiguous({candidates: array<string>, conventional: string})
|
|
316
|
+
| Ambiguous({candidates: array<string>, conventional: string})
|
|
313
317
|
| NoCandidate
|
|
314
318
|
|
|
315
319
|
/**
|
|
@@ -381,8 +385,7 @@ let keyFieldGapMessage = (resolution: keyFieldResolution): option<string> =>
|
|
|
381
385
|
`has no row key: it declares no @id and its \`*Id\` fields ` ++
|
|
382
386
|
`(${candidates->Array.join(", ")}) include no "${conventional}" for the name to ` ++
|
|
383
387
|
`pick. Adding a second \`*Id\` field to a view that had one is what lands here, ` ++
|
|
384
|
-
`and it costs the view its filter and its whole orderBy in the schema. Declare ` ++
|
|
385
|
-
`@id on the field that identifies a row.`,
|
|
388
|
+
`and it costs the view its filter and its whole orderBy in the schema. Declare ` ++ `@id on the field that identifies a row.`,
|
|
386
389
|
)
|
|
387
390
|
}
|
|
388
391
|
|
|
@@ -494,15 +497,14 @@ let deriveConnectionFilterType = (
|
|
|
494
497
|
~capability: serverCapability=emptyCapability,
|
|
495
498
|
): string => {
|
|
496
499
|
let baseFields = ["search: String", "searchPrefix: String", "ids: [ID!]"]
|
|
497
|
-
let perFieldFilters =
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
})
|
|
500
|
+
let perFieldFilters = capability.filterFields->Array.flatMap(f => {
|
|
501
|
+
let eq = `${f.name}Eq: ${f.gqlType}`
|
|
502
|
+
if f.range {
|
|
503
|
+
[eq, `${f.name}From: ${f.gqlType}`, `${f.name}To: ${f.gqlType}`]
|
|
504
|
+
} else {
|
|
505
|
+
[eq]
|
|
506
|
+
}
|
|
507
|
+
})
|
|
506
508
|
let allFields = Array.concat(baseFields, perFieldFilters)
|
|
507
509
|
let body = allFields->Array.map(f => ` ${f}`)->Array.join("\n")
|
|
508
510
|
`input ${filterTypeName} {\n${body}\n}`
|
|
@@ -511,10 +513,9 @@ let deriveConnectionFilterType = (
|
|
|
511
513
|
// Emits an `enum <Type>OrderField` and `input <Type>OrderBy` pair when the
|
|
512
514
|
// capability has any sort fields. Returns [] when no field is sortable so
|
|
513
515
|
// the connection field doesn't reference a non-existent OrderBy type.
|
|
514
|
-
let deriveConnectionOrderByType = (
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
): array<string> =>
|
|
516
|
+
let deriveConnectionOrderByType = (~singularTypeName: string, ~capability: serverCapability): array<
|
|
517
|
+
string,
|
|
518
|
+
> =>
|
|
518
519
|
if capability.sortFields->Array.length == 0 {
|
|
519
520
|
[]
|
|
520
521
|
} else {
|
|
@@ -558,10 +559,7 @@ let deriveObjectQueryField = (
|
|
|
558
559
|
` ${singleFieldName}: ${typeName}`
|
|
559
560
|
}
|
|
560
561
|
|
|
561
|
-
let deriveListQueryField = (
|
|
562
|
-
~listFieldName: string,
|
|
563
|
-
~pluralTypeName: string,
|
|
564
|
-
): string =>
|
|
562
|
+
let deriveListQueryField = (~listFieldName: string, ~pluralTypeName: string): string =>
|
|
565
563
|
` ${listFieldName}(nextToken: String, limit: Int): ${pluralTypeName}!`
|
|
566
564
|
|
|
567
565
|
// Batched-by-ids query: fetches multiple entities in a single BatchGetItem.
|
|
@@ -569,10 +567,7 @@ let deriveListQueryField = (
|
|
|
569
567
|
// caller correlates by `id` on each returned item. Single-key tables only —
|
|
570
568
|
// composite-key BatchGetItem requires both pk + sk per key entry, which is
|
|
571
569
|
// out of scope for this field.
|
|
572
|
-
let deriveByIdsQueryField = (
|
|
573
|
-
~listFieldName: string,
|
|
574
|
-
~returnTypeName: string,
|
|
575
|
-
): string =>
|
|
570
|
+
let deriveByIdsQueryField = (~listFieldName: string, ~returnTypeName: string): string =>
|
|
576
571
|
` ${listFieldName}ByIds(ids: [String!]!, includeRetired: Boolean): [${returnTypeName}!]!`
|
|
577
572
|
|
|
578
573
|
// ── The reference door ─────────────────────────────────────────────────────
|
|
@@ -611,10 +606,8 @@ let deriveRefTypeSdl = (~returnTypeName: string): string =>
|
|
|
611
606
|
// `retiredState` is null in two cases that do not need telling apart by a
|
|
612
607
|
// consumer: a live row, and a boolean-form retirement, where the field is the
|
|
613
608
|
// state and `retired: true` has already said everything there is to say.
|
|
614
|
-
let deriveRefsQueryField = (
|
|
615
|
-
|
|
616
|
-
~returnTypeName: string,
|
|
617
|
-
): string => ` ${listFieldName}Refs(ids: [ID!]!): [${returnTypeName}Ref!]!`
|
|
609
|
+
let deriveRefsQueryField = (~listFieldName: string, ~returnTypeName: string): string =>
|
|
610
|
+
` ${listFieldName}Refs(ids: [ID!]!): [${returnTypeName}Ref!]!`
|
|
618
611
|
|
|
619
612
|
// `includeRetired` sits beside the paging arguments rather than inside `filter`,
|
|
620
613
|
// and that placement is the point. `filter` is the caller's description of the
|
|
@@ -748,10 +741,7 @@ let mutationArgTypes = (~fieldName: string, variantSchema: S.t<unknown>): option
|
|
|
748
741
|
fields
|
|
749
742
|
->Dict.toArray
|
|
750
743
|
->Array.forEach(((argName, argType)) =>
|
|
751
|
-
out->Dict.set(
|
|
752
|
-
argName,
|
|
753
|
-
fromSchemaType(~required=true, ~asInput=true, argType, [], Set.make()),
|
|
754
|
-
)
|
|
744
|
+
out->Dict.set(argName, fromSchemaType(~required=true, ~asInput=true, argType, [], Set.make()))
|
|
755
745
|
)
|
|
756
746
|
out
|
|
757
747
|
})
|
|
@@ -771,8 +761,10 @@ let generate = (
|
|
|
771
761
|
// `Plugin_Activate` / `Platform_Plugin_Activate` — always the last
|
|
772
762
|
// underscore-separated segment (e.g. `Activate`).
|
|
773
763
|
let constructorNameOf = (fieldName: string): string =>
|
|
774
|
-
fieldName
|
|
775
|
-
|
|
764
|
+
fieldName
|
|
765
|
+
->String.split("_")
|
|
766
|
+
->Array.get(fieldName->String.split("_")->Array.length - 1)
|
|
767
|
+
->Option.getOr(fieldName)
|
|
776
768
|
|
|
777
769
|
mutationEntries->Array.forEach(entry => {
|
|
778
770
|
let schema = entry.commandSchema
|
|
@@ -800,9 +792,8 @@ let generate = (
|
|
|
800
792
|
entry.fieldNames->Array.forEach(fieldName => {
|
|
801
793
|
let cname = constructorNameOf(fieldName)
|
|
802
794
|
let variantIndex = variantNames->Array.indexOf(cname)
|
|
803
|
-
let variantSchema =
|
|
804
|
-
? anyOf->Array.get(variantIndex)->Option.getOr(schema)
|
|
805
|
-
: schema
|
|
795
|
+
let variantSchema =
|
|
796
|
+
variantIndex >= 0 ? anyOf->Array.get(variantIndex)->Option.getOr(schema) : schema
|
|
806
797
|
switch deriveMutationFieldFromObject(
|
|
807
798
|
~fieldName,
|
|
808
799
|
~collectedTypes=types,
|
|
@@ -835,8 +826,7 @@ let generate = (
|
|
|
835
826
|
~collectedTypes=types,
|
|
836
827
|
~seenTypes,
|
|
837
828
|
schema,
|
|
838
|
-
)
|
|
839
|
-
->Option.forEach(field => mutations->Array.push(field))
|
|
829
|
+
)->Option.forEach(field => mutations->Array.push(field))
|
|
840
830
|
}
|
|
841
831
|
| _ => ()
|
|
842
832
|
}
|
|
@@ -981,8 +971,9 @@ let generate = (
|
|
|
981
971
|
let edgeName = entry.returnTypeName ++ "Edge"
|
|
982
972
|
seenTypes->Set.add(edgeName)
|
|
983
973
|
seenTypes->Set.add(connectionTypeName)
|
|
984
|
-
deriveConnectionTypes(~singularTypeName=entry.returnTypeName)
|
|
985
|
-
|
|
974
|
+
deriveConnectionTypes(~singularTypeName=entry.returnTypeName)->Array.forEach(t =>
|
|
975
|
+
types->Array.push(t)
|
|
976
|
+
)
|
|
986
977
|
}
|
|
987
978
|
let capability = deriveServerCapability(~entityName=entityNameOf(entry), entry.stateSchema)
|
|
988
979
|
let connectionFilterTypeName = entry.returnTypeName ++ "Filter"
|
|
@@ -992,8 +983,10 @@ let generate = (
|
|
|
992
983
|
deriveConnectionFilterType(~filterTypeName=connectionFilterTypeName, ~capability),
|
|
993
984
|
)
|
|
994
985
|
}
|
|
995
|
-
let orderByTypes =
|
|
996
|
-
|
|
986
|
+
let orderByTypes = deriveConnectionOrderByType(
|
|
987
|
+
~singularTypeName=entry.returnTypeName,
|
|
988
|
+
~capability,
|
|
989
|
+
)
|
|
997
990
|
let hasOrderBy = orderByTypes->Array.length > 0
|
|
998
991
|
if hasOrderBy {
|
|
999
992
|
let orderFieldEnumName = entry.returnTypeName ++ "OrderField"
|
|
@@ -1021,10 +1014,7 @@ let generate = (
|
|
|
1021
1014
|
)
|
|
1022
1015
|
types->Array.push(pluralType)
|
|
1023
1016
|
}
|
|
1024
|
-
let listField = deriveListQueryField(
|
|
1025
|
-
~listFieldName,
|
|
1026
|
-
~pluralTypeName=listFieldName,
|
|
1027
|
-
)
|
|
1017
|
+
let listField = deriveListQueryField(~listFieldName, ~pluralTypeName=listFieldName)
|
|
1028
1018
|
queries->Array.push(listField)
|
|
1029
1019
|
}
|
|
1030
1020
|
})
|
|
@@ -99,6 +99,10 @@ function fromSchemaType(_required, _asInputOpt, _st, collectedTypes, seenTypes)
|
|
|
99
99
|
_st = inner;
|
|
100
100
|
_asInputOpt = asInput;
|
|
101
101
|
continue;
|
|
102
|
+
case "Defaulted" :
|
|
103
|
+
_st = st._1;
|
|
104
|
+
_asInputOpt = asInput;
|
|
105
|
+
continue;
|
|
102
106
|
case "TaggedUnion" :
|
|
103
107
|
let name$3 = st._0;
|
|
104
108
|
if (asInput) {
|
|
@@ -232,11 +236,14 @@ function scalarOfSchemaType(_st) {
|
|
|
232
236
|
return "String";
|
|
233
237
|
}
|
|
234
238
|
} else {
|
|
235
|
-
|
|
236
|
-
|
|
239
|
+
switch (st.TAG) {
|
|
240
|
+
case "Semantic" :
|
|
241
|
+
case "Defaulted" :
|
|
242
|
+
_st = st._1;
|
|
243
|
+
continue;
|
|
244
|
+
default:
|
|
245
|
+
return "String";
|
|
237
246
|
}
|
|
238
|
-
_st = st._1;
|
|
239
|
-
continue;
|
|
240
247
|
}
|
|
241
248
|
};
|
|
242
249
|
}
|
|
@@ -19,7 +19,10 @@ let inspectScalar = (schema: S.t<'a>): string => {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
let inspectObjectType = (~typeName: string, schema: S.t<'a>): option<string> => {
|
|
22
|
-
let types = GraphQL_FragmentGenerator.deriveObjectTypeWithNested(
|
|
22
|
+
let types = GraphQL_FragmentGenerator.deriveObjectTypeWithNested(
|
|
23
|
+
~typeName,
|
|
24
|
+
schema->S.castToUnknown,
|
|
25
|
+
)
|
|
23
26
|
types->Array.get(types->Array.length - 1)
|
|
24
27
|
}
|
|
25
28
|
|
|
@@ -103,8 +106,7 @@ let inspectFragment = (fragment: Reventless.Plugin.apiSchemaFragment): fragmentI
|
|
|
103
106
|
| true => `type Mutation {\n${parts.mutations->Array.join("\n")}\n}`
|
|
104
107
|
| false => ""
|
|
105
108
|
}
|
|
106
|
-
let sdlParts =
|
|
107
|
-
[typesSdl, queriesSdl, mutationsSdl]->Array.filter(p => p->String.length > 0)
|
|
109
|
+
let sdlParts = [typesSdl, queriesSdl, mutationsSdl]->Array.filter(p => p->String.length > 0)
|
|
108
110
|
let sdlPreview = sdlParts->Array.join("\n\n")
|
|
109
111
|
{types: parts.types, mutations: parts.mutations, queries: parts.queries, sdlPreview}
|
|
110
112
|
}
|