@reventlessdev/reventless-core 3.0.0-alpha.238 → 3.0.0-alpha.240
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 +40 -0
- package/package.json +12 -12
- package/src/Message.res +11 -11
- package/src/Message.res.mjs +15 -14
- package/src/Projection.res +2 -2
- package/src/Projection.res.mjs +5 -4
- package/src/adapter/Monitoring/Monitoring.res +24 -2
- package/src/adapter/Monitoring/Monitoring.res.mjs +3 -3
- package/src/admin/Platform_AdminApi.res.mjs +3 -3
- package/src/admin/Platform_Admin_Structure.res +33 -112
- package/src/admin/Platform_Admin_Structure.res.mjs +8 -138
- package/src/admin/Platform_ComponentDefinitionsApi.res +2 -1
- package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +5 -1
- package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs +12 -12
- package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments.res.mjs +14 -14
- package/src/components/Aggregate/Aggregate_Callback.res +2 -2
- package/src/components/Aggregate/Aggregate_Callback.res.mjs +4 -4
- package/src/components/Api/ApiAllowedStatesHelpers.res.mjs +3 -3
- package/src/components/Api/ApiNoApiHelpers.res.mjs +5 -5
- package/src/components/Api/ApiTargetStateHelpers.res.mjs +3 -3
- package/src/components/Api/GraphQL_FragmentGenerator.res +140 -24
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +48 -21
- package/src/components/Api/GraphQL_SchemaInspector.res +1 -1
- package/src/components/Api/GraphQL_SchemaInspector.res.mjs +1 -1
- package/src/components/Api/MCP_SchemaGenerator.res +1 -1
- package/src/components/Api/MCP_SchemaGenerator.res.mjs +1 -1
- package/src/components/Api/SchemaType.res +6 -10
- package/src/components/Api/SchemaType.res.mjs +4 -4
- package/src/components/Api/StorageRefFields.res +1 -1
- package/src/components/Api/StorageRefFields.res.mjs +1 -1
- package/src/components/Api/SuryToJsonSchema.res +19 -0
- package/src/components/Api/SuryToJsonSchema.res.mjs +10 -5
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +3 -4
- package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +22 -23
- package/src/components/CommandTopic/CommandTopic_Callback.res +1 -2
- package/src/components/CommandTopic/CommandTopic_Callback.res.mjs +3 -4
- package/src/components/CommandTopic/CommandTopic_Helpers.res +1 -1
- package/src/components/CommandTopic/CommandTopic_Helpers.res.mjs +3 -3
- package/src/components/Counter/Counter.res.mjs +2 -2
- package/src/components/Counter/Counter_Callback.res.mjs +4 -4
- package/src/components/Counter/Counter_Operations.res.mjs +4 -4
- package/src/components/Dcb/Dcb_Builder.res +1 -1
- package/src/components/Dcb/Dcb_Builder.res.mjs +8 -6
- package/src/components/DcbEventLog/DcbEventLog_Builder.res.mjs +4 -3
- package/src/components/EventCollector/EventCollector_Builder.res +1 -1
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res +1 -2
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs +11 -12
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res +3 -4
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs +24 -25
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +1 -1
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res.mjs +3 -3
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +2 -2
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs +4 -4
- package/src/components/StateViewSlice/StateViewSlice_Builder.res +1 -1
- package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +3 -3
- package/src/plugin/api/PluginBaseFragment.res +12 -29
- package/src/plugin/api/PluginBaseFragment.res.mjs +3 -22
- package/src/plugin/component/Capability_Inference.res +118 -1
- package/src/plugin/component/Capability_Inference.res.mjs +128 -1
- package/src/plugin/component/Plugin_Builder.res +9 -2
- package/src/plugin/component/Plugin_Builder.res.mjs +5 -2
- package/src/plugin/component/Plugin_Helpers.res +11 -11
- package/src/plugin/component/Plugin_Helpers.res.mjs +11 -10
- package/src/plugin/component/Plugin_Structure.res +458 -296
- package/src/plugin/component/Plugin_Structure.res.mjs +259 -182
- package/src/plugin/component/Plugin_SubscriptionSchema.res +1 -1
- package/src/plugin/component/Plugin_SubscriptionSchema.res.mjs +1 -1
- package/src/plugin/component/SchemaWalker.res +11 -11
- package/src/plugin/component/SchemaWalker.res.mjs +8 -9
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +15 -15
- package/src/plugin/lifecycle/PluginBehavior.res.mjs +55 -55
- package/src/plugin/lifecycle/PluginSpec.res +22 -7
- package/src/plugin/lifecycle/PluginSpec.res.mjs +91 -36
- package/src/plugin/lifecycle/PluginsReadModelSpec.res +36 -9
- package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +33 -22
- package/src/util/Interstack.res +3 -3
- package/src/util/LogFormat.res +1 -2
- package/src/util/LogFormat.res.mjs +2 -2
- package/tests/IdentityTest.res +6 -7
- package/tests/IdentityTest.res.mjs +7 -9
- package/tests/adapter/MonitoringTest.res +30 -3
- package/tests/adapter/MonitoringTest.res.mjs +31 -12
- package/tests/adapter/RuntimeExtensionHookReachTest.res +0 -1
- package/tests/adapter/RuntimeExtensionHookReachTest.res.mjs +5 -7
- package/tests/admin/Platform_Admin_StructureTest.res +254 -0
- package/tests/admin/Platform_Admin_StructureTest.res.mjs +219 -0
- package/tests/admin/Platform_BakedManifestTest.res +1 -0
- package/tests/admin/Platform_BakedManifestTest.res.mjs +1 -0
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +3 -0
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +6 -0
- package/tests/admin/Platform_PluginStructuresApiTest.res +1 -0
- package/tests/admin/Platform_PluginStructuresApiTest.res.mjs +2 -0
- package/tests/aggregate/AggregateCacheTest.res +0 -1
- package/tests/aggregate/AggregateCacheTest.res.mjs +13 -15
- package/tests/aggregate/AggregateConflictTest.res +0 -1
- package/tests/aggregate/AggregateConflictTest.res.mjs +7 -9
- package/tests/aggregate/AggregateFixtures.res +0 -1
- package/tests/aggregate/AggregateFixtures.res.mjs +19 -21
- package/tests/aggregate/AggregateSnapshotTest.res +1 -2
- package/tests/aggregate/AggregateSnapshotTest.res.mjs +15 -16
- package/tests/api/ApiNoApiTest.res.mjs +17 -9
- package/tests/api/GraphQL_FragmentGeneratorTest.res +232 -0
- package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +207 -55
- package/tests/api/PsInternalFieldsReadModel.res +21 -0
- package/tests/api/PsInternalFieldsReadModel.res.mjs +74 -0
- package/tests/api/StorageRefFieldsTest.res.mjs +13 -13
- package/tests/api/SuryToJsonSchemaTest.res +73 -3
- package/tests/api/SuryToJsonSchemaTest.res.mjs +364 -816
- package/tests/commandgenerator/CommandGeneratorFixtures.res +0 -1
- package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +19 -21
- package/tests/commandgenerator/OwnerStampingTest.res +0 -1
- package/tests/commandgenerator/OwnerStampingTest.res.mjs +9 -11
- package/tests/commandtopic/CommandTopicCallbackFixtures.res +0 -1
- package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +7 -9
- package/tests/counter/CounterFixtures.res +0 -1
- package/tests/counter/CounterFixtures.res.mjs +1 -4
- package/tests/dcb/DcbDecodeTest.res.mjs +24 -24
- package/tests/dcb/DcbEventLogOperationsTest.res +2 -2
- package/tests/dcb/DcbEventLogOperationsTest.res.mjs +3 -3
- package/tests/dcb/DcbEventLogSchemaTest.res.mjs +7 -7
- package/tests/dcb/DcbFixtures.res +0 -1
- package/tests/dcb/DcbFixtures.res.mjs +87 -89
- package/tests/dcb/DcbTagTest.res.mjs +6 -6
- package/tests/dcb/DcbValidationTest.res.mjs +52 -52
- package/tests/eventlog/EventLogFixtures.res +0 -1
- package/tests/eventlog/EventLogFixtures.res.mjs +7 -9
- package/tests/eventmapper/EventMapperFixtures.res +0 -1
- package/tests/eventmapper/EventMapperFixtures.res.mjs +24 -26
- package/tests/eventtopic/EventTopicFixtures.res +0 -1
- package/tests/eventtopic/EventTopicFixtures.res.mjs +7 -9
- package/tests/extensionpoint/ExtensionPointFixtures.res +0 -1
- package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +10 -12
- package/tests/extensionpoint/ExtensionPointOperationsTest.res +1 -2
- package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +9 -10
- package/tests/logger/LogFormatTest.res +3 -2
- package/tests/logger/LogFormatTest.res.mjs +7 -9
- package/tests/message/MessageTest.res +2 -2
- package/tests/message/MessageTest.res.mjs +8 -7
- package/tests/message/MetaEnvelopeTest.res +5 -5
- package/tests/message/MetaEnvelopeTest.res.mjs +12 -11
- package/tests/plugin/ManifestVisibilityTest.res.mjs +7 -7
- package/tests/plugin/PluginDefinitionScalars.res +5 -3
- package/tests/plugin/PluginDefinitionScalars.res.mjs +2 -2
- package/tests/plugin/PluginLifecycleCorpusTest.res +4 -3
- package/tests/plugin/PluginLifecycleCorpusTest.res.mjs +3 -6
- package/tests/plugin/PluginSpecExperiment.res +0 -1
- package/tests/plugin/PluginSpecExperiment.res.mjs +12 -14
- package/tests/plugin/PluginStructureTest.res +292 -2
- package/tests/plugin/PluginStructureTest.res.mjs +391 -88
- package/tests/plugin/Plugin_EventQuerySchemaTest.res.mjs +3 -3
- package/tests/plugin/SchemaWalkerTest.res +0 -1
- package/tests/plugin/SchemaWalkerTest.res.mjs +17 -19
- package/tests/plugin/StateChangeSlice/PsAttachInvoice.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsDispatchShipment.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsGatedCommands.res.mjs +9 -9
- package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsReserveStock.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +15 -15
- package/tests/plugin/StateChangeSlice/PsTypoStore.res +31 -0
- package/tests/plugin/StateChangeSlice/PsTypoStore.res.mjs +62 -0
- package/tests/plugin/StateChangeSlice/PsUploadAvatar.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsUploadImages.res +40 -0
- package/tests/plugin/StateChangeSlice/PsUploadImages.res.mjs +66 -0
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +13 -12
- package/tests/plugin/StateViewSlice/PsAvailableProductsView.res.mjs +8 -8
- package/tests/plugin/StateViewSlice/PsCategoriesView.res.mjs +6 -6
- package/tests/plugin/StateViewSlice/PsCustomersView.res.mjs +10 -10
- package/tests/plugin/StateViewSlice/PsGatedView.res.mjs +6 -6
- package/tests/plugin/StateViewSlice/PsOrdersView.res.mjs +9 -9
- package/tests/plugin/StateViewSlice/PsShipmentsView.res.mjs +11 -10
- package/tests/plugin/pluginDefinitionRequiredScalars.txt +15 -0
- package/tests/querydb/QueryDbFixtures.res +0 -1
- package/tests/querydb/QueryDbFixtures.res.mjs +5 -7
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +0 -1
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +4 -6
- package/tests/util/CommandPublisherTest.res +0 -1
- package/tests/util/CommandPublisherTest.res.mjs +4 -6
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Sury from "sury";
|
|
4
4
|
import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
|
|
5
5
|
import * as Effect from "effect/Effect";
|
|
6
6
|
import * as Stream from "effect/Stream";
|
|
7
7
|
import * as Aggregate_Callback$ReventlessCore from "../../src/components/Aggregate/Aggregate_Callback.res.mjs";
|
|
8
8
|
|
|
9
|
-
S.enableJson();
|
|
10
|
-
|
|
11
9
|
let name = "ConflictTestAggregate";
|
|
12
10
|
|
|
13
|
-
let commandSchema =
|
|
11
|
+
let commandSchema = Sury.$schema(s => ({
|
|
14
12
|
TAG: "Create",
|
|
15
|
-
name: s.m(
|
|
13
|
+
name: s.m(Sury.string)
|
|
16
14
|
}));
|
|
17
15
|
|
|
18
|
-
let eventSchema =
|
|
16
|
+
let eventSchema = Sury.$schema(s => ({
|
|
19
17
|
TAG: "Created",
|
|
20
|
-
name: s.m(
|
|
18
|
+
name: s.m(Sury.string)
|
|
21
19
|
}));
|
|
22
20
|
|
|
23
|
-
let errorSchema =
|
|
21
|
+
let errorSchema = Sury.literal("AlreadyExists");
|
|
24
22
|
|
|
25
23
|
let moduleUrl = import.meta.url;
|
|
26
24
|
|
|
@@ -383,4 +381,4 @@ export {
|
|
|
383
381
|
testMeta,
|
|
384
382
|
makeTopicItem,
|
|
385
383
|
}
|
|
386
|
-
/*
|
|
384
|
+
/* commandSchema Not a pure module */
|
|
@@ -1,39 +1,37 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Sury from "sury";
|
|
4
4
|
import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
|
|
5
5
|
import * as Stream from "effect/Stream";
|
|
6
6
|
import * as Aggregate_Callback$ReventlessCore from "../../src/components/Aggregate/Aggregate_Callback.res.mjs";
|
|
7
7
|
|
|
8
|
-
S.enableJson();
|
|
9
|
-
|
|
10
8
|
let name = "TestAggregate";
|
|
11
9
|
|
|
12
|
-
let commandSchema =
|
|
13
|
-
|
|
10
|
+
let commandSchema = Sury.union([
|
|
11
|
+
Sury.$schema(s => ({
|
|
14
12
|
TAG: "Create",
|
|
15
|
-
name: s.m(
|
|
13
|
+
name: s.m(Sury.string)
|
|
16
14
|
})),
|
|
17
|
-
|
|
15
|
+
Sury.$schema(s => ({
|
|
18
16
|
TAG: "Rename",
|
|
19
|
-
newName: s.m(
|
|
17
|
+
newName: s.m(Sury.string)
|
|
20
18
|
}))
|
|
21
19
|
]);
|
|
22
20
|
|
|
23
|
-
let eventSchema =
|
|
24
|
-
|
|
21
|
+
let eventSchema = Sury.union([
|
|
22
|
+
Sury.$schema(s => ({
|
|
25
23
|
TAG: "Created",
|
|
26
|
-
name: s.m(
|
|
24
|
+
name: s.m(Sury.string)
|
|
27
25
|
})),
|
|
28
|
-
|
|
26
|
+
Sury.$schema(s => ({
|
|
29
27
|
TAG: "Renamed",
|
|
30
|
-
newName: s.m(
|
|
28
|
+
newName: s.m(Sury.string)
|
|
31
29
|
}))
|
|
32
30
|
]);
|
|
33
31
|
|
|
34
|
-
let errorSchema =
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
let errorSchema = Sury.union([
|
|
33
|
+
Sury.literal("AlreadyExists"),
|
|
34
|
+
Sury.literal("NotFound")
|
|
37
35
|
]);
|
|
38
36
|
|
|
39
37
|
let moduleUrl = import.meta.url;
|
|
@@ -52,11 +50,11 @@ let AggSpec = {
|
|
|
52
50
|
commandAuthorization: commandAuthorization
|
|
53
51
|
};
|
|
54
52
|
|
|
55
|
-
let stateSchema =
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
let stateSchema = Sury.union([
|
|
54
|
+
Sury.literal("NotCreated"),
|
|
55
|
+
Sury.$schema(s => ({
|
|
58
56
|
TAG: "Created",
|
|
59
|
-
name: s.m(
|
|
57
|
+
name: s.m(Sury.string)
|
|
60
58
|
}))
|
|
61
59
|
]);
|
|
62
60
|
|
|
@@ -305,4 +303,4 @@ export {
|
|
|
305
303
|
testMeta,
|
|
306
304
|
makeTopicItem,
|
|
307
305
|
}
|
|
308
|
-
/*
|
|
306
|
+
/* commandSchema Not a pure module */
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
open JestGlobals
|
|
14
14
|
|
|
15
|
-
S.enableJson()
|
|
16
15
|
|
|
17
16
|
module AggSpec = {
|
|
18
17
|
module Id = Reventless.Id.StringPure
|
|
@@ -300,7 +299,7 @@ describe("Aggregate_Callback — snapshots:", () => {
|
|
|
300
299
|
| Some(snap) =>
|
|
301
300
|
expect(snap.seqNr)->toBe(20)
|
|
302
301
|
// 20 items folded through the seeded state — no double-count, no gap.
|
|
303
|
-
let decoded = snap.state->
|
|
302
|
+
let decoded = snap.state->Reventless.Util_Sury.fromJson(TestBehavior.stateSchema)
|
|
304
303
|
expect(decoded.items->Array.length)->toBe(20)
|
|
305
304
|
| None => expect("expected snapshot at 20")->toBe("none")
|
|
306
305
|
}
|
|
@@ -1,31 +1,30 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Sury from "sury";
|
|
4
4
|
import * as Stream from "@reventlessdev/rescript-effect/src/Stream.res.mjs";
|
|
5
5
|
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
6
6
|
import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
|
|
7
7
|
import * as Effect from "effect/Effect";
|
|
8
8
|
import * as Stream$1 from "effect/Stream";
|
|
9
|
+
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
9
10
|
import * as Aggregate_Callback$ReventlessCore from "../../src/components/Aggregate/Aggregate_Callback.res.mjs";
|
|
10
11
|
|
|
11
|
-
S.enableJson();
|
|
12
|
-
|
|
13
12
|
let name = "SnapshotTestAggregate";
|
|
14
13
|
|
|
15
|
-
let commandSchema =
|
|
16
|
-
|
|
14
|
+
let commandSchema = Sury.union([
|
|
15
|
+
Sury.$schema(s => ({
|
|
17
16
|
TAG: "Add",
|
|
18
|
-
item: s.m(
|
|
17
|
+
item: s.m(Sury.string)
|
|
19
18
|
})),
|
|
20
|
-
|
|
19
|
+
Sury.literal("Noop")
|
|
21
20
|
]);
|
|
22
21
|
|
|
23
|
-
let eventSchema =
|
|
22
|
+
let eventSchema = Sury.$schema(s => ({
|
|
24
23
|
TAG: "Added",
|
|
25
|
-
item: s.m(
|
|
24
|
+
item: s.m(Sury.string)
|
|
26
25
|
}));
|
|
27
26
|
|
|
28
|
-
let errorSchema =
|
|
27
|
+
let errorSchema = Sury.literal("Never");
|
|
29
28
|
|
|
30
29
|
let moduleUrl = import.meta.url;
|
|
31
30
|
|
|
@@ -43,8 +42,8 @@ let AggSpec = {
|
|
|
43
42
|
commandAuthorization: commandAuthorization
|
|
44
43
|
};
|
|
45
44
|
|
|
46
|
-
let stateSchema =
|
|
47
|
-
items: s.m(
|
|
45
|
+
let stateSchema = Sury.$schema(s => ({
|
|
46
|
+
items: s.m(Sury.array(Sury.string))
|
|
48
47
|
}));
|
|
49
48
|
|
|
50
49
|
let initialState = {
|
|
@@ -325,8 +324,8 @@ let TestHandler = Aggregate_Callback$ReventlessCore.Make({
|
|
|
325
324
|
eventLog: eventLog
|
|
326
325
|
});
|
|
327
326
|
|
|
328
|
-
let stateSchema$1 =
|
|
329
|
-
items: s.m(
|
|
327
|
+
let stateSchema$1 = Sury.$schema(s => ({
|
|
328
|
+
items: s.m(Sury.array(Sury.string))
|
|
330
329
|
}));
|
|
331
330
|
|
|
332
331
|
let initialState$1 = {
|
|
@@ -550,7 +549,7 @@ globalThis.describe("Aggregate_Callback — snapshots:", () => {
|
|
|
550
549
|
let snap = mock.getSnapshot("agg-1");
|
|
551
550
|
if (snap !== undefined) {
|
|
552
551
|
globalThis.expect(snap.seqNr).toBe(20);
|
|
553
|
-
let decoded =
|
|
552
|
+
let decoded = Util_Sury$Reventless.fromJson(snap.state, stateSchema);
|
|
554
553
|
globalThis.expect(decoded.items.length).toBe(20);
|
|
555
554
|
} else {
|
|
556
555
|
globalThis.expect("expected snapshot at 20").toBe("none");
|
|
@@ -642,4 +641,4 @@ export {
|
|
|
642
641
|
run,
|
|
643
642
|
tick,
|
|
644
643
|
}
|
|
645
|
-
/*
|
|
644
|
+
/* commandSchema Not a pure module */
|
|
@@ -1,37 +1,42 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Sury from "sury";
|
|
4
4
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
5
|
import * as Api$ReventlessInfra from "@reventlessdev/reventless-infra/src/components/Api.res.mjs";
|
|
6
6
|
import * as ApiNoApiHelpers$ReventlessCore from "../../src/components/Api/ApiNoApiHelpers.res.mjs";
|
|
7
7
|
|
|
8
8
|
globalThis.describe("ApiNoApiHelpers:", () => {
|
|
9
9
|
globalThis.test("isNoApi returns false for schema without noApi metadata", () => {
|
|
10
|
-
|
|
10
|
+
let schema = Sury.string;
|
|
11
|
+
globalThis.expect(ApiNoApiHelpers$ReventlessCore.isNoApi(schema)).toBe(false);
|
|
11
12
|
});
|
|
12
13
|
globalThis.test("isNoApi returns true for schema with noApi metadata set to true", () => {
|
|
13
|
-
let schema
|
|
14
|
+
let schema = Sury.string;
|
|
15
|
+
let schema$p = Sury.$Metadata_set(schema, Api$ReventlessInfra.noApiId, true);
|
|
14
16
|
globalThis.expect(ApiNoApiHelpers$ReventlessCore.isNoApi(schema$p)).toBe(true);
|
|
15
17
|
});
|
|
16
18
|
globalThis.test("getExcludedVariants returns None for schema without noApiVariants metadata", () => {
|
|
17
|
-
|
|
19
|
+
let schema = Sury.string;
|
|
20
|
+
globalThis.expect(ApiNoApiHelpers$ReventlessCore.getExcludedVariants(schema)).toBe(undefined);
|
|
18
21
|
});
|
|
19
22
|
globalThis.test("getExcludedVariants returns Some with DeleteItem when set", () => {
|
|
23
|
+
let schema = Sury.string;
|
|
20
24
|
let excluded = new Set([
|
|
21
25
|
"DeleteItem",
|
|
22
26
|
"UpdateItem"
|
|
23
27
|
]);
|
|
24
|
-
let schema$p =
|
|
28
|
+
let schema$p = Sury.$Metadata_set(schema, Api$ReventlessInfra.noApiVariantsId, excluded);
|
|
25
29
|
let result = ApiNoApiHelpers$ReventlessCore.getExcludedVariants(schema$p);
|
|
26
30
|
globalThis.expect(Stdlib_Option.getOr(Stdlib_Option.map(result, set => set.has("DeleteItem")), false)).toBe(true);
|
|
27
31
|
});
|
|
28
32
|
globalThis.test("filterNoApiVariants returns all field names when no variants are excluded", () => {
|
|
33
|
+
let schema = Sury.string;
|
|
29
34
|
let fieldNames = [
|
|
30
35
|
"CreateItem",
|
|
31
36
|
"DeleteItem",
|
|
32
37
|
"UpdateItem"
|
|
33
38
|
];
|
|
34
|
-
let filtered = ApiNoApiHelpers$ReventlessCore.filterNoApiVariants(fieldNames,
|
|
39
|
+
let filtered = ApiNoApiHelpers$ReventlessCore.filterNoApiVariants(fieldNames, schema);
|
|
35
40
|
globalThis.expect(filtered).toEqual([
|
|
36
41
|
"CreateItem",
|
|
37
42
|
"DeleteItem",
|
|
@@ -39,8 +44,9 @@ globalThis.describe("ApiNoApiHelpers:", () => {
|
|
|
39
44
|
]);
|
|
40
45
|
});
|
|
41
46
|
globalThis.test("filterNoApiVariants filters out excluded variants", () => {
|
|
47
|
+
let schema = Sury.string;
|
|
42
48
|
let excluded = new Set(["DeleteItem"]);
|
|
43
|
-
let schema$p =
|
|
49
|
+
let schema$p = Sury.$Metadata_set(schema, Api$ReventlessInfra.noApiVariantsId, excluded);
|
|
44
50
|
let fieldNames = [
|
|
45
51
|
"CreateItem",
|
|
46
52
|
"DeleteItem",
|
|
@@ -53,11 +59,12 @@ globalThis.describe("ApiNoApiHelpers:", () => {
|
|
|
53
59
|
]);
|
|
54
60
|
});
|
|
55
61
|
globalThis.test("filterNoApiVariants filters out multiple excluded variants", () => {
|
|
62
|
+
let schema = Sury.string;
|
|
56
63
|
let excluded = new Set([
|
|
57
64
|
"DeleteItem",
|
|
58
65
|
"UpdateItem"
|
|
59
66
|
]);
|
|
60
|
-
let schema$p =
|
|
67
|
+
let schema$p = Sury.$Metadata_set(schema, Api$ReventlessInfra.noApiVariantsId, excluded);
|
|
61
68
|
let fieldNames = [
|
|
62
69
|
"CreateItem",
|
|
63
70
|
"DeleteItem",
|
|
@@ -71,12 +78,13 @@ globalThis.describe("ApiNoApiHelpers:", () => {
|
|
|
71
78
|
]);
|
|
72
79
|
});
|
|
73
80
|
globalThis.test("filterNoApiVariants returns empty array when all variants are excluded", () => {
|
|
81
|
+
let schema = Sury.string;
|
|
74
82
|
let excluded = new Set([
|
|
75
83
|
"CreateItem",
|
|
76
84
|
"DeleteItem",
|
|
77
85
|
"UpdateItem"
|
|
78
86
|
]);
|
|
79
|
-
let schema$p =
|
|
87
|
+
let schema$p = Sury.$Metadata_set(schema, Api$ReventlessInfra.noApiVariantsId, excluded);
|
|
80
88
|
let fieldNames = [
|
|
81
89
|
"CreateItem",
|
|
82
90
|
"DeleteItem",
|
|
@@ -340,3 +340,235 @@ describe("GraphQL_FragmentGenerator.mutationArgTypes", () => {
|
|
|
340
340
|
expect((mismatched, field->String.length > 0))->toEqual(([], true))
|
|
341
341
|
})
|
|
342
342
|
})
|
|
343
|
+
|
|
344
|
+
module RefDoorRow = {
|
|
345
|
+
@schema
|
|
346
|
+
type state = {id: string, name: string}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
let queryFor = (fragment, needle) =>
|
|
350
|
+
GraphQL_Stitcher.decode(fragment).queries->Array.find(q => q->String.includes(needle))
|
|
351
|
+
|
|
352
|
+
let refDoorFragment = (~subIdField=?) =>
|
|
353
|
+
GraphQL_FragmentGenerator.generate(
|
|
354
|
+
~mutationEntries=[],
|
|
355
|
+
~queryEntries=[
|
|
356
|
+
{
|
|
357
|
+
ReventlessInfra.Api.singleFieldName: "Catalog_Product",
|
|
358
|
+
listFieldName: "Catalog_Products",
|
|
359
|
+
returnTypeName: "Catalog_Product",
|
|
360
|
+
stateSchema: RefDoorRow.stateSchema->S.castToUnknown,
|
|
361
|
+
authorization: None,
|
|
362
|
+
connectionSpec: true,
|
|
363
|
+
subIdField: ?subIdField,
|
|
364
|
+
},
|
|
365
|
+
],
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
// What a caller holding a pointer to a withheld row may learn about it, and what
|
|
369
|
+
// the two doors that could never answer for one can now be asked.
|
|
370
|
+
describe("the reference door and the archive argument", () => {
|
|
371
|
+
|
|
372
|
+
// The narrowness is the type's, not a rule each backend re-implements: a caller
|
|
373
|
+
// cannot ask this door for a price, because there is no price on it.
|
|
374
|
+
testSync("projects a reference to id, label and the state that retired it", () => {
|
|
375
|
+
let sdl = GraphQL_FragmentGenerator.deriveRefTypeSdl(~returnTypeName="Catalog_Product")
|
|
376
|
+
expect((
|
|
377
|
+
sdl->String.includes("type Catalog_ProductRef"),
|
|
378
|
+
sdl->String.includes("label: String!"),
|
|
379
|
+
sdl->String.includes("retiredState: String"),
|
|
380
|
+
sdl->String.includes("price"),
|
|
381
|
+
))->toEqual((true, true, true, false))
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
// Emitted for every view rather than only the annotated ones, on the reasoning
|
|
385
|
+
// `includeRetired` already states: a field that appears with an annotation makes
|
|
386
|
+
// adding or removing it a breaking schema change.
|
|
387
|
+
testSync("names the door after the list field it resolves against", () =>
|
|
388
|
+
expect(
|
|
389
|
+
GraphQL_FragmentGenerator.deriveRefsQueryField(
|
|
390
|
+
~listFieldName="Catalog_Products",
|
|
391
|
+
~returnTypeName="Catalog_Product",
|
|
392
|
+
),
|
|
393
|
+
)->toEqual(" Catalog_ProductsRefs(ids: [ID!]!): [Catalog_ProductRef!]!")
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
// Every assertion above reads a `derive*` helper directly, which is how a door
|
|
397
|
+
// that no `generate` call emitted still passed them all: the SDL both AppSync
|
|
398
|
+
// APIs are built from comes from `generate`, while the adapter provisions a
|
|
399
|
+
// `<list>Refs` resolver per queryable on the premise that it is declared there.
|
|
400
|
+
// AppSync rejects a resolver for a field its schema does not have, so the
|
|
401
|
+
// mismatch surfaced as a failed deploy rather than a missing feature.
|
|
402
|
+
testSync("emits the door from generate, not only from the helper", () =>
|
|
403
|
+
expect((
|
|
404
|
+
queryFor(refDoorFragment(), "Catalog_ProductsRefs(ids: [ID!]!)")->Option.isSome,
|
|
405
|
+
typeDefFor(refDoorFragment(), "type Catalog_ProductRef")->Option.isSome,
|
|
406
|
+
))->toEqual((true, true))
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
// The condition the resolver side uses, mirrored: a composite-key view gets no
|
|
410
|
+
// door, because the read behind it is a BatchGetItem that would need both keys.
|
|
411
|
+
// Emitting the field for one would restore the same mismatch, reversed.
|
|
412
|
+
testSync("withholds the door from a composite-key view", () =>
|
|
413
|
+
expect((
|
|
414
|
+
queryFor(refDoorFragment(~subIdField="lineNo"), "Catalog_ProductsRefs")->Option.isSome,
|
|
415
|
+
typeDefFor(refDoorFragment(~subIdField="lineNo"), "type Catalog_ProductRef")->Option.isSome,
|
|
416
|
+
))->toEqual((false, false))
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
// The dead end this closes: the archive toggle put retired rows on screen and
|
|
420
|
+
// clicking one read a door that refused them to every caller alive, elevated
|
|
421
|
+
// included, because there was no way to ask.
|
|
422
|
+
testSync("lets the single-entity and by-ids doors be asked for the archive", () =>
|
|
423
|
+
expect((
|
|
424
|
+
GraphQL_FragmentGenerator.deriveObjectQueryField(
|
|
425
|
+
~singleFieldName="Catalog_Product",
|
|
426
|
+
~typeName="Catalog_Product",
|
|
427
|
+
)->String.includes("includeRetired: Boolean"),
|
|
428
|
+
GraphQL_FragmentGenerator.deriveByIdsQueryField(
|
|
429
|
+
~listFieldName="Catalog_Products",
|
|
430
|
+
~returnTypeName="Catalog_Product",
|
|
431
|
+
)->String.includes("includeRetired: Boolean"),
|
|
432
|
+
))->toEqual((true, true))
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
// A sub-id read keeps its sort-key argument beside the new one; dropping it
|
|
436
|
+
// would silently turn a two-key door into a one-key one.
|
|
437
|
+
testSync("keeps the sub-id argument when the view has one", () =>
|
|
438
|
+
expect(
|
|
439
|
+
GraphQL_FragmentGenerator.deriveObjectQueryField(
|
|
440
|
+
~singleFieldName="Ordering_OrderLine",
|
|
441
|
+
~typeName="Ordering_OrderLine",
|
|
442
|
+
~subIdField="lineNo",
|
|
443
|
+
),
|
|
444
|
+
)->toEqual(" Ordering_OrderLine(id: ID!, lineNo: String!, includeRetired: Boolean): Ordering_OrderLine")
|
|
445
|
+
)
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
// The by-index door is asserted whole rather than by `String.includes`, because
|
|
449
|
+
// what was wrong with it was never a missing substring: the field declared an
|
|
450
|
+
// `id` its resolver did not read and omitted the key its resolver did, so every
|
|
451
|
+
// part of the signature is load-bearing.
|
|
452
|
+
describe("the by-index door", () => {
|
|
453
|
+
let index = (~index, ~idField=?, ~subIdField=?): Reventless.ReadModel.indexConfig => {
|
|
454
|
+
index,
|
|
455
|
+
type_: "S",
|
|
456
|
+
idField: ?idField,
|
|
457
|
+
subIdField: ?subIdField,
|
|
458
|
+
projectionType: ALL,
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
testSync("takes the index value it filters on, and can be asked for the archive", () =>
|
|
462
|
+
expect(
|
|
463
|
+
GraphQL_FragmentGenerator.deriveIndexQueryField(
|
|
464
|
+
~singleFieldName="Catalog_Product",
|
|
465
|
+
~indexConfig=index(~index="categoryId"),
|
|
466
|
+
~connectionTypeName="Catalog_ProductConnection",
|
|
467
|
+
),
|
|
468
|
+
)->toEqual(
|
|
469
|
+
" Catalog_ProductByCategoryId(categoryId: String!, first: Int, after: String, last: Int, before: String, includeRetired: Boolean): Catalog_ProductConnection!",
|
|
470
|
+
)
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
// A named index has two different strings in play — `byOwner` names the index,
|
|
474
|
+
// `ownerId` names the column. The field is named after the first and keyed on
|
|
475
|
+
// the second, and swapping them is how the local adapter came to offer an
|
|
476
|
+
// argument the row had no field for.
|
|
477
|
+
testSync("names the field after the index and keys it on the column", () =>
|
|
478
|
+
expect(
|
|
479
|
+
GraphQL_FragmentGenerator.deriveIndexQueryField(
|
|
480
|
+
~singleFieldName="Ordering_Order",
|
|
481
|
+
~indexConfig=index(~index="byOwner", ~idField="ownerId"),
|
|
482
|
+
~connectionTypeName="Ordering_OrderConnection",
|
|
483
|
+
),
|
|
484
|
+
)->toEqual(
|
|
485
|
+
" Ordering_OrderByOwner(ownerId: String!, first: Int, after: String, last: Int, before: String, includeRetired: Boolean): Ordering_OrderConnection!",
|
|
486
|
+
)
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
// Optional, unlike the partition argument: naming the index value is the point
|
|
490
|
+
// of the door, narrowing to one sort value is a refinement.
|
|
491
|
+
testSync("offers the sort key the sort template has always read", () =>
|
|
492
|
+
expect(
|
|
493
|
+
GraphQL_FragmentGenerator.deriveIndexQueryField(
|
|
494
|
+
~singleFieldName="Ordering_Order",
|
|
495
|
+
~indexConfig=index(~index="byCustomer", ~idField="customerId", ~subIdField="placedAt"),
|
|
496
|
+
~connectionTypeName="Ordering_OrderConnection",
|
|
497
|
+
),
|
|
498
|
+
)->toEqual(
|
|
499
|
+
" Ordering_OrderByCustomer(customerId: String!, placedAt: String, first: Int, after: String, last: Int, before: String, includeRetired: Boolean): Ordering_OrderConnection!",
|
|
500
|
+
)
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
// One derivation, called by every backend. The local adapter used to spell the
|
|
504
|
+
// name out itself and produced `XByByOwner` where this produces `XByOwner`.
|
|
505
|
+
testSync("drops a leading `by` exactly once", () =>
|
|
506
|
+
expect((
|
|
507
|
+
GraphQL_FragmentGenerator.indexQueryFieldName(~singleFieldName="X", ~index="byOwner"),
|
|
508
|
+
GraphQL_FragmentGenerator.indexQueryFieldName(~singleFieldName="X", ~index="ownerId"),
|
|
509
|
+
GraphQL_FragmentGenerator.indexQueryFieldName(~singleFieldName="X", ~index="by"),
|
|
510
|
+
))->toEqual(("XByOwner", "XByOwnerId", "XByBy"))
|
|
511
|
+
)
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
// ── @internal: a field that is not on the GraphQL surface ────────────────────
|
|
515
|
+
//
|
|
516
|
+
// A read model's `@schema type state` is otherwise simultaneously the storage
|
|
517
|
+
// shape and the API shape. `@internal` separates them: the field stays in the
|
|
518
|
+
// record and in storage, and every generated object type drops it.
|
|
519
|
+
//
|
|
520
|
+
// The declaration is read off the schema rather than passed in, which is the
|
|
521
|
+
// point — the alternative is a hand-written exclude list beside the query entry,
|
|
522
|
+
// kept in step with the record by whoever next edits it. That is exactly what
|
|
523
|
+
// `PluginBaseFragment` maintained and what this replaces.
|
|
524
|
+
//
|
|
525
|
+
// The fixture is `PsInternalFieldsReadModel`, a spec file: the annotation machinery
|
|
526
|
+
// runs under `@@reventless.spec`.
|
|
527
|
+
|
|
528
|
+
describe("@internal keeps a field off the generated type", () => {
|
|
529
|
+
let stateSchema = PsInternalFieldsReadModel.stateSchema->S.castToUnknown
|
|
530
|
+
|
|
531
|
+
let types = (~excludeFields=?) =>
|
|
532
|
+
GraphQL_FragmentGenerator.deriveObjectTypeWithNested(
|
|
533
|
+
~typeName="Platform_Widget",
|
|
534
|
+
~excludeFields?,
|
|
535
|
+
stateSchema,
|
|
536
|
+
)->Array.join("\n")
|
|
537
|
+
|
|
538
|
+
testSync("the declared fields are absent", () =>
|
|
539
|
+
expect((
|
|
540
|
+
types()->String.includes("eventCollector"),
|
|
541
|
+
types()->String.includes("extensionNames"),
|
|
542
|
+
))->toEqual((false, false))
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
testSync("and everything else is untouched", () =>
|
|
546
|
+
expect((types()->String.includes("name"), types()->String.includes("itemId")))->toEqual((
|
|
547
|
+
true,
|
|
548
|
+
true,
|
|
549
|
+
))
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
// The caller's own exclusions still apply. The two lists answer different
|
|
553
|
+
// questions — one is a decision made where the entry is assembled, the other a
|
|
554
|
+
// declaration on the field — so the marker joins the list rather than
|
|
555
|
+
// replacing it.
|
|
556
|
+
testSync("a caller's excludeFields still applies alongside", () => {
|
|
557
|
+
let sdl = types(~excludeFields=["name"])
|
|
558
|
+
expect((sdl->String.includes("name"), sdl->String.includes("eventCollector")))->toEqual((
|
|
559
|
+
false,
|
|
560
|
+
false,
|
|
561
|
+
))
|
|
562
|
+
})
|
|
563
|
+
|
|
564
|
+
// The published state schema and the SDL have to agree, because AutoUI builds
|
|
565
|
+
// its list query from the former and sends it against the latter. This is the
|
|
566
|
+
// pairing that used to need two hand-maintained lists to hold.
|
|
567
|
+
testSync("the published state schema drops them too", () => {
|
|
568
|
+
let json = SuryToJsonSchema.deriveObjectSchema(stateSchema)->JSON.stringify
|
|
569
|
+
expect((json->String.includes("eventCollector"), json->String.includes("name")))->toEqual((
|
|
570
|
+
false,
|
|
571
|
+
true,
|
|
572
|
+
))
|
|
573
|
+
})
|
|
574
|
+
})
|