@reventlessdev/reventless-core 3.0.0-alpha.179 → 3.0.0-alpha.181
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 +21 -0
- package/package.json +8 -8
- package/src/Message.res +2 -1
- package/src/Message.res.mjs +5 -1
- package/src/adapter/Monitoring/Monitoring.res +14 -2
- package/src/adapter/Monitoring/Monitoring.res.mjs +4 -2
- package/src/admin/Platform_Admin_Structure.res +2 -0
- package/src/admin/Platform_Admin_Structure.res.mjs +2 -0
- package/src/admin/Platform_ComponentDefinitionsApi.res +2 -1
- package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +5 -1
- package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments_Projection.res +1 -1
- package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments_Projection.res.mjs +2 -1
- package/src/components/Api/ApiTargetStateHelpers.res +20 -0
- package/src/components/Api/ApiTargetStateHelpers.res.mjs +16 -0
- package/src/components/Api/GraphQL_FragmentGenerator.res +1 -0
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +1 -0
- package/src/components/Api/SchemaType.res +3 -0
- package/src/components/Api/SchemaType.res.mjs +10 -2
- package/src/components/Api/SuryToJsonSchema.res +16 -0
- package/src/components/Api/SuryToJsonSchema.res.mjs +28 -0
- package/src/components/Dcb/Dcb_Builder.res +4 -5
- package/src/components/Dcb/Dcb_Builder.res.mjs +3 -5
- package/src/components/DcbEventLog/DcbEventLog_Operations.res +6 -1
- package/src/components/DcbEventLog/DcbEventLog_Operations.res.mjs +2 -1
- package/src/components/InboundTranslationSlice/InboundTranslationSlice.res +25 -0
- package/src/components/InboundTranslationSlice/InboundTranslationSlice.res.mjs +31 -0
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res +8 -8
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs +26 -6
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res +44 -37
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res.mjs +17 -25
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +27 -2
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs +4 -0
- package/src/components/StateViewSlice/StateViewSlice_Builder.res +20 -6
- package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +23 -5
- package/src/components/StateViewSlice/StateViewSlice_Callback.res +1 -1
- package/src/components/StateViewSlice/StateViewSlice_Callback.res.mjs +5 -1
- package/src/plugin/component/Plugin_Helpers.res +4 -1
- package/src/plugin/component/Plugin_Structure.res +15 -1
- package/src/plugin/component/Plugin_Structure.res.mjs +4 -1
- package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +2 -0
- package/tests/IdentityTest.res.mjs +174 -0
- package/tests/ResourceAttributionTest.res.mjs +75 -0
- package/tests/adapter/MonitoringTest.res +32 -2
- package/tests/adapter/MonitoringTest.res.mjs +116 -0
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +10 -0
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +365 -0
- package/tests/admin/Platform_UIFragmentsApiTest.res.mjs +101 -0
- package/tests/aggregate/AggregateCacheTest.res.mjs +433 -0
- package/tests/aggregate/AggregateCallbackTest.res.mjs +143 -0
- package/tests/aggregate/AggregateCausationTest.res.mjs +47 -0
- package/tests/aggregate/AggregateConflictTest.res.mjs +386 -0
- package/tests/aggregate/AggregateFixtures.res.mjs +308 -0
- package/tests/aggregate/AggregateRejectionTest.res.mjs +166 -0
- package/tests/aggregate/AggregateSnapshotTest.res.mjs +645 -0
- package/tests/api/ApiNoApiTest.res.mjs +90 -0
- package/tests/api/GraphQL_StitcherTest.res.mjs +112 -0
- package/tests/api/SimpleTest.res.mjs +10 -0
- package/tests/api/SuryToJsonSchemaTest.res +68 -0
- package/tests/api/SuryToJsonSchemaTest.res.mjs +843 -0
- package/tests/commandgenerator/CommandGeneratorCallbackTest.res.mjs +160 -0
- package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +197 -0
- package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +152 -0
- package/tests/commandtopic/CommandTopicCallbackTest.res.mjs +106 -0
- package/tests/commandtopic/CommandTopicHelpersRejectionTest.res.mjs +109 -0
- package/tests/counter/CounterCallbackTest.res.mjs +140 -0
- package/tests/counter/CounterFixtures.res.mjs +67 -0
- package/tests/dcb/DcbDecodeTest.res.mjs +194 -0
- package/tests/dcb/DcbEventLogOperationsTest.res.mjs +268 -0
- package/tests/dcb/DcbFixtures.res.mjs +534 -0
- package/tests/dcb/DcbScopeInferenceTest.res.mjs +480 -0
- package/tests/dcb/DcbStateChangeSliceTest.res.mjs +540 -0
- package/tests/dcb/DcbTagTest.res.mjs +867 -0
- package/tests/dcb/DcbValidationTest.res.mjs +476 -0
- package/tests/eventlog/EventLogFixtures.res.mjs +196 -0
- package/tests/eventlog/EventLogOperationsTest.res.mjs +192 -0
- package/tests/eventlog/EventLogRetryTest.res.mjs +195 -0
- package/tests/eventmapper/EventMapperCallbackTest.res.mjs +141 -0
- package/tests/eventmapper/EventMapperFixtures.res.mjs +440 -0
- package/tests/eventmapper/EventMapperTest.res.mjs +83 -0
- package/tests/eventtopic/EventTopicFixtures.res.mjs +65 -0
- package/tests/eventtopic/EventTopicOperationsTest.res.mjs +71 -0
- package/tests/extensionpoint/ExtensionPointCallbackTest.res.mjs +94 -0
- package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +205 -0
- package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +304 -0
- package/tests/extensionpoint/PluginDisconnectScheduleTest.res.mjs +92 -0
- package/tests/ftp/FTPTest.res.mjs +88 -0
- package/tests/logger/LogFormatTest.res.mjs +329 -0
- package/tests/logger/LoggerLazyTest.res.mjs +40 -0
- package/tests/message/MessageTest.res.mjs +218 -0
- package/tests/message/MetaEnvelopeTest.res.mjs +188 -0
- package/tests/plugin/HeartbeatDisconnectGraceTest.res.mjs +91 -0
- package/tests/plugin/ManifestVisibilityTest.res.mjs +215 -0
- package/tests/plugin/PluginSpecExperiment.res.mjs +31 -0
- package/tests/plugin/PluginStructureTest.res +55 -0
- package/tests/plugin/PluginStructureTest.res.mjs +467 -0
- package/tests/plugin/PluginVersionTest.res.mjs +30 -0
- package/tests/plugin/SchemaWalkerTest.res.mjs +160 -0
- package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +62 -0
- package/tests/plugin/StateChangeSlice/PsShipOrder.res +4 -1
- package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +77 -0
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res +5 -4
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +110 -0
- package/tests/plugin/StateViewSlice/PsAvailableProductsView.res +1 -1
- package/tests/plugin/StateViewSlice/PsAvailableProductsView.res.mjs +70 -0
- package/tests/plugin/StateViewSlice/PsCustomersView.res +1 -1
- package/tests/plugin/StateViewSlice/PsCustomersView.res.mjs +70 -0
- package/tests/plugin/StateViewSlice/PsOrdersView.res +1 -1
- package/tests/plugin/StateViewSlice/PsOrdersView.res.mjs +82 -0
- package/tests/poc/StructuralSubtypingPoc.res.mjs +61 -0
- package/tests/projection/ProjectionOptimizeTest.res.mjs +75 -0
- package/tests/querydb/QueryDbFixtures.res.mjs +135 -0
- package/tests/querydb/QueryDbOperationsTest.res.mjs +168 -0
- package/tests/sideeffecthandler/SideEffectHandlerCallbackTest.res.mjs +77 -0
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +139 -0
- package/tests/util/CommandPublisherTest.res.mjs +78 -0
- package/tests/util/CsvStreamTest.res.mjs +51 -0
- package/tests/util/LruTest.res.mjs +105 -0
- package/tests/util/MetricsTest.res.mjs +53 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Api$ReventlessInfra from "@reventlessdev/reventless-infra/src/components/Api.res.mjs";
|
|
6
|
+
import * as ApiNoApiHelpers$ReventlessCore from "../../src/components/Api/ApiNoApiHelpers.res.mjs";
|
|
7
|
+
|
|
8
|
+
globalThis.describe("ApiNoApiHelpers:", () => {
|
|
9
|
+
globalThis.test("isNoApi returns false for schema without noApi metadata", () => {
|
|
10
|
+
globalThis.expect(ApiNoApiHelpers$ReventlessCore.isNoApi(S.string)).toBe(false);
|
|
11
|
+
});
|
|
12
|
+
globalThis.test("isNoApi returns true for schema with noApi metadata set to true", () => {
|
|
13
|
+
let schema$p = S.Metadata.set(S.string, Api$ReventlessInfra.noApiId, true);
|
|
14
|
+
globalThis.expect(ApiNoApiHelpers$ReventlessCore.isNoApi(schema$p)).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
globalThis.test("getExcludedVariants returns None for schema without noApiVariants metadata", () => {
|
|
17
|
+
globalThis.expect(ApiNoApiHelpers$ReventlessCore.getExcludedVariants(S.string)).toBe(undefined);
|
|
18
|
+
});
|
|
19
|
+
globalThis.test("getExcludedVariants returns Some with DeleteItem when set", () => {
|
|
20
|
+
let excluded = new Set([
|
|
21
|
+
"DeleteItem",
|
|
22
|
+
"UpdateItem"
|
|
23
|
+
]);
|
|
24
|
+
let schema$p = S.Metadata.set(S.string, Api$ReventlessInfra.noApiVariantsId, excluded);
|
|
25
|
+
let result = ApiNoApiHelpers$ReventlessCore.getExcludedVariants(schema$p);
|
|
26
|
+
globalThis.expect(Stdlib_Option.getOr(Stdlib_Option.map(result, set => set.has("DeleteItem")), false)).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
globalThis.test("filterNoApiVariants returns all field names when no variants are excluded", () => {
|
|
29
|
+
let fieldNames = [
|
|
30
|
+
"CreateItem",
|
|
31
|
+
"DeleteItem",
|
|
32
|
+
"UpdateItem"
|
|
33
|
+
];
|
|
34
|
+
let filtered = ApiNoApiHelpers$ReventlessCore.filterNoApiVariants(fieldNames, S.string);
|
|
35
|
+
globalThis.expect(filtered).toEqual([
|
|
36
|
+
"CreateItem",
|
|
37
|
+
"DeleteItem",
|
|
38
|
+
"UpdateItem"
|
|
39
|
+
]);
|
|
40
|
+
});
|
|
41
|
+
globalThis.test("filterNoApiVariants filters out excluded variants", () => {
|
|
42
|
+
let excluded = new Set(["DeleteItem"]);
|
|
43
|
+
let schema$p = S.Metadata.set(S.string, Api$ReventlessInfra.noApiVariantsId, excluded);
|
|
44
|
+
let fieldNames = [
|
|
45
|
+
"CreateItem",
|
|
46
|
+
"DeleteItem",
|
|
47
|
+
"UpdateItem"
|
|
48
|
+
];
|
|
49
|
+
let filtered = ApiNoApiHelpers$ReventlessCore.filterNoApiVariants(fieldNames, schema$p);
|
|
50
|
+
globalThis.expect(filtered).toEqual([
|
|
51
|
+
"CreateItem",
|
|
52
|
+
"UpdateItem"
|
|
53
|
+
]);
|
|
54
|
+
});
|
|
55
|
+
globalThis.test("filterNoApiVariants filters out multiple excluded variants", () => {
|
|
56
|
+
let excluded = new Set([
|
|
57
|
+
"DeleteItem",
|
|
58
|
+
"UpdateItem"
|
|
59
|
+
]);
|
|
60
|
+
let schema$p = S.Metadata.set(S.string, Api$ReventlessInfra.noApiVariantsId, excluded);
|
|
61
|
+
let fieldNames = [
|
|
62
|
+
"CreateItem",
|
|
63
|
+
"DeleteItem",
|
|
64
|
+
"UpdateItem",
|
|
65
|
+
"GetItem"
|
|
66
|
+
];
|
|
67
|
+
let filtered = ApiNoApiHelpers$ReventlessCore.filterNoApiVariants(fieldNames, schema$p);
|
|
68
|
+
globalThis.expect(filtered).toEqual([
|
|
69
|
+
"CreateItem",
|
|
70
|
+
"GetItem"
|
|
71
|
+
]);
|
|
72
|
+
});
|
|
73
|
+
globalThis.test("filterNoApiVariants returns empty array when all variants are excluded", () => {
|
|
74
|
+
let excluded = new Set([
|
|
75
|
+
"CreateItem",
|
|
76
|
+
"DeleteItem",
|
|
77
|
+
"UpdateItem"
|
|
78
|
+
]);
|
|
79
|
+
let schema$p = S.Metadata.set(S.string, Api$ReventlessInfra.noApiVariantsId, excluded);
|
|
80
|
+
let fieldNames = [
|
|
81
|
+
"CreateItem",
|
|
82
|
+
"DeleteItem",
|
|
83
|
+
"UpdateItem"
|
|
84
|
+
];
|
|
85
|
+
let filtered = ApiNoApiHelpers$ReventlessCore.filterNoApiVariants(fieldNames, schema$p);
|
|
86
|
+
globalThis.expect(filtered).toEqual([]);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
/* Not a pure module */
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as GraphQL_Stitcher$ReventlessCore from "../../src/components/Api/GraphQL_Stitcher.res.mjs";
|
|
4
|
+
import * as Platform_AdminApi$ReventlessCore from "../../src/admin/Platform_AdminApi.res.mjs";
|
|
5
|
+
|
|
6
|
+
globalThis.describe("GraphQL_Stitcher.subscriptionSources", () => {
|
|
7
|
+
globalThis.test("encode/decode round-trips the subscription→mutation source mapping", () => {
|
|
8
|
+
let fragment = GraphQL_Stitcher$ReventlessCore.encode({
|
|
9
|
+
types: [],
|
|
10
|
+
mutations: [` Catalog_AddProduct(input: AddInput): CommandResult`],
|
|
11
|
+
queries: [],
|
|
12
|
+
subscriptions: [` onCatalog_AddProduct(id: ID): CommandResult`],
|
|
13
|
+
subscriptionSources: [{
|
|
14
|
+
field: "onCatalog_AddProduct",
|
|
15
|
+
mutations: ["Catalog_AddProduct"]
|
|
16
|
+
}]
|
|
17
|
+
});
|
|
18
|
+
let parts = GraphQL_Stitcher$ReventlessCore.decode(fragment);
|
|
19
|
+
globalThis.expect(parts.subscriptionSources).toEqual([{
|
|
20
|
+
field: "onCatalog_AddProduct",
|
|
21
|
+
mutations: ["Catalog_AddProduct"]
|
|
22
|
+
}]);
|
|
23
|
+
});
|
|
24
|
+
globalThis.test("decode tolerates fragments encoded before the field existed", () => {
|
|
25
|
+
globalThis.expect(GraphQL_Stitcher$ReventlessCore.decode({
|
|
26
|
+
encoded: `{"types":[],"mutations":[],"queries":[],"subscriptions":[" onX(id: ID): CommandResult"]}`,
|
|
27
|
+
protocol: "graphql"
|
|
28
|
+
}).subscriptionSources).toEqual([]);
|
|
29
|
+
});
|
|
30
|
+
globalThis.test("collectSubscriptionSources unions across fragments, first wins per field", () => {
|
|
31
|
+
let base = GraphQL_Stitcher$ReventlessCore.encode({
|
|
32
|
+
types: [],
|
|
33
|
+
mutations: [],
|
|
34
|
+
queries: [],
|
|
35
|
+
subscriptions: [` onUIFragmentChange: UIFragmentChangeEvent`],
|
|
36
|
+
subscriptionSources: [{
|
|
37
|
+
field: "onUIFragmentChange",
|
|
38
|
+
mutations: ["Platform_UIFragmentRegistered"]
|
|
39
|
+
}]
|
|
40
|
+
});
|
|
41
|
+
let pluginA = GraphQL_Stitcher$ReventlessCore.encode({
|
|
42
|
+
types: [],
|
|
43
|
+
mutations: [],
|
|
44
|
+
queries: [],
|
|
45
|
+
subscriptions: [` onA(id: ID): CommandResult`],
|
|
46
|
+
subscriptionSources: [
|
|
47
|
+
{
|
|
48
|
+
field: "onA",
|
|
49
|
+
mutations: ["A"]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
field: "onUIFragmentChange",
|
|
53
|
+
mutations: ["Rogue_Mutation"]
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
let collected = GraphQL_Stitcher$ReventlessCore.collectSubscriptionSources(base, [pluginA]);
|
|
58
|
+
globalThis.expect(collected).toEqual([
|
|
59
|
+
{
|
|
60
|
+
field: "onUIFragmentChange",
|
|
61
|
+
mutations: ["Platform_UIFragmentRegistered"]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
field: "onA",
|
|
65
|
+
mutations: ["A"]
|
|
66
|
+
}
|
|
67
|
+
]);
|
|
68
|
+
});
|
|
69
|
+
globalThis.test("core-emitted admin base fragment carries no provider directives", () => {
|
|
70
|
+
let base = Platform_AdminApi$ReventlessCore.baseFragment(true);
|
|
71
|
+
globalThis.expect(base.encoded.includes("@aws_subscribe")).toBe(false);
|
|
72
|
+
globalThis.expect(base.encoded.includes("@aws_auth")).toBe(false);
|
|
73
|
+
let parts = GraphQL_Stitcher$ReventlessCore.decode(base);
|
|
74
|
+
let fields = parts.subscriptionSources.map(s => s.field);
|
|
75
|
+
globalThis.expect(fields.includes("onUIFragmentChange")).toBe(true);
|
|
76
|
+
globalThis.expect(fields.includes("onPluginStatusChange")).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
globalThis.describe("GraphQL_Stitcher.stitchStandalone", () => {
|
|
81
|
+
let pluginFragment = GraphQL_Stitcher$ReventlessCore.encode({
|
|
82
|
+
types: [
|
|
83
|
+
`type Product implements Node {\n id: ID!\n name: String\n}`,
|
|
84
|
+
`union CommandResult = CommandAccepted | CommandRejected | CommandPending`
|
|
85
|
+
],
|
|
86
|
+
mutations: [` Catalog_AddProduct(input: AddInput): CommandResult`],
|
|
87
|
+
queries: [` Catalog_products: [Product]`],
|
|
88
|
+
subscriptions: [` onCatalog_AddProduct(id: ID): CommandResult`],
|
|
89
|
+
subscriptionSources: [{
|
|
90
|
+
field: "onCatalog_AddProduct",
|
|
91
|
+
mutations: ["Catalog_AddProduct"]
|
|
92
|
+
}]
|
|
93
|
+
});
|
|
94
|
+
globalThis.test("renders a self-contained subgraph document with relay base types", () => {
|
|
95
|
+
let sdl = GraphQL_Stitcher$ReventlessCore.stitchStandalone(pluginFragment);
|
|
96
|
+
globalThis.expect(sdl).toContain("interface Node {");
|
|
97
|
+
globalThis.expect(sdl).toContain("type PageInfo {");
|
|
98
|
+
globalThis.expect(sdl).toContain("type Product implements Node {");
|
|
99
|
+
globalThis.expect(sdl).toContain("Catalog_AddProduct(input: AddInput): CommandResult");
|
|
100
|
+
globalThis.expect(sdl).toContain("onCatalog_AddProduct(id: ID): CommandResult");
|
|
101
|
+
});
|
|
102
|
+
globalThis.test("omits the global node query (the canonical base document owns it)", () => {
|
|
103
|
+
let sdl = GraphQL_Stitcher$ReventlessCore.stitchStandalone(pluginFragment);
|
|
104
|
+
globalThis.expect(sdl.includes("node(id: ID!): Node")).toBe(false);
|
|
105
|
+
});
|
|
106
|
+
globalThis.test("stitch keeps injecting the global node query (whole-schema path unchanged)", () => {
|
|
107
|
+
let sdl = GraphQL_Stitcher$ReventlessCore.stitch(pluginFragment, []);
|
|
108
|
+
globalThis.expect(sdl).toContain("node(id: ID!): Node");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
/* Not a pure module */
|
|
@@ -29,6 +29,8 @@ let emptySpec: Reventless.StateAnnotations.stateAnnotationSpec = {
|
|
|
29
29
|
collapsed: [],
|
|
30
30
|
scan: [],
|
|
31
31
|
scanSort: [],
|
|
32
|
+
semantic: [],
|
|
33
|
+
metric: [],
|
|
32
34
|
status: None,
|
|
33
35
|
groupBy: None,
|
|
34
36
|
visibility: None,
|
|
@@ -49,6 +51,25 @@ describe("SuryToJsonSchema:", () => {
|
|
|
49
51
|
idSchema->Option.flatMap(s => getProperty(s, "x-reventless-id")),
|
|
50
52
|
)->toBe(None)
|
|
51
53
|
})
|
|
54
|
+
|
|
55
|
+
testSync("emits format:\"date-time\" for a DateTime-marked string field", () => {
|
|
56
|
+
let schema = S.schema(s =>
|
|
57
|
+
{
|
|
58
|
+
"placedAt": s.matches(Reventless.DateTime.string),
|
|
59
|
+
"name": s.matches(S.string),
|
|
60
|
+
}
|
|
61
|
+
)->S.castToUnknown
|
|
62
|
+
let json = SuryToJsonSchema.deriveObjectSchema(schema)
|
|
63
|
+
expect(
|
|
64
|
+
getPropertyOf(json, "placedAt")
|
|
65
|
+
->Option.flatMap(s => getProperty(s, "format"))
|
|
66
|
+
->Option.flatMap(JSON.Decode.string),
|
|
67
|
+
)->toBe(Some("date-time"))
|
|
68
|
+
// A plain string field stays plain — the marker is opt-in.
|
|
69
|
+
expect(
|
|
70
|
+
getPropertyOf(json, "name")->Option.flatMap(s => getProperty(s, "format")),
|
|
71
|
+
)->toBe(None)
|
|
72
|
+
})
|
|
52
73
|
})
|
|
53
74
|
|
|
54
75
|
describe("deriveObjectSchema with stateAnnotations metadata:", () => {
|
|
@@ -306,6 +327,53 @@ describe("SuryToJsonSchema:", () => {
|
|
|
306
327
|
))->toEqual((Some(true), None))
|
|
307
328
|
})
|
|
308
329
|
|
|
330
|
+
testSync("emits x-reventless-semantic on the field listed in semantic", () => {
|
|
331
|
+
let schema = S.schema(s =>
|
|
332
|
+
{
|
|
333
|
+
"id": s.matches(S.string),
|
|
334
|
+
"total": s.matches(S.float),
|
|
335
|
+
}
|
|
336
|
+
)->S.castToUnknown
|
|
337
|
+
let schema' = schema->withSpec({...emptySpec, semantic: [("total", "currency")]})
|
|
338
|
+
let json = SuryToJsonSchema.deriveObjectSchema(schema')
|
|
339
|
+
let totalSchema = getPropertyOf(json, "total")
|
|
340
|
+
let idSchema = getPropertyOf(json, "id")
|
|
341
|
+
expect((
|
|
342
|
+
totalSchema
|
|
343
|
+
->Option.flatMap(s => getProperty(s, "x-reventless-semantic"))
|
|
344
|
+
->Option.flatMap(JSON.Decode.string),
|
|
345
|
+
idSchema->Option.flatMap(s => getProperty(s, "x-reventless-semantic")),
|
|
346
|
+
))->toEqual((Some("currency"), None))
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
testSync("emits x-reventless-metric {aggregate,label} on the field listed in metric", () => {
|
|
350
|
+
let schema = S.schema(s =>
|
|
351
|
+
{
|
|
352
|
+
"id": s.matches(S.string),
|
|
353
|
+
"total": s.matches(S.float),
|
|
354
|
+
}
|
|
355
|
+
)->S.castToUnknown
|
|
356
|
+
let schema' =
|
|
357
|
+
schema->withSpec({...emptySpec, metric: [("total", {aggregate: "sum", label: "Revenue"})]})
|
|
358
|
+
let json = SuryToJsonSchema.deriveObjectSchema(schema')
|
|
359
|
+
let metricObj = getPropertyOf(json, "total")->Option.flatMap(s => getProperty(s, "x-reventless-metric"))
|
|
360
|
+
expect((
|
|
361
|
+
metricObj->Option.flatMap(m => getProperty(m, "aggregate"))->Option.flatMap(JSON.Decode.string),
|
|
362
|
+
metricObj->Option.flatMap(m => getProperty(m, "label"))->Option.flatMap(JSON.Decode.string),
|
|
363
|
+
))->toEqual((Some("sum"), Some("Revenue")))
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
testSync("omits the metric label when empty (UI derives one from the field name)", () => {
|
|
367
|
+
let schema = S.schema(s => {"total": s.matches(S.float)})->S.castToUnknown
|
|
368
|
+
let schema' = schema->withSpec({...emptySpec, metric: [("total", {aggregate: "sum", label: ""})]})
|
|
369
|
+
let json = SuryToJsonSchema.deriveObjectSchema(schema')
|
|
370
|
+
let metricObj = getPropertyOf(json, "total")->Option.flatMap(s => getProperty(s, "x-reventless-metric"))
|
|
371
|
+
expect((
|
|
372
|
+
metricObj->Option.flatMap(m => getProperty(m, "aggregate"))->Option.flatMap(JSON.Decode.string),
|
|
373
|
+
metricObj->Option.flatMap(m => getProperty(m, "label")),
|
|
374
|
+
))->toEqual((Some("sum"), None))
|
|
375
|
+
})
|
|
376
|
+
|
|
309
377
|
testSync("emits x-reventless-group-by on the field named by groupBy", () => {
|
|
310
378
|
let schema = S.schema(s =>
|
|
311
379
|
{
|