@reventlessdev/reventless-core 3.0.0-alpha.239 → 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 +28 -0
- package/package.json +9 -9
- 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 -113
- package/src/admin/Platform_Admin_Structure.res.mjs +8 -139
- 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 +18 -12
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +7 -13
- 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 +11 -0
- package/src/components/Api/SuryToJsonSchema.res.mjs +2 -1
- 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 +2 -2
- package/src/plugin/component/Plugin_Builder.res.mjs +2 -1
- 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 +349 -274
- package/src/plugin/component/Plugin_Structure.res.mjs +212 -175
- 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/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 +62 -1
- package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +102 -58
- 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 +43 -0
- package/tests/api/SuryToJsonSchemaTest.res.mjs +352 -849
- 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 +188 -1
- package/tests/plugin/PluginStructureTest.res.mjs +293 -102
- 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
|
@@ -368,7 +368,6 @@ let refDoorFragment = (~subIdField=?) =>
|
|
|
368
368
|
// What a caller holding a pointer to a withheld row may learn about it, and what
|
|
369
369
|
// the two doors that could never answer for one can now be asked.
|
|
370
370
|
describe("the reference door and the archive argument", () => {
|
|
371
|
-
open Expect
|
|
372
371
|
|
|
373
372
|
// The narrowness is the type's, not a rule each backend re-implements: a caller
|
|
374
373
|
// cannot ask this door for a price, because there is no price on it.
|
|
@@ -511,3 +510,65 @@ describe("the by-index door", () => {
|
|
|
511
510
|
))->toEqual(("XByOwner", "XByOwnerId", "XByBy"))
|
|
512
511
|
)
|
|
513
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
|
+
})
|
|
@@ -1,20 +1,22 @@
|
|
|
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 Money$Reventless from "@reventlessdev/reventless-spec/src/semantic/Money.res.mjs";
|
|
6
6
|
import * as GraphQL_Stitcher$ReventlessCore from "../../src/components/Api/GraphQL_Stitcher.res.mjs";
|
|
7
|
+
import * as SuryToJsonSchema$ReventlessCore from "../../src/components/Api/SuryToJsonSchema.res.mjs";
|
|
7
8
|
import * as GraphQL_FragmentGenerator$ReventlessCore from "../../src/components/Api/GraphQL_FragmentGenerator.res.mjs";
|
|
9
|
+
import * as PsInternalFieldsReadModel$ReventlessCore from "./PsInternalFieldsReadModel.res.mjs";
|
|
8
10
|
import * as OutboundTranslationSlice_Callback$ReventlessCore from "../../src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs";
|
|
9
11
|
|
|
10
|
-
let commandSchema =
|
|
11
|
-
|
|
12
|
+
let commandSchema = Sury.union([
|
|
13
|
+
Sury.$schema(s => ({
|
|
12
14
|
TAG: "CancelOrder",
|
|
13
|
-
orderId: s.m(
|
|
15
|
+
orderId: s.m(Sury.string)
|
|
14
16
|
})),
|
|
15
|
-
|
|
17
|
+
Sury.$schema(s => ({
|
|
16
18
|
TAG: "ReopenOrder",
|
|
17
|
-
orderId: s.m(
|
|
19
|
+
orderId: s.m(Sury.string)
|
|
18
20
|
}))
|
|
19
21
|
]);
|
|
20
22
|
|
|
@@ -52,9 +54,9 @@ globalThis.describe("GraphQL_FragmentGenerator.generate mutation id injection",
|
|
|
52
54
|
});
|
|
53
55
|
});
|
|
54
56
|
|
|
55
|
-
let outboundItemSchema =
|
|
56
|
-
customerId: s.m(
|
|
57
|
-
address: s.m(
|
|
57
|
+
let outboundItemSchema = Sury.$schema(s => ({
|
|
58
|
+
customerId: s.m(Sury.string),
|
|
59
|
+
address: s.m(Sury.string)
|
|
58
60
|
}));
|
|
59
61
|
|
|
60
62
|
let GeocodeItem = {
|
|
@@ -86,9 +88,9 @@ globalThis.describe("GraphQL_FragmentGenerator slice TODO rows", () => {
|
|
|
86
88
|
|
|
87
89
|
globalThis.describe("resolveKeyField — the ladder", () => {
|
|
88
90
|
globalThis.test("a lone `*Id` field is the only thing the key could be", () => {
|
|
89
|
-
let schema =
|
|
90
|
-
productId: s.m(
|
|
91
|
-
name: s.m(
|
|
91
|
+
let schema = Sury.$schema(s => ({
|
|
92
|
+
productId: s.m(Sury.string),
|
|
93
|
+
name: s.m(Sury.string)
|
|
92
94
|
}));
|
|
93
95
|
globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("AvailableProducts", schema)).toEqual([
|
|
94
96
|
"productId",
|
|
@@ -96,9 +98,9 @@ globalThis.describe("resolveKeyField — the ladder", () => {
|
|
|
96
98
|
]);
|
|
97
99
|
});
|
|
98
100
|
globalThis.test("several `*Id` fields are disambiguated by the component name", () => {
|
|
99
|
-
let schema =
|
|
100
|
-
productId: s.m(
|
|
101
|
-
categoryId: s.m(
|
|
101
|
+
let schema = Sury.$schema(s => ({
|
|
102
|
+
productId: s.m(Sury.string),
|
|
103
|
+
categoryId: s.m(Sury.string)
|
|
102
104
|
}));
|
|
103
105
|
globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("Products", schema)).toEqual([
|
|
104
106
|
"productId",
|
|
@@ -106,9 +108,9 @@ globalThis.describe("resolveKeyField — the ladder", () => {
|
|
|
106
108
|
]);
|
|
107
109
|
});
|
|
108
110
|
globalThis.test("the convention rung singularises the way Api_Naming does", () => {
|
|
109
|
-
let schema =
|
|
110
|
-
categoryId: s.m(
|
|
111
|
-
ownerId: s.m(
|
|
111
|
+
let schema = Sury.$schema(s => ({
|
|
112
|
+
categoryId: s.m(Sury.string),
|
|
113
|
+
ownerId: s.m(Sury.string)
|
|
112
114
|
}));
|
|
113
115
|
globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("Categories", schema)).toEqual([
|
|
114
116
|
"categoryId",
|
|
@@ -116,23 +118,23 @@ globalThis.describe("resolveKeyField — the ladder", () => {
|
|
|
116
118
|
]);
|
|
117
119
|
});
|
|
118
120
|
globalThis.test("several `*Id` fields with no name match declines", () => {
|
|
119
|
-
let schema =
|
|
120
|
-
productId: s.m(
|
|
121
|
-
categoryId: s.m(
|
|
121
|
+
let schema = Sury.$schema(s => ({
|
|
122
|
+
productId: s.m(Sury.string),
|
|
123
|
+
categoryId: s.m(Sury.string)
|
|
122
124
|
}));
|
|
123
125
|
globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("ProductDemand", schema)).toEqual(undefined);
|
|
124
126
|
});
|
|
125
127
|
globalThis.test("no `*Id` field at all declines", () => {
|
|
126
|
-
let schema =
|
|
127
|
-
email: s.m(
|
|
128
|
-
address: s.m(
|
|
128
|
+
let schema = Sury.$schema(s => ({
|
|
129
|
+
email: s.m(Sury.string),
|
|
130
|
+
address: s.m(Sury.string)
|
|
129
131
|
}));
|
|
130
132
|
globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("Customers", schema)).toEqual(undefined);
|
|
131
133
|
});
|
|
132
134
|
globalThis.test("a word merely ending in `id` is not a key", () => {
|
|
133
|
-
let schema =
|
|
134
|
-
paid: s.m(
|
|
135
|
-
valid: s.m(
|
|
135
|
+
let schema = Sury.$schema(s => ({
|
|
136
|
+
paid: s.m(Sury.string),
|
|
137
|
+
valid: s.m(Sury.string)
|
|
136
138
|
}));
|
|
137
139
|
globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.resolveKeyField("Invoices", schema)).toEqual(undefined);
|
|
138
140
|
});
|
|
@@ -140,17 +142,17 @@ globalThis.describe("resolveKeyField — the ladder", () => {
|
|
|
140
142
|
|
|
141
143
|
globalThis.describe("deriveServerCapability — inferred keys reach the SDL surface", () => {
|
|
142
144
|
globalThis.test("an inferred key yields an eq filter and a sort field", () => {
|
|
143
|
-
let schema =
|
|
144
|
-
orderId: s.m(
|
|
145
|
-
total: s.m(
|
|
145
|
+
let schema = Sury.$schema(s => ({
|
|
146
|
+
orderId: s.m(Sury.string),
|
|
147
|
+
total: s.m(Sury.float)
|
|
146
148
|
}));
|
|
147
149
|
let c = GraphQL_FragmentGenerator$ReventlessCore.deriveServerCapability("Orders", schema);
|
|
148
150
|
globalThis.expect(c.filterFields.map(f => f.name)).toEqual(["orderId"]);
|
|
149
151
|
globalThis.expect(c.sortFields).toEqual(["orderId"]);
|
|
150
152
|
});
|
|
151
153
|
globalThis.test("an unresolvable key still yields nothing — the old behaviour, now narrowed", () => {
|
|
152
|
-
let schema =
|
|
153
|
-
email: s.m(
|
|
154
|
+
let schema = Sury.$schema(s => ({
|
|
155
|
+
email: s.m(Sury.string)
|
|
154
156
|
}));
|
|
155
157
|
let c = GraphQL_FragmentGenerator$ReventlessCore.deriveServerCapability("Customers", schema);
|
|
156
158
|
globalThis.expect([
|
|
@@ -162,15 +164,15 @@ globalThis.describe("deriveServerCapability — inferred keys reach the SDL surf
|
|
|
162
164
|
]);
|
|
163
165
|
});
|
|
164
166
|
globalThis.test("the filter input carries the inferred key's eq field", () => {
|
|
165
|
-
let schema =
|
|
166
|
-
orderId: s.m(
|
|
167
|
+
let schema = Sury.$schema(s => ({
|
|
168
|
+
orderId: s.m(Sury.string)
|
|
167
169
|
}));
|
|
168
170
|
let input = GraphQL_FragmentGenerator$ReventlessCore.deriveConnectionFilterType("Ordering_OrderFilter", GraphQL_FragmentGenerator$ReventlessCore.deriveServerCapability("Orders", schema));
|
|
169
171
|
globalThis.expect(input.includes("orderIdEq: ID")).toBe(true);
|
|
170
172
|
});
|
|
171
173
|
globalThis.test("the order-by pair exists because of the inferred key", () => {
|
|
172
|
-
let schema =
|
|
173
|
-
orderId: s.m(
|
|
174
|
+
let schema = Sury.$schema(s => ({
|
|
175
|
+
orderId: s.m(Sury.string)
|
|
174
176
|
}));
|
|
175
177
|
let types = GraphQL_FragmentGenerator$ReventlessCore.deriveConnectionOrderByType("Ordering_Order", GraphQL_FragmentGenerator$ReventlessCore.deriveServerCapability("Orders", schema));
|
|
176
178
|
globalThis.expect(types.length).toBe(2);
|
|
@@ -178,15 +180,15 @@ globalThis.describe("deriveServerCapability — inferred keys reach the SDL surf
|
|
|
178
180
|
});
|
|
179
181
|
});
|
|
180
182
|
|
|
181
|
-
let commandSchema$1 =
|
|
182
|
-
|
|
183
|
+
let commandSchema$1 = Sury.union([
|
|
184
|
+
Sury.$schema(s => ({
|
|
183
185
|
TAG: "AddProduct",
|
|
184
|
-
productId: s.m(
|
|
186
|
+
productId: s.m(Sury.string),
|
|
185
187
|
price: s.m(Money$Reventless.schema)
|
|
186
188
|
})),
|
|
187
|
-
|
|
189
|
+
Sury.$schema(s => ({
|
|
188
190
|
TAG: "ArchiveProduct",
|
|
189
|
-
productId: s.m(
|
|
191
|
+
productId: s.m(Sury.string)
|
|
190
192
|
}))
|
|
191
193
|
]);
|
|
192
194
|
|
|
@@ -199,15 +201,15 @@ let AddProductCmd = {
|
|
|
199
201
|
commandAuthorization: commandAuthorization$1
|
|
200
202
|
};
|
|
201
203
|
|
|
202
|
-
let commandSchema$2 =
|
|
203
|
-
|
|
204
|
+
let commandSchema$2 = Sury.union([
|
|
205
|
+
Sury.$schema(s => ({
|
|
204
206
|
TAG: "ChangeProductPrice",
|
|
205
|
-
productId: s.m(
|
|
207
|
+
productId: s.m(Sury.string),
|
|
206
208
|
price: s.m(Money$Reventless.schema)
|
|
207
209
|
})),
|
|
208
|
-
|
|
210
|
+
Sury.$schema(s => ({
|
|
209
211
|
TAG: "ClearProductPrice",
|
|
210
|
-
productId: s.m(
|
|
212
|
+
productId: s.m(Sury.string)
|
|
211
213
|
}))
|
|
212
214
|
]);
|
|
213
215
|
|
|
@@ -244,8 +246,8 @@ globalThis.describe("semantic composites are named once, not once per field", ()
|
|
|
244
246
|
globalThis.expect(fragmentTypes.some(t => t.includes("AddProductPrice"))).toBe(false);
|
|
245
247
|
});
|
|
246
248
|
globalThis.test("the output position keeps the bare name", () => {
|
|
247
|
-
let types = GraphQL_FragmentGenerator$ReventlessCore.deriveObjectTypeWithNested("Catalog_Product", undefined, false,
|
|
248
|
-
productId: s.m(
|
|
249
|
+
let types = GraphQL_FragmentGenerator$ReventlessCore.deriveObjectTypeWithNested("Catalog_Product", undefined, false, Sury.$schema(s => ({
|
|
250
|
+
productId: s.m(Sury.string),
|
|
249
251
|
price: s.m(Money$Reventless.schema)
|
|
250
252
|
})));
|
|
251
253
|
globalThis.expect([
|
|
@@ -260,17 +262,17 @@ globalThis.describe("semantic composites are named once, not once per field", ()
|
|
|
260
262
|
});
|
|
261
263
|
});
|
|
262
264
|
|
|
263
|
-
let shippingMethodSchema =
|
|
264
|
-
|
|
265
|
-
|
|
265
|
+
let shippingMethodSchema = Sury.union([
|
|
266
|
+
Sury.literal("Standard"),
|
|
267
|
+
Sury.literal("Express")
|
|
266
268
|
]);
|
|
267
269
|
|
|
268
|
-
let schema =
|
|
269
|
-
orderId: s.m(
|
|
270
|
+
let schema = Sury.$schema(s => ({
|
|
271
|
+
orderId: s.m(Sury.string),
|
|
270
272
|
shippingMethod: s.m(shippingMethodSchema),
|
|
271
273
|
total: s.m(Money$Reventless.schema),
|
|
272
|
-
tip: s.m(
|
|
273
|
-
itemCount: s.m(
|
|
274
|
+
tip: s.m(Sury.$option(Money$Reventless.schema)),
|
|
275
|
+
itemCount: s.m(Sury.int)
|
|
274
276
|
}));
|
|
275
277
|
|
|
276
278
|
let PlaceOrder = {
|
|
@@ -322,9 +324,9 @@ globalThis.describe("GraphQL_FragmentGenerator.mutationArgTypes", () => {
|
|
|
322
324
|
});
|
|
323
325
|
});
|
|
324
326
|
|
|
325
|
-
let stateSchema =
|
|
326
|
-
id: s.m(
|
|
327
|
-
name: s.m(
|
|
327
|
+
let stateSchema = Sury.$schema(s => ({
|
|
328
|
+
id: s.m(Sury.string),
|
|
329
|
+
name: s.m(Sury.string)
|
|
328
330
|
}));
|
|
329
331
|
|
|
330
332
|
let RefDoorRow = {
|
|
@@ -427,6 +429,48 @@ globalThis.describe("the by-index door", () => {
|
|
|
427
429
|
});
|
|
428
430
|
});
|
|
429
431
|
|
|
432
|
+
globalThis.describe("@internal keeps a field off the generated type", () => {
|
|
433
|
+
let types = excludeFields => GraphQL_FragmentGenerator$ReventlessCore.deriveObjectTypeWithNested("Platform_Widget", excludeFields, undefined, PsInternalFieldsReadModel$ReventlessCore.stateSchema).join("\n");
|
|
434
|
+
globalThis.test("the declared fields are absent", () => {
|
|
435
|
+
globalThis.expect([
|
|
436
|
+
types(undefined).includes("eventCollector"),
|
|
437
|
+
types(undefined).includes("extensionNames")
|
|
438
|
+
]).toEqual([
|
|
439
|
+
false,
|
|
440
|
+
false
|
|
441
|
+
]);
|
|
442
|
+
});
|
|
443
|
+
globalThis.test("and everything else is untouched", () => {
|
|
444
|
+
globalThis.expect([
|
|
445
|
+
types(undefined).includes("name"),
|
|
446
|
+
types(undefined).includes("itemId")
|
|
447
|
+
]).toEqual([
|
|
448
|
+
true,
|
|
449
|
+
true
|
|
450
|
+
]);
|
|
451
|
+
});
|
|
452
|
+
globalThis.test("a caller's excludeFields still applies alongside", () => {
|
|
453
|
+
let sdl = types(["name"]);
|
|
454
|
+
globalThis.expect([
|
|
455
|
+
sdl.includes("name"),
|
|
456
|
+
sdl.includes("eventCollector")
|
|
457
|
+
]).toEqual([
|
|
458
|
+
false,
|
|
459
|
+
false
|
|
460
|
+
]);
|
|
461
|
+
});
|
|
462
|
+
globalThis.test("the published state schema drops them too", () => {
|
|
463
|
+
let json = JSON.stringify(SuryToJsonSchema$ReventlessCore.deriveObjectSchema(PsInternalFieldsReadModel$ReventlessCore.stateSchema));
|
|
464
|
+
globalThis.expect([
|
|
465
|
+
json.includes("eventCollector"),
|
|
466
|
+
json.includes("name")
|
|
467
|
+
]).toEqual([
|
|
468
|
+
false,
|
|
469
|
+
true
|
|
470
|
+
]);
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
|
|
430
474
|
export {
|
|
431
475
|
OrderSliceCmd,
|
|
432
476
|
mutationFor,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Fixture for `@internal`: a state record whose storage shape and API shape
|
|
2
|
+
// differ. `eventCollector` and `extensionNames` are projected and stored and
|
|
3
|
+
// belong on no generated surface; everything else is ordinary.
|
|
4
|
+
//
|
|
5
|
+
// A spec file rather than a module inside the test, and named `*ReadModel*`
|
|
6
|
+
// deliberately: the annotation machinery runs under `@@reventless.spec` AND only
|
|
7
|
+
// for a file the PPX recognises as a read model or state view. That is also the
|
|
8
|
+
// honest scope for `@internal` — it describes a read model's state.
|
|
9
|
+
|
|
10
|
+
@@reventless.spec("InternalFieldsReadModel")
|
|
11
|
+
|
|
12
|
+
@schema
|
|
13
|
+
type consumedEvent = ItemRecorded({itemId: string, name: string})
|
|
14
|
+
|
|
15
|
+
@schema
|
|
16
|
+
type state = {
|
|
17
|
+
@id itemId: string,
|
|
18
|
+
name: string,
|
|
19
|
+
@internal eventCollector: string,
|
|
20
|
+
@internal extensionNames: array<string>,
|
|
21
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Sury from "sury";
|
|
4
|
+
import * as ReadModel$Reventless from "@reventlessdev/reventless-spec/src/components/ReadModel.res.mjs";
|
|
5
|
+
import * as StateAnnotations$Reventless from "@reventlessdev/reventless-spec/src/components/StateAnnotations.res.mjs";
|
|
6
|
+
|
|
7
|
+
let consumedEventSchema = Sury.$schema(s => ({
|
|
8
|
+
TAG: "ItemRecorded",
|
|
9
|
+
itemId: s.m(Sury.string),
|
|
10
|
+
name: s.m(Sury.string)
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
let stateSchema = Sury.$schema(s => ({
|
|
14
|
+
itemId: s.m(Sury.string),
|
|
15
|
+
name: s.m(Sury.string),
|
|
16
|
+
eventCollector: s.m(Sury.string),
|
|
17
|
+
extensionNames: s.m(Sury.array(Sury.string))
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
let config = ReadModel$Reventless.config(undefined, undefined, undefined);
|
|
21
|
+
|
|
22
|
+
let makeId = (state => state.itemId);
|
|
23
|
+
|
|
24
|
+
let stateSchema$1 = Sury.$Metadata_set(stateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
|
|
25
|
+
ids: ["itemId"],
|
|
26
|
+
compositeIds: [],
|
|
27
|
+
subIds: [],
|
|
28
|
+
compositeSubIds: [],
|
|
29
|
+
indexes: [],
|
|
30
|
+
hidden: [],
|
|
31
|
+
summary: [],
|
|
32
|
+
internal: [
|
|
33
|
+
"eventCollector",
|
|
34
|
+
"extensionNames"
|
|
35
|
+
],
|
|
36
|
+
drillTargets: [],
|
|
37
|
+
drillTargetKeys: [],
|
|
38
|
+
collapsed: [],
|
|
39
|
+
scan: [],
|
|
40
|
+
scanSort: [],
|
|
41
|
+
semantic: [],
|
|
42
|
+
metric: [],
|
|
43
|
+
lifecycle: undefined,
|
|
44
|
+
groupBy: undefined,
|
|
45
|
+
visibility: undefined,
|
|
46
|
+
live: undefined,
|
|
47
|
+
retired: undefined
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
let name = "InternalFieldsReadModel";
|
|
51
|
+
|
|
52
|
+
let Id;
|
|
53
|
+
|
|
54
|
+
let subIdConfig;
|
|
55
|
+
|
|
56
|
+
let moduleUrl = "@reventlessdev/reventless-core/tests/api/PsInternalFieldsReadModel.res.mjs";
|
|
57
|
+
|
|
58
|
+
let authorization = "AllowAuthenticated";
|
|
59
|
+
|
|
60
|
+
let visibility = "Public";
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
name,
|
|
64
|
+
Id,
|
|
65
|
+
consumedEventSchema,
|
|
66
|
+
config,
|
|
67
|
+
subIdConfig,
|
|
68
|
+
makeId,
|
|
69
|
+
stateSchema$1 as stateSchema,
|
|
70
|
+
moduleUrl,
|
|
71
|
+
authorization,
|
|
72
|
+
visibility,
|
|
73
|
+
}
|
|
74
|
+
/* consumedEventSchema Not a pure module */
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Sury from "sury";
|
|
4
4
|
import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
|
|
5
5
|
import * as StorageRefFields$ReventlessCore from "../../src/components/Api/StorageRefFields.res.mjs";
|
|
6
6
|
|
|
7
7
|
function variant(tag, fields) {
|
|
8
|
-
return
|
|
9
|
-
s.f("TAG",
|
|
8
|
+
return Sury.object(s => {
|
|
9
|
+
s.f("TAG", Sury.literal(tag));
|
|
10
10
|
fields.forEach(param => {
|
|
11
11
|
s.f(param[0], param[1]);
|
|
12
12
|
});
|
|
@@ -17,7 +17,7 @@ let ref_ = StorageRef$Reventless.forStore;
|
|
|
17
17
|
|
|
18
18
|
globalThis.describe("StorageRefFields.fromEventSchema", () => {
|
|
19
19
|
globalThis.test("finds a declared single-valued ref field and qualifies its store", () => {
|
|
20
|
-
let schema =
|
|
20
|
+
let schema = Sury.union([variant("ProductImageChanged", [[
|
|
21
21
|
"imageUrl",
|
|
22
22
|
StorageRef$Reventless.forStore(undefined, "productImages")
|
|
23
23
|
]])]);
|
|
@@ -31,16 +31,16 @@ globalThis.describe("StorageRefFields.fromEventSchema", () => {
|
|
|
31
31
|
}]);
|
|
32
32
|
});
|
|
33
33
|
globalThis.test("a qualified declaration keeps the store it names", () => {
|
|
34
|
-
let schema =
|
|
34
|
+
let schema = Sury.union([variant("OrderPhotoAttached", [[
|
|
35
35
|
"photo",
|
|
36
36
|
StorageRef$Reventless.forStore("Catalog", "productImages")
|
|
37
37
|
]])]);
|
|
38
38
|
globalThis.expect(StorageRefFields$ReventlessCore.fromEventSchema("Ordering", schema).flatMap(e => e.fields.map(f => f.store))).toEqual(["Catalog.productImages"]);
|
|
39
39
|
});
|
|
40
40
|
globalThis.test("finds a multi-valued ref field and records its arity", () => {
|
|
41
|
-
let schema =
|
|
41
|
+
let schema = Sury.union([variant("GalleryReplaced", [[
|
|
42
42
|
"imageUrls",
|
|
43
|
-
|
|
43
|
+
Sury.array(StorageRef$Reventless.forStore(undefined, "productImages"))
|
|
44
44
|
]])]);
|
|
45
45
|
globalThis.expect(StorageRefFields$ReventlessCore.fromEventSchema("Catalog", schema).flatMap(e => e.fields)).toEqual([{
|
|
46
46
|
field: "imageUrls",
|
|
@@ -49,10 +49,10 @@ globalThis.describe("StorageRefFields.fromEventSchema", () => {
|
|
|
49
49
|
}]);
|
|
50
50
|
});
|
|
51
51
|
globalThis.test("a variant with no declared field is omitted entirely", () => {
|
|
52
|
-
let schema =
|
|
52
|
+
let schema = Sury.union([
|
|
53
53
|
variant("ProductRenamed", [[
|
|
54
54
|
"name",
|
|
55
|
-
|
|
55
|
+
Sury.string
|
|
56
56
|
]]),
|
|
57
57
|
variant("ProductImageChanged", [[
|
|
58
58
|
"imageUrl",
|
|
@@ -62,16 +62,16 @@ globalThis.describe("StorageRefFields.fromEventSchema", () => {
|
|
|
62
62
|
globalThis.expect(StorageRefFields$ReventlessCore.fromEventSchema("Catalog", schema).map(e => e.eventType)).toEqual(["ProductImageChanged"]);
|
|
63
63
|
});
|
|
64
64
|
globalThis.test("an event schema with no declaration anywhere yields nothing", () => {
|
|
65
|
-
let schema =
|
|
65
|
+
let schema = Sury.union([variant("ProductRenamed", [[
|
|
66
66
|
"name",
|
|
67
|
-
|
|
67
|
+
Sury.string
|
|
68
68
|
]])]);
|
|
69
69
|
globalThis.expect(StorageRefFields$ReventlessCore.fromEventSchema("Catalog", schema)).toEqual([]);
|
|
70
70
|
});
|
|
71
71
|
globalThis.test("an unannotated string field is not treated as a ref", () => {
|
|
72
|
-
let schema =
|
|
72
|
+
let schema = Sury.union([variant("ProductImported", [[
|
|
73
73
|
"imageUrl",
|
|
74
|
-
|
|
74
|
+
Sury.string
|
|
75
75
|
]])]);
|
|
76
76
|
globalThis.expect(StorageRefFields$ReventlessCore.fromEventSchema("Catalog", schema)).toEqual([]);
|
|
77
77
|
});
|
|
@@ -256,6 +256,49 @@ describe("SuryToJsonSchema:", () => {
|
|
|
256
256
|
))->toEqual((Some(true), None))
|
|
257
257
|
})
|
|
258
258
|
|
|
259
|
+
// `@internal` drops the property rather than marking it. A marker is the
|
|
260
|
+
// right answer for a field that is on the surface and merely unwanted — that
|
|
261
|
+
// is `@hidden`, above. This one is not on the surface at all, so an entry
|
|
262
|
+
// here would describe a field the SDL does not declare, which is the
|
|
263
|
+
// mismatch that makes a generated list query name fields the server rejects.
|
|
264
|
+
testSync("drops a field listed in internal rather than annotating it", () => {
|
|
265
|
+
let schema = S.schema(s =>
|
|
266
|
+
{
|
|
267
|
+
"id": s.matches(S.string),
|
|
268
|
+
"eventCollector": s.matches(S.string),
|
|
269
|
+
}
|
|
270
|
+
)->S.castToUnknown
|
|
271
|
+
let schema' = schema->withSpec({...emptySpec, internal: ["eventCollector"]})
|
|
272
|
+
let json = SuryToJsonSchema.deriveObjectSchema(schema')
|
|
273
|
+
expect((
|
|
274
|
+
getPropertyOf(json, "eventCollector")->Option.isNone,
|
|
275
|
+
getPropertyOf(json, "id")->Option.isSome,
|
|
276
|
+
))->toEqual((true, true))
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
// A dropped property must not be left behind in `required`, or a consumer
|
|
280
|
+
// building a form from the schema asks for a field it was never given.
|
|
281
|
+
testSync("keeps a dropped field out of required", () => {
|
|
282
|
+
let schema = S.schema(s =>
|
|
283
|
+
{
|
|
284
|
+
"id": s.matches(S.string),
|
|
285
|
+
"eventCollector": s.matches(S.string),
|
|
286
|
+
}
|
|
287
|
+
)->S.castToUnknown
|
|
288
|
+
let json =
|
|
289
|
+
schema
|
|
290
|
+
->withSpec({...emptySpec, internal: ["eventCollector"]})
|
|
291
|
+
->SuryToJsonSchema.deriveObjectSchema
|
|
292
|
+
expect(
|
|
293
|
+
json
|
|
294
|
+
->JSON.Decode.object
|
|
295
|
+
->Option.flatMap(o => o->Dict.get("required"))
|
|
296
|
+
->Option.flatMap(JSON.Decode.array)
|
|
297
|
+
->Option.getOr([])
|
|
298
|
+
->Array.filterMap(JSON.Decode.string),
|
|
299
|
+
)->toEqual(["id"])
|
|
300
|
+
})
|
|
301
|
+
|
|
259
302
|
testSync("emits x-reventless-summary on field listed in summary", () => {
|
|
260
303
|
let schema = S.schema(s =>
|
|
261
304
|
{
|