@reventlessdev/reventless-local 3.0.0-alpha.226 → 3.0.0-alpha.228
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 +23 -0
- package/package.json +14 -14
- package/src/LocalPlatformRegistry.res +2 -2
- package/src/LocalPlatformRegistry.res.mjs +14 -13
- package/src/Platform.res +14 -15
- package/src/Platform.res.mjs +20 -21
- package/src/adapter/Auth/LocalAuth.res +3 -3
- package/src/adapter/Auth/LocalAuth.res.mjs +3 -2
- package/src/adapter/Auth/UserStore.res +1 -1
- package/src/adapter/Auth/UserStore.res.mjs +7 -6
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res +1 -1
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res.mjs +1 -1
- package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res +1 -1
- package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res.mjs +3 -3
- package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +2 -2
- package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res.mjs +4 -4
- package/src/adapter/DomainGraphQL_Server.res +2 -2
- package/src/adapter/DomainGraphQL_Server.res.mjs +3 -3
- package/src/adapter/DomainMCP_Server.res +1 -1
- package/src/adapter/MCP_ServerInstance.res +1 -1
- package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res +223 -22
- package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res.mjs +176 -18
- package/tests/BakedManifestFilesTest.res +0 -1
- package/tests/PluginEventDecodeTest.res +3 -3
- package/tests/PluginEventDecodeTest.res.mjs +4 -4
- package/tests/ShellConfigTest.res +0 -1
- package/tests/UiHintsTest.res +33 -6
- package/tests/UiHintsTest.res.mjs +15 -2
- package/tests/adapter/CommandAuthorizationTest.res.mjs +7 -7
- package/tests/adapter/GraphQL_SchemaInspectorTest.res +9 -7
- package/tests/adapter/GraphQL_SchemaInspectorTest.res.mjs +64 -64
- package/tests/adapter/LocalAuthHttpTest.res +1 -1
- package/tests/adapter/LocalAuthHttpTest.res.mjs +2 -2
- package/tests/adapter/QueryDbListResolverTest.res +82 -2
- package/tests/adapter/QueryDbListResolverTest.res.mjs +111 -16
- package/tests/components/aggregate/AggregateFixtures.res.mjs +6 -6
- package/tests/components/automationslice/AutomationSliceFixtures.res +4 -4
- package/tests/components/automationslice/AutomationSliceFixtures.res.mjs +20 -19
- package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +2 -2
- package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res.mjs +23 -22
- package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +4 -4
- package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res.mjs +21 -20
- package/tests/components/commandgenerator/CommandGeneratorFixtures.res +0 -1
- package/tests/components/commandgenerator/CommandGeneratorFixtures.res.mjs +6 -8
- package/tests/components/commandgenerator/CommandGeneratorTest.res +1 -1
- package/tests/components/commandgenerator/CommandGeneratorTest.res.mjs +2 -2
- package/tests/components/commandtopic/CommandTopicFixtures.res.mjs +9 -9
- package/tests/components/commandtopic/CommandTopicStreamFixtures.res.mjs +9 -9
- package/tests/components/dcb/DcbCrossPartitionFixtures.res +3 -3
- package/tests/components/dcb/DcbCrossPartitionFixtures.res.mjs +22 -21
- package/tests/components/dcb/DcbEventLogAppendStreamTest.res +1 -1
- package/tests/components/dcb/DcbEventLogAppendStreamTest.res.mjs +2 -2
- package/tests/components/dcb/DcbFixtures.res +2 -2
- package/tests/components/dcb/DcbFixtures.res.mjs +12 -11
- package/tests/components/eventlog/EventLogFixtures.res.mjs +6 -6
- package/tests/components/eventlog/EventLogProvisioningSeamTest.res.mjs +3 -3
- package/tests/components/eventtopic/EventTopicFixtures.res.mjs +6 -6
- package/tests/components/eventtopic/EventTopicStreamFixtures.res.mjs +6 -6
- package/tests/components/extensionpoint/ExtensionPointFixtures.res +0 -1
- package/tests/components/extensionpoint/ExtensionPointFixtures.res.mjs +11 -13
- package/tests/components/extensionpoint/ExtensionPointTest.res +3 -3
- package/tests/components/extensionpoint/ExtensionPointTest.res.mjs +4 -4
- package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res.mjs +10 -10
- package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res.mjs +9 -9
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res.mjs +23 -21
- package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res +2 -2
- package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res.mjs +17 -14
- package/tests/components/querydb/QueryDbFixtures.res.mjs +4 -4
- package/tests/components/querydb/QueryDbSubIdFixtures.res.mjs +6 -6
- package/tests/components/readmodel/DcbReadModelE2EFixtures.res +3 -3
- package/tests/components/readmodel/DcbReadModelE2EFixtures.res.mjs +17 -16
- package/tests/components/readmodel/DcbReadModelTypoFailFastTest.res.mjs +7 -7
- package/tests/components/readmodel/MixedSourceReadModelFixtures.res +5 -5
- package/tests/components/readmodel/MixedSourceReadModelFixtures.res.mjs +20 -19
- package/tests/components/readmodel/ReadModelFixtures.res +3 -3
- package/tests/components/readmodel/ReadModelFixtures.res.mjs +9 -8
- package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res +2 -3
- package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +7 -8
- package/tests/components/stateviewslice/StateViewSliceFixtures.res +2 -2
- package/tests/components/stateviewslice/StateViewSliceFixtures.res.mjs +22 -21
- package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res +2 -2
- package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res.mjs +27 -26
- package/tests/components/task/TaskFixtures.res +0 -1
- package/tests/components/task/TaskFixtures.res.mjs +0 -3
|
@@ -16,7 +16,6 @@ let keysOf = (config: ReventlessInfra.Platform.bakedManifest) =>
|
|
|
16
16
|
BakedManifest.files(~config)->Array.map(((key, _)) => key)
|
|
17
17
|
|
|
18
18
|
describe("BakedManifest.files", () => {
|
|
19
|
-
open Expect
|
|
20
19
|
|
|
21
20
|
// The regression line: one declaration, one file, under the name every
|
|
22
21
|
// existing deployment's config.json already points at.
|
|
@@ -16,7 +16,7 @@ let envelopeOf = (event: ReventlessCore.PluginSpec.event) =>
|
|
|
16
16
|
"Catalog",
|
|
17
17
|
meta,
|
|
18
18
|
~recordedAt="2024-01-01T00:00:00Z",
|
|
19
|
-
event->
|
|
19
|
+
event->Reventless.Util_Sury.toJson(ReventlessCore.PluginSpec.eventSchema),
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
describe("Platform.decodePluginEventEnvelope", () => {
|
|
@@ -38,7 +38,7 @@ describe("Platform.decodePluginEventEnvelope", () => {
|
|
|
38
38
|
testSync("returns None for a bare event JSON (no envelope) and malformed input", () => {
|
|
39
39
|
// The old bug class: input that is not the {id, meta, event} envelope.
|
|
40
40
|
let bare =
|
|
41
|
-
ReventlessCore.PluginSpec.VersionDetected("2.0.0")->
|
|
41
|
+
ReventlessCore.PluginSpec.VersionDetected("2.0.0")->Reventless.Util_Sury.toJson(
|
|
42
42
|
ReventlessCore.PluginSpec.eventSchema,
|
|
43
43
|
)
|
|
44
44
|
expect(Platform.decodePluginEventEnvelope(bare))->toEqual(None)
|
|
@@ -64,7 +64,7 @@ describe("Platform.decodeUiFragmentRegistryEventEnvelope", () => {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
let dcbEnvelopeOf = (event: ReventlessCore.UiFragmentRegistry.event) => {
|
|
67
|
-
let json = event->
|
|
67
|
+
let json = event->Reventless.Util_Sury.toJson(ReventlessCore.UiFragmentRegistry.eventSchema)
|
|
68
68
|
let (eventType, data) = json->ReventlessCore.Message.splitMessage
|
|
69
69
|
ReventlessCore.Message.composeEventJson'(
|
|
70
70
|
"Catalog",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
4
4
|
import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
|
|
5
5
|
import * as Platform$ReventlessLocal from "../src/Platform.res.mjs";
|
|
6
6
|
import * as PluginSpec$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/lifecycle/PluginSpec.res.mjs";
|
|
@@ -15,7 +15,7 @@ TestRunner$ReventlessLocal.setup();
|
|
|
15
15
|
let meta = Message$ReventlessCore.generateMeta(PluginSpec$ReventlessCore.name, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
16
16
|
|
|
17
17
|
function envelopeOf(event) {
|
|
18
|
-
return Message$ReventlessCore.composeEventJson$p("Catalog", meta, "2024-01-01T00:00:00Z",
|
|
18
|
+
return Message$ReventlessCore.composeEventJson$p("Catalog", meta, "2024-01-01T00:00:00Z", Util_Sury$Reventless.toJson(event, PluginSpec$ReventlessCore.eventSchema));
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
globalThis.describe("Platform.decodePluginEventEnvelope", () => {
|
|
@@ -46,7 +46,7 @@ globalThis.describe("Platform.decodePluginEventEnvelope", () => {
|
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
48
|
globalThis.test("returns None for a bare event JSON (no envelope) and malformed input", () => {
|
|
49
|
-
let bare =
|
|
49
|
+
let bare = Util_Sury$Reventless.toJson({
|
|
50
50
|
TAG: "VersionDetected",
|
|
51
51
|
_0: "2.0.0"
|
|
52
52
|
}, PluginSpec$ReventlessCore.eventSchema);
|
|
@@ -62,7 +62,7 @@ globalThis.describe("Platform.decodePluginEventEnvelope", () => {
|
|
|
62
62
|
globalThis.describe("Platform.decodeUiFragmentRegistryEventEnvelope", () => {
|
|
63
63
|
let dcbMeta = Message$ReventlessCore.generateMeta(ComponentType$ReventlessCore.name(Platform_Admin_Structure$ReventlessCore.pluginId, "DcbEventLog"), undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
64
64
|
let dcbEnvelopeOf = event => {
|
|
65
|
-
let json =
|
|
65
|
+
let json = Util_Sury$Reventless.toJson(event, UiFragmentRegistry$ReventlessCore.eventSchema);
|
|
66
66
|
let match = Message$ReventlessCore.splitMessage(json);
|
|
67
67
|
return Message$ReventlessCore.composeEventJson$p("Catalog", dcbMeta, "2024-01-01T00:00:00Z", Message$ReventlessCore.combineMessage(match[0], match[1]));
|
|
68
68
|
};
|
|
@@ -167,7 +167,6 @@ let fulfilment: ReventlessInfra.Platform.bakedJourney = {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
describe("ShellConfig.overlay — journeys", () => {
|
|
170
|
-
open Expect
|
|
171
170
|
|
|
172
171
|
// The regression line. A shell that has never heard of journeys must not
|
|
173
172
|
// suddenly find a key it does not know.
|
package/tests/UiHintsTest.res
CHANGED
|
@@ -103,30 +103,54 @@ describe("UiHints.emit", () => {
|
|
|
103
103
|
// point, while mid-session it is almost always an editor mid-save, and killing a
|
|
104
104
|
// running dev server over a keystroke is worse than the restart this replaces.
|
|
105
105
|
|
|
106
|
-
//
|
|
106
|
+
// The edit is repeated, and that is not belt-and-braces.
|
|
107
|
+
//
|
|
108
|
+
// `fs.watch` does not promise that a write landing near the watcher's creation
|
|
109
|
+
// is reported. The FSEvents stream behind it on macOS is armed asynchronously,
|
|
110
|
+
// and a write that gets there first is not reported late — it is not reported at
|
|
111
|
+
// all. Measured against this very module: once the stream is up the edit is seen
|
|
112
|
+
// in about 10ms, and when it is not, the same edit produces no event in four
|
|
113
|
+
// seconds, with which of the two happens varying by how many watchers the
|
|
114
|
+
// process has already opened rather than by anything the test does.
|
|
115
|
+
//
|
|
116
|
+
// So a single edit tests the arming, not the reload. Repeating it on an interval
|
|
117
|
+
// far longer than a reload takes — 50ms of debounce plus a file copy — leaves the
|
|
118
|
+
// case where the first write lands identical to what it always was, and lets the
|
|
119
|
+
// case where it is dropped recover on the next one instead of reporting that hot
|
|
120
|
+
// reload is broken. Re-writing the same bytes is what a developer saving twice
|
|
121
|
+
// does, so nothing here asserts less than it did.
|
|
122
|
+
let retryEvery = 1000
|
|
123
|
+
|
|
124
|
+
// All three exits close the watcher AND clear both timers. A watcher is `unref`ed
|
|
107
125
|
// and would not hold the run open on its own, but a live 4-second timer would —
|
|
108
126
|
// and "Jest did not exit" on a suite that passed is exactly the noise that
|
|
109
127
|
// teaches a reader to ignore it.
|
|
110
|
-
let waitForReload = (~timeoutMs: int=4000, ~
|
|
128
|
+
let waitForReload = (~timeoutMs: int=4000, ~edit: unit => unit, ~uiHintsFile, ~dir) =>
|
|
111
129
|
Promise.make((resolve, _) => {
|
|
112
130
|
let fired = ref(0)
|
|
113
131
|
let watcher = ref(None)
|
|
114
132
|
let deadline = ref(None)
|
|
133
|
+
let retry = ref(None)
|
|
115
134
|
// Resolves with a count rather than rejecting on the deadline: "nothing was
|
|
116
135
|
// re-served" is the expected answer in half these cases, and a rejection
|
|
117
136
|
// would make the assertion read as an infrastructure failure.
|
|
118
137
|
let finish = () => {
|
|
119
138
|
watcher.contents->Option.forEach(NodeFs.watcherClose)
|
|
120
139
|
deadline.contents->Option.forEach(clearTimeout)
|
|
140
|
+
retry.contents->Option.forEach(clearTimeout)
|
|
121
141
|
resolve(fired.contents)
|
|
122
142
|
}
|
|
143
|
+
let rec editUntilSeen = () => {
|
|
144
|
+
edit()
|
|
145
|
+
retry := Some(setTimeout(editUntilSeen, retryEvery))
|
|
146
|
+
}
|
|
123
147
|
watcher :=
|
|
124
148
|
UiHints.watch(~uiHintsFile, ~dir, ~onReload=() => {
|
|
125
149
|
fired := fired.contents + 1
|
|
126
150
|
finish()
|
|
127
151
|
})
|
|
128
152
|
deadline := Some(setTimeout(finish, timeoutMs))
|
|
129
|
-
|
|
153
|
+
editUntilSeen()
|
|
130
154
|
})
|
|
131
155
|
|
|
132
156
|
describe("UiHints.watch", () => {
|
|
@@ -147,7 +171,7 @@ describe("UiHints.watch", () => {
|
|
|
147
171
|
let fired = await waitForReload(
|
|
148
172
|
~uiHintsFile=Some(path),
|
|
149
173
|
~dir,
|
|
150
|
-
~
|
|
174
|
+
~edit=() => NodeFs.writeFileSync(path, edited),
|
|
151
175
|
)
|
|
152
176
|
expect((fired > 0, served(dir)))->toEqual((true, edited))
|
|
153
177
|
})
|
|
@@ -163,7 +187,7 @@ describe("UiHints.watch", () => {
|
|
|
163
187
|
~timeoutMs=1500,
|
|
164
188
|
~uiHintsFile=Some(path),
|
|
165
189
|
~dir,
|
|
166
|
-
~
|
|
190
|
+
~edit=() => NodeFs.writeFileSync(path, `{"Catalog": {"views":`),
|
|
167
191
|
)
|
|
168
192
|
expect((fired, served(dir)))->toEqual((0, declared))
|
|
169
193
|
})
|
|
@@ -178,7 +202,10 @@ describe("UiHints.watch", () => {
|
|
|
178
202
|
let fired = await waitForReload(
|
|
179
203
|
~uiHintsFile=Some(path),
|
|
180
204
|
~dir,
|
|
181
|
-
|
|
205
|
+
// Both halves of the save, so a repeat of this edit is the same story told
|
|
206
|
+
// again and still ends on the whole file — never a truncated write left
|
|
207
|
+
// standing after a complete one.
|
|
208
|
+
~edit=() => {
|
|
182
209
|
NodeFs.writeFileSync(path, `{"Catalog": {"views":`)
|
|
183
210
|
let _ = setTimeout(() => NodeFs.writeFileSync(path, whole), 200)
|
|
184
211
|
},
|
|
@@ -88,7 +88,7 @@ globalThis.describe("UiHints.emit", () => {
|
|
|
88
88
|
});
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
-
function waitForReload(timeoutMsOpt,
|
|
91
|
+
function waitForReload(timeoutMsOpt, edit, uiHintsFile, dir) {
|
|
92
92
|
let timeoutMs = timeoutMsOpt !== undefined ? timeoutMsOpt : 4000;
|
|
93
93
|
return new Promise((resolve, param) => {
|
|
94
94
|
let fired = {
|
|
@@ -100,6 +100,9 @@ function waitForReload(timeoutMsOpt, afterWatching, uiHintsFile, dir) {
|
|
|
100
100
|
let deadline = {
|
|
101
101
|
contents: undefined
|
|
102
102
|
};
|
|
103
|
+
let retry = {
|
|
104
|
+
contents: undefined
|
|
105
|
+
};
|
|
103
106
|
let finish = () => {
|
|
104
107
|
Stdlib_Option.forEach(watcher.contents, prim => {
|
|
105
108
|
prim.close();
|
|
@@ -107,14 +110,21 @@ function waitForReload(timeoutMsOpt, afterWatching, uiHintsFile, dir) {
|
|
|
107
110
|
Stdlib_Option.forEach(deadline.contents, prim => {
|
|
108
111
|
clearTimeout(prim);
|
|
109
112
|
});
|
|
113
|
+
Stdlib_Option.forEach(retry.contents, prim => {
|
|
114
|
+
clearTimeout(prim);
|
|
115
|
+
});
|
|
110
116
|
resolve(fired.contents);
|
|
111
117
|
};
|
|
118
|
+
let editUntilSeen = () => {
|
|
119
|
+
edit();
|
|
120
|
+
retry.contents = Primitive_option.some(setTimeout(editUntilSeen, 1000));
|
|
121
|
+
};
|
|
112
122
|
watcher.contents = UiHints$ReventlessLocal.watch(uiHintsFile, dir, () => {
|
|
113
123
|
fired.contents = fired.contents + 1 | 0;
|
|
114
124
|
finish();
|
|
115
125
|
});
|
|
116
126
|
deadline.contents = Primitive_option.some(setTimeout(finish, timeoutMs));
|
|
117
|
-
|
|
127
|
+
editUntilSeen();
|
|
118
128
|
});
|
|
119
129
|
}
|
|
120
130
|
|
|
@@ -178,6 +188,8 @@ globalThis.describe("UiHints.watch", () => {
|
|
|
178
188
|
});
|
|
179
189
|
});
|
|
180
190
|
|
|
191
|
+
let retryEvery = 1000;
|
|
192
|
+
|
|
181
193
|
export {
|
|
182
194
|
shipped,
|
|
183
195
|
declared,
|
|
@@ -187,6 +199,7 @@ export {
|
|
|
187
199
|
served,
|
|
188
200
|
baselinePath,
|
|
189
201
|
threw,
|
|
202
|
+
retryEvery,
|
|
190
203
|
waitForReload,
|
|
191
204
|
}
|
|
192
205
|
/* Not a pure module */
|
|
@@ -1,6 +1,6 @@
|
|
|
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_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
5
5
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
6
6
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
@@ -15,16 +15,16 @@ import * as CommandGeneratorResolvers_GraphQL$ReventlessLocal from "../../src/ad
|
|
|
15
15
|
|
|
16
16
|
TestRunner$ReventlessLocal.setup();
|
|
17
17
|
|
|
18
|
-
let commandSchema =
|
|
19
|
-
|
|
18
|
+
let commandSchema = Sury.union([
|
|
19
|
+
Sury.$schema(s => ({
|
|
20
20
|
TAG: "Add",
|
|
21
|
-
name: s.m(
|
|
21
|
+
name: s.m(Sury.string)
|
|
22
22
|
})),
|
|
23
|
-
|
|
23
|
+
Sury.$schema(s => ({
|
|
24
24
|
TAG: "Rename",
|
|
25
|
-
name: s.m(
|
|
25
|
+
name: s.m(Sury.string)
|
|
26
26
|
})),
|
|
27
|
-
|
|
27
|
+
Sury.literal("Archive")
|
|
28
28
|
]);
|
|
29
29
|
|
|
30
30
|
function commandAuthorization(cmd) {
|
|
@@ -271,7 +271,7 @@ describe("GraphQL_SchemaInspector", () => {
|
|
|
271
271
|
expect(result.typeDef->Option.isSome)->toBe(true)
|
|
272
272
|
let typeDef = result.typeDef->Option.getOrThrow
|
|
273
273
|
expect(typeDef->String.includes("type CatalogProduct"))->toBe(true)
|
|
274
|
-
expect(result.singleQuery->String.includes("Catalog_Product(id: ID
|
|
274
|
+
expect(result.singleQuery->String.includes("Catalog_Product(id: ID!, includeRetired: Boolean)"))->toBe(true)
|
|
275
275
|
expect(result.singleQuery->String.includes("CatalogProduct"))->toBe(true)
|
|
276
276
|
expect(result.listQuery->Option.isSome)->toBe(true)
|
|
277
277
|
let listQ = result.listQuery->Option.getOrThrow
|
|
@@ -298,7 +298,7 @@ describe("GraphQL_SchemaInspector", () => {
|
|
|
298
298
|
)
|
|
299
299
|
let inspection = ReventlessCore.GraphQL_SchemaInspector.inspectFragment(fragment)
|
|
300
300
|
let sdl = inspection.sdlPreview
|
|
301
|
-
expect(sdl->String.includes("RM_Product(id: ID
|
|
301
|
+
expect(sdl->String.includes("RM_Product(id: ID!, includeRetired: Boolean): RMProduct"))->toBe(true)
|
|
302
302
|
expect(sdl->String.includes("type RMProduct"))->toBe(true)
|
|
303
303
|
// The type should have an injected id: ID! field (first field in the type)
|
|
304
304
|
let typeLines = sdl->String.split("\n")
|
|
@@ -357,7 +357,7 @@ describe("GraphQL_SchemaInspector", () => {
|
|
|
357
357
|
)
|
|
358
358
|
let inspection = ReventlessCore.GraphQL_SchemaInspector.inspectFragment(fragment)
|
|
359
359
|
let sdl = inspection.sdlPreview
|
|
360
|
-
expect(sdl->String.includes("Default_Thing(id: ID
|
|
360
|
+
expect(sdl->String.includes("Default_Thing(id: ID!, includeRetired: Boolean): DefaultThing"))->toBe(true)
|
|
361
361
|
})
|
|
362
362
|
})
|
|
363
363
|
|
|
@@ -542,13 +542,15 @@ describe("GraphQL_SchemaInspector", () => {
|
|
|
542
542
|
],
|
|
543
543
|
)
|
|
544
544
|
let inspection = ReventlessCore.GraphQL_SchemaInspector.inspectFragment(fragment)
|
|
545
|
-
// TestState, TestStateEdge, TestStateConnection, TestStateFilter (
|
|
545
|
+
// TestState, TestStateEdge, TestStateConnection, TestStateFilter (connection filter)
|
|
546
|
+
// + TestStateRef (the reference door's projection)
|
|
546
547
|
// + CommandResult union + CommandAccepted + CommandRejected + CommandPending
|
|
547
548
|
// (auto-injected whenever the fragment emits any mutation field).
|
|
548
|
-
expect(inspection.types->Array.length)->toBe(
|
|
549
|
+
expect(inspection.types->Array.length)->toBe(9)
|
|
549
550
|
expect(inspection.mutations->Array.length)->toBe(1)
|
|
550
|
-
// single Test_State(id), list Test_States(...),
|
|
551
|
-
|
|
551
|
+
// single Test_State(id), list Test_States(...), Test_StatesByIds(ids: [String!]!)
|
|
552
|
+
// and Test_StatesRefs(ids: [ID!]!) — the by-ids read projected to a reference.
|
|
553
|
+
expect(inspection.queries->Array.length)->toBe(4)
|
|
552
554
|
expect(inspection.sdlPreview->String.includes("type TestState"))->toBe(true)
|
|
553
555
|
expect(inspection.sdlPreview->String.includes("type TestStateEdge"))->toBe(true)
|
|
554
556
|
expect(inspection.sdlPreview->String.includes("type TestStateConnection"))->toBe(true)
|
|
@@ -1,6 +1,6 @@
|
|
|
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 DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
6
6
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
@@ -16,87 +16,93 @@ import * as Plugin_SubscriptionSchema$ReventlessCore from "@reventlessdev/revent
|
|
|
16
16
|
|
|
17
17
|
TestRunner$ReventlessLocal.setup();
|
|
18
18
|
|
|
19
|
-
let
|
|
19
|
+
let stringSchema = Sury.string;
|
|
20
|
+
|
|
21
|
+
let numberSchema = Sury.float;
|
|
22
|
+
|
|
23
|
+
let boolSchema = Sury.bool;
|
|
24
|
+
|
|
25
|
+
let testStateSchema = Sury.$schema(s => ({
|
|
20
26
|
id: s.m(DcbTag$Reventless.string),
|
|
21
|
-
name: s.m(
|
|
22
|
-
price: s.m(
|
|
23
|
-
active: s.m(
|
|
27
|
+
name: s.m(Sury.string),
|
|
28
|
+
price: s.m(Sury.float),
|
|
29
|
+
active: s.m(Sury.bool)
|
|
24
30
|
}));
|
|
25
31
|
|
|
26
|
-
let svStateSchema =
|
|
32
|
+
let svStateSchema = Sury.$schema(s => ({
|
|
27
33
|
productId: s.m(DcbTag$Reventless.string),
|
|
28
|
-
name: s.m(
|
|
29
|
-
price: s.m(
|
|
34
|
+
name: s.m(Sury.string),
|
|
35
|
+
price: s.m(Sury.float)
|
|
30
36
|
}));
|
|
31
37
|
|
|
32
|
-
let sourceKindSchema =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
let sourceKindSchema = Sury.union([
|
|
39
|
+
Sury.literal("tagged"),
|
|
40
|
+
Sury.literal("ancestry"),
|
|
41
|
+
Sury.literal("substrate")
|
|
36
42
|
]);
|
|
37
43
|
|
|
38
|
-
let enumStateSchema =
|
|
44
|
+
let enumStateSchema = Sury.$schema(s => ({
|
|
39
45
|
productId: s.m(DcbTag$Reventless.string),
|
|
40
46
|
requiredSource: s.m(sourceKindSchema),
|
|
41
|
-
optionalSource: s.m(
|
|
47
|
+
optionalSource: s.m(Sury.$option(sourceKindSchema))
|
|
42
48
|
}));
|
|
43
49
|
|
|
44
|
-
let addCommandSchema =
|
|
50
|
+
let addCommandSchema = Sury.$schema(s => ({
|
|
45
51
|
productId: s.m(DcbTag$Reventless.string),
|
|
46
|
-
name: s.m(
|
|
52
|
+
name: s.m(Sury.string)
|
|
47
53
|
}));
|
|
48
54
|
|
|
49
|
-
let unionCommandSchema =
|
|
50
|
-
|
|
55
|
+
let unionCommandSchema = Sury.union([
|
|
56
|
+
Sury.$schema(s => ({
|
|
51
57
|
TAG: "Create",
|
|
52
58
|
itemId: s.m(DcbTag$Reventless.string),
|
|
53
|
-
name: s.m(
|
|
59
|
+
name: s.m(Sury.string)
|
|
54
60
|
})),
|
|
55
|
-
|
|
61
|
+
Sury.$schema(s => ({
|
|
56
62
|
TAG: "Rename",
|
|
57
63
|
itemId: s.m(DcbTag$Reventless.string),
|
|
58
|
-
newName: s.m(
|
|
64
|
+
newName: s.m(Sury.string)
|
|
59
65
|
}))
|
|
60
66
|
]);
|
|
61
67
|
|
|
62
|
-
let dcbSingleCommandSchema =
|
|
68
|
+
let dcbSingleCommandSchema = Sury.$schema(s => ({
|
|
63
69
|
TAG: "AddCategory",
|
|
64
70
|
categoryId: s.m(DcbTag$Reventless.string),
|
|
65
|
-
name: s.m(
|
|
71
|
+
name: s.m(Sury.string)
|
|
66
72
|
}));
|
|
67
73
|
|
|
68
|
-
let dcbMultiCommandSchema =
|
|
69
|
-
|
|
74
|
+
let dcbMultiCommandSchema = Sury.union([
|
|
75
|
+
Sury.$schema(s => ({
|
|
70
76
|
TAG: "SyncNewProduct",
|
|
71
77
|
productId: s.m(DcbTag$Reventless.string),
|
|
72
|
-
name: s.m(
|
|
73
|
-
price: s.m(
|
|
78
|
+
name: s.m(Sury.string),
|
|
79
|
+
price: s.m(Sury.float)
|
|
74
80
|
})),
|
|
75
|
-
|
|
81
|
+
Sury.$schema(s => ({
|
|
76
82
|
TAG: "ChangeSyncedPrice",
|
|
77
83
|
productId: s.m(DcbTag$Reventless.string),
|
|
78
|
-
price: s.m(
|
|
84
|
+
price: s.m(Sury.float)
|
|
79
85
|
}))
|
|
80
86
|
]);
|
|
81
87
|
|
|
82
|
-
let plainStateSchema =
|
|
88
|
+
let plainStateSchema = Sury.$schema(s => ({
|
|
83
89
|
productId: s.m(DcbTag$Reventless.string),
|
|
84
|
-
name: s.m(
|
|
90
|
+
name: s.m(Sury.string)
|
|
85
91
|
}));
|
|
86
92
|
|
|
87
|
-
let keylessStateSchema =
|
|
88
|
-
name: s.m(
|
|
89
|
-
note: s.m(
|
|
93
|
+
let keylessStateSchema = Sury.$schema(s => ({
|
|
94
|
+
name: s.m(Sury.string),
|
|
95
|
+
note: s.m(Sury.string)
|
|
90
96
|
}));
|
|
91
97
|
|
|
92
|
-
let indexedStateSchema =
|
|
98
|
+
let indexedStateSchema = Sury.$schema(s => ({
|
|
93
99
|
productId: s.m(DcbTag$Reventless.string),
|
|
94
|
-
ownerId: s.m(
|
|
95
|
-
status: s.m(
|
|
96
|
-
name: s.m(
|
|
100
|
+
ownerId: s.m(Sury.string),
|
|
101
|
+
status: s.m(Sury.string),
|
|
102
|
+
name: s.m(Sury.string)
|
|
97
103
|
}));
|
|
98
104
|
|
|
99
|
-
let indexedStateSchemaWithAnnotations =
|
|
105
|
+
let indexedStateSchemaWithAnnotations = Sury.$Metadata_set(indexedStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
|
|
100
106
|
ids: ["productId"],
|
|
101
107
|
compositeIds: [],
|
|
102
108
|
subIds: [],
|
|
@@ -121,13 +127,13 @@ let indexedStateSchemaWithAnnotations = S.Metadata.set(indexedStateSchema, State
|
|
|
121
127
|
retired: undefined
|
|
122
128
|
});
|
|
123
129
|
|
|
124
|
-
let orderedStateSchema =
|
|
130
|
+
let orderedStateSchema = Sury.$schema(s => ({
|
|
125
131
|
productId: s.m(DcbTag$Reventless.string),
|
|
126
|
-
createdAt: s.m(
|
|
127
|
-
name: s.m(
|
|
132
|
+
createdAt: s.m(Sury.string),
|
|
133
|
+
name: s.m(Sury.string)
|
|
128
134
|
}));
|
|
129
135
|
|
|
130
|
-
let orderedStateSchemaWithAnnotations =
|
|
136
|
+
let orderedStateSchemaWithAnnotations = Sury.$Metadata_set(orderedStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
|
|
131
137
|
ids: ["productId"],
|
|
132
138
|
compositeIds: [],
|
|
133
139
|
subIds: ["createdAt"],
|
|
@@ -149,14 +155,14 @@ let orderedStateSchemaWithAnnotations = S.Metadata.set(orderedStateSchema, State
|
|
|
149
155
|
retired: undefined
|
|
150
156
|
});
|
|
151
157
|
|
|
152
|
-
let scanStateSchema =
|
|
158
|
+
let scanStateSchema = Sury.$schema(s => ({
|
|
153
159
|
productId: s.m(DcbTag$Reventless.string),
|
|
154
|
-
status: s.m(
|
|
155
|
-
name: s.m(
|
|
156
|
-
description: s.m(
|
|
160
|
+
status: s.m(Sury.string),
|
|
161
|
+
name: s.m(Sury.string),
|
|
162
|
+
description: s.m(Sury.string)
|
|
157
163
|
}));
|
|
158
164
|
|
|
159
|
-
let scanStateSchemaWithAnnotations =
|
|
165
|
+
let scanStateSchemaWithAnnotations = Sury.$Metadata_set(scanStateSchema, StateAnnotations$Reventless.stateAnnotationsId, {
|
|
160
166
|
ids: ["productId"],
|
|
161
167
|
compositeIds: [],
|
|
162
168
|
subIds: [],
|
|
@@ -181,16 +187,16 @@ let scanStateSchemaWithAnnotations = S.Metadata.set(scanStateSchema, StateAnnota
|
|
|
181
187
|
globalThis.describe("GraphQL_SchemaInspector", () => {
|
|
182
188
|
globalThis.describe("inspectScalar", () => {
|
|
183
189
|
globalThis.test("plain string derives to String", async () => {
|
|
184
|
-
globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(
|
|
190
|
+
globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(stringSchema)).toBe("String");
|
|
185
191
|
});
|
|
186
192
|
globalThis.test("tagged string derives to ID", async () => {
|
|
187
193
|
globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(DcbTag$Reventless.string)).toBe("ID");
|
|
188
194
|
});
|
|
189
195
|
globalThis.test("float derives to Float", async () => {
|
|
190
|
-
globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(
|
|
196
|
+
globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(numberSchema)).toBe("Float");
|
|
191
197
|
});
|
|
192
198
|
globalThis.test("bool derives to Boolean", async () => {
|
|
193
|
-
globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(
|
|
199
|
+
globalThis.expect(GraphQL_SchemaInspector$ReventlessCore.inspectScalar(boolSchema)).toBe("Boolean");
|
|
194
200
|
});
|
|
195
201
|
});
|
|
196
202
|
globalThis.describe("inspectObjectType", () => {
|
|
@@ -205,7 +211,7 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
|
|
|
205
211
|
globalThis.expect(sdl.includes("active: Boolean")).toBe(true);
|
|
206
212
|
});
|
|
207
213
|
globalThis.test("returns None for non-object schema", async () => {
|
|
208
|
-
let result = GraphQL_SchemaInspector$ReventlessCore.inspectObjectType("Foo",
|
|
214
|
+
let result = GraphQL_SchemaInspector$ReventlessCore.inspectObjectType("Foo", stringSchema);
|
|
209
215
|
globalThis.expect(Stdlib_Option.isNone(result)).toBe(true);
|
|
210
216
|
});
|
|
211
217
|
});
|
|
@@ -229,7 +235,7 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
|
|
|
229
235
|
globalThis.expect(renameField.includes("newName: String")).toBe(true);
|
|
230
236
|
});
|
|
231
237
|
globalThis.test("returns empty for non-object/non-union schema", async () => {
|
|
232
|
-
let fields = GraphQL_SchemaInspector$ReventlessCore.inspectMutationFields("Foo",
|
|
238
|
+
let fields = GraphQL_SchemaInspector$ReventlessCore.inspectMutationFields("Foo", stringSchema);
|
|
233
239
|
globalThis.expect(fields.length).toBe(0);
|
|
234
240
|
});
|
|
235
241
|
});
|
|
@@ -239,7 +245,7 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
|
|
|
239
245
|
globalThis.expect(Stdlib_Option.isSome(result.typeDef)).toBe(true);
|
|
240
246
|
let typeDef = Stdlib_Option.getOrThrow(result.typeDef, undefined);
|
|
241
247
|
globalThis.expect(typeDef.includes("type CatalogProduct")).toBe(true);
|
|
242
|
-
globalThis.expect(result.singleQuery.includes("Catalog_Product(id: ID
|
|
248
|
+
globalThis.expect(result.singleQuery.includes("Catalog_Product(id: ID!, includeRetired: Boolean)")).toBe(true);
|
|
243
249
|
globalThis.expect(result.singleQuery.includes("CatalogProduct")).toBe(true);
|
|
244
250
|
globalThis.expect(Stdlib_Option.isSome(result.listQuery)).toBe(true);
|
|
245
251
|
let listQ = Stdlib_Option.getOrThrow(result.listQuery, undefined);
|
|
@@ -258,7 +264,7 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
|
|
|
258
264
|
}]);
|
|
259
265
|
let inspection = GraphQL_SchemaInspector$ReventlessCore.inspectFragment(fragment);
|
|
260
266
|
let sdl = inspection.sdlPreview;
|
|
261
|
-
globalThis.expect(sdl.includes("RM_Product(id: ID
|
|
267
|
+
globalThis.expect(sdl.includes("RM_Product(id: ID!, includeRetired: Boolean): RMProduct")).toBe(true);
|
|
262
268
|
globalThis.expect(sdl.includes("type RMProduct")).toBe(true);
|
|
263
269
|
let typeLines = sdl.split("\n");
|
|
264
270
|
let idFieldInType = typeLines.some(line => {
|
|
@@ -302,7 +308,7 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
|
|
|
302
308
|
}]);
|
|
303
309
|
let inspection = GraphQL_SchemaInspector$ReventlessCore.inspectFragment(fragment);
|
|
304
310
|
let sdl = inspection.sdlPreview;
|
|
305
|
-
globalThis.expect(sdl.includes("Default_Thing(id: ID
|
|
311
|
+
globalThis.expect(sdl.includes("Default_Thing(id: ID!, includeRetired: Boolean): DefaultThing")).toBe(true);
|
|
306
312
|
});
|
|
307
313
|
});
|
|
308
314
|
globalThis.describe("Relay compliance", () => {
|
|
@@ -424,9 +430,9 @@ globalThis.describe("GraphQL_SchemaInspector", () => {
|
|
|
424
430
|
authorization: undefined
|
|
425
431
|
}]);
|
|
426
432
|
let inspection = GraphQL_SchemaInspector$ReventlessCore.inspectFragment(fragment);
|
|
427
|
-
globalThis.expect(inspection.types.length).toBe(
|
|
433
|
+
globalThis.expect(inspection.types.length).toBe(9);
|
|
428
434
|
globalThis.expect(inspection.mutations.length).toBe(1);
|
|
429
|
-
globalThis.expect(inspection.queries.length).toBe(
|
|
435
|
+
globalThis.expect(inspection.queries.length).toBe(4);
|
|
430
436
|
globalThis.expect(inspection.sdlPreview.includes("type TestState")).toBe(true);
|
|
431
437
|
globalThis.expect(inspection.sdlPreview.includes("type TestStateEdge")).toBe(true);
|
|
432
438
|
globalThis.expect(inspection.sdlPreview.includes("type TestStateConnection")).toBe(true);
|
|
@@ -707,14 +713,8 @@ globalThis.describe("optional enum fields preserve GraphQL nullability", () => {
|
|
|
707
713
|
});
|
|
708
714
|
});
|
|
709
715
|
|
|
710
|
-
let stringSchema = S.string;
|
|
711
|
-
|
|
712
716
|
let taggedSchema = DcbTag$Reventless.string;
|
|
713
717
|
|
|
714
|
-
let numberSchema = S.float;
|
|
715
|
-
|
|
716
|
-
let boolSchema = S.bool;
|
|
717
|
-
|
|
718
718
|
export {
|
|
719
719
|
stringSchema,
|
|
720
720
|
taggedSchema,
|
|
@@ -163,7 +163,7 @@ testPromise("POST /__inmemory/login returns {token, identity} for valid credenti
|
|
|
163
163
|
// The echoed identity matches what LocalAuth.lookupUser returns.
|
|
164
164
|
switch getJsonField(body, "identity") {
|
|
165
165
|
| Some(idJson) =>
|
|
166
|
-
let id = idJson->
|
|
166
|
+
let id = idJson->Reventless.Util_Sury.fromJson(Reventless.Identity.schema)
|
|
167
167
|
expect(id.username)->toEqual("alice")
|
|
168
168
|
expect(id.groups)->toEqual(["Editor"])
|
|
169
169
|
| None => JsError.throwWithMessage("response missing identity field")
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as S from "sury/src/S.res.mjs";
|
|
4
3
|
import * as Nodehttp from "node:http";
|
|
5
4
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
6
5
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
6
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
8
7
|
import * as Identity$Reventless from "@reventlessdev/reventless-spec/src/types/Identity.res.mjs";
|
|
8
|
+
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
9
9
|
import * as LocalAuth$ReventlessLocal from "../../src/adapter/Auth/LocalAuth.res.mjs";
|
|
10
10
|
import * as TestRunner$ReventlessLocal from "../../src/test/TestRunner.res.mjs";
|
|
11
11
|
import * as DomainGraphQL_Server$ReventlessLocal from "../../src/adapter/DomainGraphQL_Server.res.mjs";
|
|
@@ -151,7 +151,7 @@ globalThis.test("POST /__inmemory/login returns {token, identity} for valid cred
|
|
|
151
151
|
if (idJson === undefined) {
|
|
152
152
|
return Stdlib_JsError.throwWithMessage("response missing identity field");
|
|
153
153
|
}
|
|
154
|
-
let id =
|
|
154
|
+
let id = Util_Sury$Reventless.fromJson(idJson, Identity$Reventless.schema);
|
|
155
155
|
globalThis.expect(id.username).toEqual("alice");
|
|
156
156
|
globalThis.expect(id.groups).toEqual(["Editor"]);
|
|
157
157
|
});
|