@reventlessdev/reventless-core 3.0.0-alpha.258 → 3.0.0-alpha.260
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 +18 -0
- package/package.json +9 -9
- package/src/Projection.res +158 -40
- package/src/Projection.res.mjs +107 -28
- package/src/admin/UiFragmentRegistry/{StateChangeSlice → StateChange}/UiFragmentRegistry.res.mjs +1 -1
- package/src/admin/UiFragmentRegistry/{StateChangeSlice → StateChange}/UiFragmentRegistry_Behavior.res.mjs +1 -1
- package/src/admin/UiFragmentRegistry/{StateViewSlice → StateView}/UiFragments.res.mjs +1 -1
- package/src/admin/UiFragmentRegistry/{StateViewSlice → StateView}/UiFragments_Projection.res.mjs +1 -1
- package/src/components/Api/GraphQL_FragmentGenerator.res +16 -2
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +13 -5
- package/src/components/Api/SchemaType.res +81 -1
- package/src/components/Api/SchemaType.res.mjs +82 -3
- package/src/components/Api/SuryToJsonSchema.res +10 -0
- package/src/components/Api/SuryToJsonSchema.res.mjs +135 -110
- package/src/components/ReadModel/ReadModel_Callback.res +5 -2
- package/src/components/ReadModel/ReadModel_Callback.res.mjs +2 -5
- package/src/components/StateViewSlice/StateViewSlice_Builder.res +7 -6
- package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +2 -5
- package/src/components/StateViewSlice/StateViewSlice_Callback.res +3 -1
- package/src/components/StateViewSlice/StateViewSlice_Callback.res.mjs +1 -1
- package/src/plugin/component/Plugin_Structure.res +9 -46
- package/src/plugin/component/Plugin_Structure.res.mjs +8 -40
- package/src/plugin/connect/PluginExtensionPoint_UiFragment.res.mjs +1 -1
- package/tests/admin/AdminApiSchemaDriftTest.res.mjs +1 -1
- package/tests/api/BrandedMarkerCompositionTest.res +74 -0
- package/tests/api/BrandedMarkerCompositionTest.res.mjs +74 -0
- package/tests/api/PsBrandedMarkersReadModel.res +24 -0
- package/tests/api/PsBrandedMarkersReadModel.res.mjs +87 -0
- package/tests/api/SuryToJsonSchemaTest.res +91 -3
- package/tests/api/SuryToJsonSchemaTest.res.mjs +66 -4
- package/tests/plugin/PluginStructureAccessTest.res.mjs +3 -3
- package/tests/plugin/PluginStructureTest.res +24 -5
- package/tests/plugin/PluginStructureTest.res.mjs +32 -26
- package/tests/plugin/{StateChangeSlice → StateChange}/PsAttachInvoice.res.mjs +1 -1
- package/tests/plugin/{StateChangeSlice → StateChange}/PsChangePhoto.res.mjs +1 -1
- package/tests/plugin/{StateChangeSlice → StateChange}/PsDispatchShipment.res.mjs +1 -1
- package/tests/plugin/{StateChangeSlice → StateChange}/PsGatedCommands.res.mjs +1 -1
- package/tests/plugin/{StateChangeSlice → StateChange}/PsPlaceOrder.res.mjs +1 -1
- package/tests/plugin/{StateChangeSlice → StateChange}/PsReserveStock.res.mjs +1 -1
- package/tests/plugin/{StateChangeSlice → StateChange}/PsShipOrder.res.mjs +1 -1
- package/tests/plugin/{StateChangeSlice → StateChange}/PsTransitionSwitch.res.mjs +1 -1
- package/tests/plugin/{StateChangeSlice → StateChange}/PsTypoStore.res.mjs +1 -1
- package/tests/plugin/{StateChangeSlice → StateChange}/PsUploadAvatar.res.mjs +1 -1
- package/tests/plugin/{StateChangeSlice → StateChange}/PsUploadImages.res.mjs +1 -1
- package/tests/plugin/{StateViewSlice → StateView}/PsAnnotatedView.res +4 -2
- package/tests/plugin/{StateViewSlice → StateView}/PsAnnotatedView.res.mjs +8 -4
- package/tests/plugin/{StateViewSlice → StateView}/PsAvailableProductsView.res.mjs +1 -1
- package/tests/plugin/{StateViewSlice → StateView}/PsCategoriesView.res.mjs +1 -1
- package/tests/plugin/{StateViewSlice → StateView}/PsCustomersView.res.mjs +1 -1
- package/tests/plugin/{StateViewSlice → StateView}/PsGatedView.res.mjs +1 -1
- package/tests/plugin/{StateViewSlice → StateView}/PsOrdersView.res.mjs +1 -1
- package/tests/plugin/{StateViewSlice → StateView}/PsShipmentsView.res.mjs +1 -1
- package/tests/projection/LifecycleTrailTest.res +139 -0
- package/tests/projection/LifecycleTrailTest.res.mjs +280 -0
- /package/src/admin/UiFragmentRegistry/{StateChangeSlice → StateChange}/UiFragmentRegistry.res +0 -0
- /package/src/admin/UiFragmentRegistry/{StateChangeSlice → StateChange}/UiFragmentRegistry_Behavior.res +0 -0
- /package/src/admin/UiFragmentRegistry/{StateViewSlice → StateView}/UiFragments.res +0 -0
- /package/src/admin/UiFragmentRegistry/{StateViewSlice → StateView}/UiFragments_Projection.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsAttachInvoice.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsChangePhoto.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsDispatchShipment.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsGatedCommands.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsPlaceOrder.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsReserveStock.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsShipOrder.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsTransitionSwitch.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsTypoStore.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsUploadAvatar.res +0 -0
- /package/tests/plugin/{StateChangeSlice → StateChange}/PsUploadImages.res +0 -0
- /package/tests/plugin/{StateViewSlice → StateView}/PsAvailableProductsView.res +0 -0
- /package/tests/plugin/{StateViewSlice → StateView}/PsCategoriesView.res +0 -0
- /package/tests/plugin/{StateViewSlice → StateView}/PsCustomersView.res +0 -0
- /package/tests/plugin/{StateViewSlice → StateView}/PsGatedView.res +0 -0
- /package/tests/plugin/{StateViewSlice → StateView}/PsOrdersView.res +0 -0
- /package/tests/plugin/{StateViewSlice → StateView}/PsShipmentsView.res +0 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// The rule that fills a lifecycle trail: an action that moves a view's
|
|
2
|
+
// lifecycle field appends `{state, at}`, and nothing else does. The example GWTs
|
|
3
|
+
// cover the same rule end to end, but their harness stamps one fixed producer
|
|
4
|
+
// time — the ordering-with-distinct-instants cases have to live here.
|
|
5
|
+
|
|
6
|
+
open JestGlobals
|
|
7
|
+
open Reventless.Projection
|
|
8
|
+
|
|
9
|
+
@schema
|
|
10
|
+
type lifecycle =
|
|
11
|
+
| Placed
|
|
12
|
+
| Shipped
|
|
13
|
+
| Cancelled
|
|
14
|
+
|
|
15
|
+
@schema
|
|
16
|
+
type order = {
|
|
17
|
+
orderId: string,
|
|
18
|
+
lifecycle: lifecycle,
|
|
19
|
+
trail: Reventless.Lifecycle.Trail.t<lifecycle>,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// A view that declares no trail, to hold the "nothing changes" case.
|
|
23
|
+
@schema
|
|
24
|
+
type plain = {
|
|
25
|
+
orderId: string,
|
|
26
|
+
lifecycle: lifecycle,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let nine = "2026-03-02T09:00:00Z"
|
|
30
|
+
let ten = "2026-03-02T10:00:00Z"
|
|
31
|
+
let eleven = "2026-03-02T11:00:00Z"
|
|
32
|
+
|
|
33
|
+
let placed = {orderId: "o1", lifecycle: Placed, trail: []}
|
|
34
|
+
|
|
35
|
+
// Applies one action to a state, the way the runtime does: `Set` writes the
|
|
36
|
+
// state it carries, `Update` runs its function over what is there.
|
|
37
|
+
let apply = (state: option<order>, action: action<string, order>): option<order> =>
|
|
38
|
+
switch (action, state) {
|
|
39
|
+
| (Set(_, s), _) | (Create(_, s), _) => Some(s)
|
|
40
|
+
| (Update(_, fn), Some(s)) => Some(fn(s))
|
|
41
|
+
| _ => state
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let run = (actions: array<(string, action<string, order>)>) =>
|
|
45
|
+
actions->Array.reduce(None, (state, (at, action)) =>
|
|
46
|
+
state->apply(Projection.rewriteAction(action, ~at, orderSchema))
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
let statesOf = (state: option<order>) =>
|
|
50
|
+
state->Option.mapOr([], s => s.trail->Array.map(entry => (entry.state, entry.at)))
|
|
51
|
+
|
|
52
|
+
describe("the lifecycle trail:", () => {
|
|
53
|
+
testSync("opens with the state the row was created in", () =>
|
|
54
|
+
expect(run([(nine, Set("o1", placed))])->statesOf)->toEqual([(Placed, nine)])
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
testSync("appends one entry per transition, in order", () =>
|
|
58
|
+
expect(
|
|
59
|
+
run([
|
|
60
|
+
(nine, Set("o1", placed)),
|
|
61
|
+
(ten, Update("o1", s => {...s, lifecycle: Shipped})),
|
|
62
|
+
])->statesOf,
|
|
63
|
+
)->toEqual([(Placed, nine), (Shipped, ten)])
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
// The case a `dict<state, instant>` cannot hold: a reopened order is `Placed`
|
|
67
|
+
// twice, at different instants, and both visits are facts about the row.
|
|
68
|
+
testSync("keeps both visits when a lifecycle revisits a state", () =>
|
|
69
|
+
expect(
|
|
70
|
+
run([
|
|
71
|
+
(nine, Set("o1", placed)),
|
|
72
|
+
(ten, Update("o1", s => {...s, lifecycle: Cancelled})),
|
|
73
|
+
(eleven, Update("o1", s => {...s, lifecycle: Placed})),
|
|
74
|
+
])->statesOf,
|
|
75
|
+
)->toEqual([(Placed, nine), (Cancelled, ten), (Placed, eleven)])
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
testSync("appends nothing for an update that leaves the lifecycle alone", () =>
|
|
79
|
+
expect(
|
|
80
|
+
run([
|
|
81
|
+
(nine, Set("o1", placed)),
|
|
82
|
+
(ten, Update("o1", s => {...s, orderId: "o1-renamed"})),
|
|
83
|
+
])->statesOf,
|
|
84
|
+
)->toEqual([(Placed, nine)])
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
// Derived from the log and the envelope's own time, so the same events in the
|
|
88
|
+
// same order produce the same trail however often they are replayed.
|
|
89
|
+
testSync("a rebuild from the same events produces an identical trail", () => {
|
|
90
|
+
let events = [
|
|
91
|
+
(nine, Set("o1", placed)),
|
|
92
|
+
(ten, Update("o1", s => {...s, lifecycle: Shipped})),
|
|
93
|
+
]
|
|
94
|
+
expect(run(events)->statesOf)->toEqual(run(events)->statesOf)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
// The marker is what makes a trail recognisable to a consumer holding only the
|
|
98
|
+
// schema. `SchemaType.trailShape` walks the entries by shape, which skips the
|
|
99
|
+
// semantic dispatch `fromSury` does, so this is the assertion that catches it
|
|
100
|
+
// being dropped there — the field would still emit as a plain array of objects.
|
|
101
|
+
testSync("carries the lifecycleTrail semantic onto the emitted JSON Schema", () => {
|
|
102
|
+
let field =
|
|
103
|
+
SuryToJsonSchema.deriveObjectSchema(~typeName="Order", orderSchema->S.castToUnknown)
|
|
104
|
+
->JSON.Decode.object
|
|
105
|
+
->Option.flatMap(o => o->Dict.get("properties"))
|
|
106
|
+
->Option.flatMap(JSON.Decode.object)
|
|
107
|
+
->Option.flatMap(p => p->Dict.get("trail"))
|
|
108
|
+
->Option.flatMap(JSON.Decode.object)
|
|
109
|
+
expect(field->Option.flatMap(f => f->Dict.get("x-reventless-semantic")))->toEqual(
|
|
110
|
+
Some(JSON.Encode.string("lifecycleTrail")),
|
|
111
|
+
)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
// One vocabulary, published once: the entry's state resolves to the enum the
|
|
115
|
+
// lifecycle field already emits, not a second copy under the trail's own path.
|
|
116
|
+
testSync("names the entry's state after the record's own lifecycle enum", () => {
|
|
117
|
+
let fields = SchemaType.fromSuryObject(~typeName="Order", orderSchema->S.castToUnknown)
|
|
118
|
+
let enumName = switch fields->Option.flatMap(f => f->Dict.get("trail")) {
|
|
119
|
+
| Some(Semantic(_, ArrayOf(ObjectRef(_, entry)))) =>
|
|
120
|
+
switch entry->Dict.get("state") {
|
|
121
|
+
| Some(Enum(name, _)) => Some(name)
|
|
122
|
+
| _ => None
|
|
123
|
+
}
|
|
124
|
+
| _ => None
|
|
125
|
+
}
|
|
126
|
+
expect(enumName)->toEqual(Some("OrderLifecycle"))
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
testSync("a view that declares no trail is projected unchanged", () => {
|
|
130
|
+
let action: action<string, plain> = Set("o1", {orderId: "o1", lifecycle: Placed})
|
|
131
|
+
let rewritten = Projection.rewriteAction(action, ~at=nine, plainSchema)
|
|
132
|
+
expect(
|
|
133
|
+
switch rewritten {
|
|
134
|
+
| Set(id, s) => Some((id, s.lifecycle))
|
|
135
|
+
| _ => None
|
|
136
|
+
},
|
|
137
|
+
)->toEqual(Some(("o1", Placed)))
|
|
138
|
+
})
|
|
139
|
+
})
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Sury from "sury";
|
|
4
|
+
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
5
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
6
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
|
+
import * as Lifecycle$Reventless from "@reventlessdev/reventless-spec/src/types/Lifecycle.res.mjs";
|
|
8
|
+
import * as Projection$ReventlessCore from "../../src/Projection.res.mjs";
|
|
9
|
+
import * as SchemaType$ReventlessCore from "../../src/components/Api/SchemaType.res.mjs";
|
|
10
|
+
import * as SuryToJsonSchema$ReventlessCore from "../../src/components/Api/SuryToJsonSchema.res.mjs";
|
|
11
|
+
|
|
12
|
+
let lifecycleSchema = Sury.union([
|
|
13
|
+
Sury.literal("Placed"),
|
|
14
|
+
Sury.literal("Shipped"),
|
|
15
|
+
Sury.literal("Cancelled")
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
let orderSchema = Sury.$schema(s => ({
|
|
19
|
+
orderId: s.m(Sury.string),
|
|
20
|
+
lifecycle: s.m(lifecycleSchema),
|
|
21
|
+
trail: s.m(Lifecycle$Reventless.Trail.schema(lifecycleSchema))
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
let plainSchema = Sury.$schema(s => ({
|
|
25
|
+
orderId: s.m(Sury.string),
|
|
26
|
+
lifecycle: s.m(lifecycleSchema)
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
let nine = "2026-03-02T09:00:00Z";
|
|
30
|
+
|
|
31
|
+
let ten = "2026-03-02T10:00:00Z";
|
|
32
|
+
|
|
33
|
+
let eleven = "2026-03-02T11:00:00Z";
|
|
34
|
+
|
|
35
|
+
let placed_trail = [];
|
|
36
|
+
|
|
37
|
+
let placed = {
|
|
38
|
+
orderId: "o1",
|
|
39
|
+
lifecycle: "Placed",
|
|
40
|
+
trail: placed_trail
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
function apply(state, action) {
|
|
44
|
+
if (typeof action !== "object") {
|
|
45
|
+
return state;
|
|
46
|
+
}
|
|
47
|
+
switch (action.TAG) {
|
|
48
|
+
case "Update" :
|
|
49
|
+
if (state !== undefined) {
|
|
50
|
+
return action._1(state);
|
|
51
|
+
} else {
|
|
52
|
+
return state;
|
|
53
|
+
}
|
|
54
|
+
case "Create" :
|
|
55
|
+
case "Set" :
|
|
56
|
+
return action._1;
|
|
57
|
+
default:
|
|
58
|
+
return state;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function run(actions) {
|
|
63
|
+
return Stdlib_Array.reduce(actions, undefined, (state, param) => apply(state, Projection$ReventlessCore.rewriteAction(param[1], param[0], orderSchema)));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function statesOf(state) {
|
|
67
|
+
return Stdlib_Option.mapOr(state, [], s => s.trail.map(entry => [
|
|
68
|
+
entry.state,
|
|
69
|
+
entry.at
|
|
70
|
+
]));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
globalThis.describe("the lifecycle trail:", () => {
|
|
74
|
+
globalThis.test("opens with the state the row was created in", () => {
|
|
75
|
+
globalThis.expect(statesOf(run([[
|
|
76
|
+
nine,
|
|
77
|
+
{
|
|
78
|
+
TAG: "Set",
|
|
79
|
+
_0: "o1",
|
|
80
|
+
_1: placed
|
|
81
|
+
}
|
|
82
|
+
]]))).toEqual([[
|
|
83
|
+
"Placed",
|
|
84
|
+
nine
|
|
85
|
+
]]);
|
|
86
|
+
});
|
|
87
|
+
globalThis.test("appends one entry per transition, in order", () => {
|
|
88
|
+
globalThis.expect(statesOf(run([
|
|
89
|
+
[
|
|
90
|
+
nine,
|
|
91
|
+
{
|
|
92
|
+
TAG: "Set",
|
|
93
|
+
_0: "o1",
|
|
94
|
+
_1: placed
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
[
|
|
98
|
+
ten,
|
|
99
|
+
{
|
|
100
|
+
TAG: "Update",
|
|
101
|
+
_0: "o1",
|
|
102
|
+
_1: s => ({
|
|
103
|
+
orderId: s.orderId,
|
|
104
|
+
lifecycle: "Shipped",
|
|
105
|
+
trail: s.trail
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
]))).toEqual([
|
|
110
|
+
[
|
|
111
|
+
"Placed",
|
|
112
|
+
nine
|
|
113
|
+
],
|
|
114
|
+
[
|
|
115
|
+
"Shipped",
|
|
116
|
+
ten
|
|
117
|
+
]
|
|
118
|
+
]);
|
|
119
|
+
});
|
|
120
|
+
globalThis.test("keeps both visits when a lifecycle revisits a state", () => {
|
|
121
|
+
globalThis.expect(statesOf(run([
|
|
122
|
+
[
|
|
123
|
+
nine,
|
|
124
|
+
{
|
|
125
|
+
TAG: "Set",
|
|
126
|
+
_0: "o1",
|
|
127
|
+
_1: placed
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
[
|
|
131
|
+
ten,
|
|
132
|
+
{
|
|
133
|
+
TAG: "Update",
|
|
134
|
+
_0: "o1",
|
|
135
|
+
_1: s => ({
|
|
136
|
+
orderId: s.orderId,
|
|
137
|
+
lifecycle: "Cancelled",
|
|
138
|
+
trail: s.trail
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
],
|
|
142
|
+
[
|
|
143
|
+
eleven,
|
|
144
|
+
{
|
|
145
|
+
TAG: "Update",
|
|
146
|
+
_0: "o1",
|
|
147
|
+
_1: s => ({
|
|
148
|
+
orderId: s.orderId,
|
|
149
|
+
lifecycle: "Placed",
|
|
150
|
+
trail: s.trail
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
]))).toEqual([
|
|
155
|
+
[
|
|
156
|
+
"Placed",
|
|
157
|
+
nine
|
|
158
|
+
],
|
|
159
|
+
[
|
|
160
|
+
"Cancelled",
|
|
161
|
+
ten
|
|
162
|
+
],
|
|
163
|
+
[
|
|
164
|
+
"Placed",
|
|
165
|
+
eleven
|
|
166
|
+
]
|
|
167
|
+
]);
|
|
168
|
+
});
|
|
169
|
+
globalThis.test("appends nothing for an update that leaves the lifecycle alone", () => {
|
|
170
|
+
globalThis.expect(statesOf(run([
|
|
171
|
+
[
|
|
172
|
+
nine,
|
|
173
|
+
{
|
|
174
|
+
TAG: "Set",
|
|
175
|
+
_0: "o1",
|
|
176
|
+
_1: placed
|
|
177
|
+
}
|
|
178
|
+
],
|
|
179
|
+
[
|
|
180
|
+
ten,
|
|
181
|
+
{
|
|
182
|
+
TAG: "Update",
|
|
183
|
+
_0: "o1",
|
|
184
|
+
_1: s => ({
|
|
185
|
+
orderId: "o1-renamed",
|
|
186
|
+
lifecycle: s.lifecycle,
|
|
187
|
+
trail: s.trail
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
]))).toEqual([[
|
|
192
|
+
"Placed",
|
|
193
|
+
nine
|
|
194
|
+
]]);
|
|
195
|
+
});
|
|
196
|
+
globalThis.test("a rebuild from the same events produces an identical trail", () => {
|
|
197
|
+
let events = [
|
|
198
|
+
[
|
|
199
|
+
nine,
|
|
200
|
+
{
|
|
201
|
+
TAG: "Set",
|
|
202
|
+
_0: "o1",
|
|
203
|
+
_1: placed
|
|
204
|
+
}
|
|
205
|
+
],
|
|
206
|
+
[
|
|
207
|
+
ten,
|
|
208
|
+
{
|
|
209
|
+
TAG: "Update",
|
|
210
|
+
_0: "o1",
|
|
211
|
+
_1: s => ({
|
|
212
|
+
orderId: s.orderId,
|
|
213
|
+
lifecycle: "Shipped",
|
|
214
|
+
trail: s.trail
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
]
|
|
218
|
+
];
|
|
219
|
+
globalThis.expect(statesOf(run(events))).toEqual(statesOf(run(events)));
|
|
220
|
+
});
|
|
221
|
+
globalThis.test("carries the lifecycleTrail semantic onto the emitted JSON Schema", () => {
|
|
222
|
+
let field = Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(SuryToJsonSchema$ReventlessCore.deriveObjectSchema(undefined, "Order", orderSchema)), o => o["properties"]), Stdlib_JSON.Decode.object), p => p["trail"]), Stdlib_JSON.Decode.object);
|
|
223
|
+
globalThis.expect(Stdlib_Option.flatMap(field, f => f["x-reventless-semantic"])).toEqual("lifecycleTrail");
|
|
224
|
+
});
|
|
225
|
+
globalThis.test("names the entry's state after the record's own lifecycle enum", () => {
|
|
226
|
+
let fields = SchemaType$ReventlessCore.fromSuryObject("Order", orderSchema);
|
|
227
|
+
let match = Stdlib_Option.flatMap(fields, f => f["trail"]);
|
|
228
|
+
let enumName;
|
|
229
|
+
if (typeof match === "object" && match.TAG === "Semantic") {
|
|
230
|
+
let match$1 = match._1;
|
|
231
|
+
if (typeof match$1 !== "object" || match$1.TAG !== "ArrayOf") {
|
|
232
|
+
enumName = undefined;
|
|
233
|
+
} else {
|
|
234
|
+
let match$2 = match$1._0;
|
|
235
|
+
if (typeof match$2 !== "object" || match$2.TAG !== "ObjectRef") {
|
|
236
|
+
enumName = undefined;
|
|
237
|
+
} else {
|
|
238
|
+
let match$3 = match$2._1["state"];
|
|
239
|
+
enumName = typeof match$3 === "object" && match$3.TAG === "Enum" ? match$3._0 : undefined;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
} else {
|
|
243
|
+
enumName = undefined;
|
|
244
|
+
}
|
|
245
|
+
globalThis.expect(enumName).toEqual("OrderLifecycle");
|
|
246
|
+
});
|
|
247
|
+
globalThis.test("a view that declares no trail is projected unchanged", () => {
|
|
248
|
+
let rewritten = Projection$ReventlessCore.rewriteAction({
|
|
249
|
+
TAG: "Set",
|
|
250
|
+
_0: "o1",
|
|
251
|
+
_1: {
|
|
252
|
+
orderId: "o1",
|
|
253
|
+
lifecycle: "Placed"
|
|
254
|
+
}
|
|
255
|
+
}, nine, plainSchema);
|
|
256
|
+
let tmp;
|
|
257
|
+
tmp = typeof rewritten !== "object" || rewritten.TAG !== "Set" ? undefined : [
|
|
258
|
+
rewritten._0,
|
|
259
|
+
rewritten._1.lifecycle
|
|
260
|
+
];
|
|
261
|
+
globalThis.expect(tmp).toEqual([
|
|
262
|
+
"o1",
|
|
263
|
+
"Placed"
|
|
264
|
+
]);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
export {
|
|
269
|
+
lifecycleSchema,
|
|
270
|
+
orderSchema,
|
|
271
|
+
plainSchema,
|
|
272
|
+
nine,
|
|
273
|
+
ten,
|
|
274
|
+
eleven,
|
|
275
|
+
placed,
|
|
276
|
+
apply,
|
|
277
|
+
run,
|
|
278
|
+
statesOf,
|
|
279
|
+
}
|
|
280
|
+
/* lifecycleSchema Not a pure module */
|
/package/src/admin/UiFragmentRegistry/{StateChangeSlice → StateChange}/UiFragmentRegistry.res
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/src/admin/UiFragmentRegistry/{StateViewSlice → StateView}/UiFragments_Projection.res
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|