@reventlessdev/online-shop-hybrid-ordering 1.0.0-alpha.100

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.
Files changed (86) hide show
  1. package/CHANGELOG.md +904 -0
  2. package/LICENSE +202 -0
  3. package/__mocks__/emptyModule.js +1 -0
  4. package/package.json +57 -0
  5. package/rescript.json +37 -0
  6. package/src/CatalogProduct/StateChangeSlice/SyncCatalogProduct.res +29 -0
  7. package/src/CatalogProduct/StateChangeSlice/SyncCatalogProduct.res.mjs +71 -0
  8. package/src/CatalogProduct/StateChangeSlice/SyncCatalogProduct_Behavior.res +27 -0
  9. package/src/CatalogProduct/StateChangeSlice/SyncCatalogProduct_Behavior.res.mjs +73 -0
  10. package/src/CatalogProduct/StateViewSliceStream/AvailableProducts.res +15 -0
  11. package/src/CatalogProduct/StateViewSliceStream/AvailableProducts.res.mjs +69 -0
  12. package/src/CatalogProduct/StateViewSliceStream/AvailableProducts_Projection.res +8 -0
  13. package/src/CatalogProduct/StateViewSliceStream/AvailableProducts_Projection.res.mjs +38 -0
  14. package/src/Customer/Aggregate/Customer.res +24 -0
  15. package/src/Customer/Aggregate/Customer.res.mjs +64 -0
  16. package/src/Customer/Aggregate/Customer_Behavior.res +41 -0
  17. package/src/Customer/Aggregate/Customer_Behavior.res.mjs +143 -0
  18. package/src/Customer/ReadModelStream/Customers.res +15 -0
  19. package/src/Customer/ReadModelStream/Customers.res.mjs +44 -0
  20. package/src/Customer/ReadModelStream/Customers_Projections.res +78 -0
  21. package/src/Customer/ReadModelStream/Customers_Projections.res.mjs +153 -0
  22. package/src/Extension/Products_Extension.res +23 -0
  23. package/src/Extension/Products_Extension.res.mjs +43 -0
  24. package/src/ExtensionPoint/Orders_ExtensionPointMapping.res +33 -0
  25. package/src/ExtensionPoint/Orders_ExtensionPointMapping.res.mjs +82 -0
  26. package/src/Order/AutomationSlice/AutoShipOrder.res +19 -0
  27. package/src/Order/AutomationSlice/AutoShipOrder.res.mjs +42 -0
  28. package/src/Order/AutomationSlice/AutoShipOrder_Automation.res +37 -0
  29. package/src/Order/AutomationSlice/AutoShipOrder_Automation.res.mjs +101 -0
  30. package/src/Order/OutboundTranslationSlice/SendOrderConfirmation.res +22 -0
  31. package/src/Order/OutboundTranslationSlice/SendOrderConfirmation.res.mjs +45 -0
  32. package/src/Order/OutboundTranslationSlice/SendOrderConfirmation_Translation.res +24 -0
  33. package/src/Order/OutboundTranslationSlice/SendOrderConfirmation_Translation.res.mjs +46 -0
  34. package/src/Order/StateChangeSlice/CancelOrder.res +29 -0
  35. package/src/Order/StateChangeSlice/CancelOrder.res.mjs +75 -0
  36. package/src/Order/StateChangeSlice/CancelOrder_Behavior.res +35 -0
  37. package/src/Order/StateChangeSlice/CancelOrder_Behavior.res.mjs +110 -0
  38. package/src/Order/StateChangeSlice/PlaceOrder.res +28 -0
  39. package/src/Order/StateChangeSlice/PlaceOrder.res.mjs +63 -0
  40. package/src/Order/StateChangeSlice/PlaceOrder_Behavior.res +39 -0
  41. package/src/Order/StateChangeSlice/PlaceOrder_Behavior.res.mjs +70 -0
  42. package/src/Order/StateChangeSlice/RefundOrder.res +27 -0
  43. package/src/Order/StateChangeSlice/RefundOrder.res.mjs +59 -0
  44. package/src/Order/StateChangeSlice/RefundOrder_Behavior.res +26 -0
  45. package/src/Order/StateChangeSlice/RefundOrder_Behavior.res.mjs +77 -0
  46. package/src/Order/StateChangeSlice/ShipOrder.res +23 -0
  47. package/src/Order/StateChangeSlice/ShipOrder.res.mjs +56 -0
  48. package/src/Order/StateChangeSlice/ShipOrder_Behavior.res +26 -0
  49. package/src/Order/StateChangeSlice/ShipOrder_Behavior.res.mjs +73 -0
  50. package/src/Order/StateViewSliceStream/Orders.res +24 -0
  51. package/src/Order/StateViewSliceStream/Orders.res.mjs +80 -0
  52. package/src/Order/StateViewSliceStream/Orders_Projection.res +10 -0
  53. package/src/Order/StateViewSliceStream/Orders_Projection.res.mjs +52 -0
  54. package/src/Plugin.res +74 -0
  55. package/src/Plugin.res.mjs +304 -0
  56. package/src/Service/EmailService.res +3 -0
  57. package/src/Service/EmailService.res.mjs +11 -0
  58. package/src/plugin.json +1 -0
  59. package/tests/CatalogProduct/StateChangeSlice/SyncCatalogProduct_GWT.res +27 -0
  60. package/tests/CatalogProduct/StateChangeSlice/SyncCatalogProduct_GWT.res.mjs +109 -0
  61. package/tests/CatalogProduct/StateViewSliceStream/AvailableProducts_GWT.res +15 -0
  62. package/tests/CatalogProduct/StateViewSliceStream/AvailableProducts_GWT.res.mjs +93 -0
  63. package/tests/Customer/Aggregate/Customer_GWT.res +63 -0
  64. package/tests/Customer/Aggregate/Customer_GWT.res.mjs +153 -0
  65. package/tests/Customer/ReadModelStream/Customers_GWT.res +84 -0
  66. package/tests/Customer/ReadModelStream/Customers_GWT.res.mjs +90 -0
  67. package/tests/Extension/Products_Extension_GWT.res +23 -0
  68. package/tests/Extension/Products_Extension_GWT.res.mjs +108 -0
  69. package/tests/ExtensionPoint/Orders_ExtensionPointMapping_GWT.res +23 -0
  70. package/tests/ExtensionPoint/Orders_ExtensionPointMapping_GWT.res.mjs +139 -0
  71. package/tests/Flow/OrderingFlow_GWT.res +69 -0
  72. package/tests/Flow/OrderingFlow_GWT.res.mjs +184 -0
  73. package/tests/Order/AutomationSlice/AutoShipOrder_GWT.res +55 -0
  74. package/tests/Order/AutomationSlice/AutoShipOrder_GWT.res.mjs +133 -0
  75. package/tests/Order/OutboundTranslationSlice/SendOrderConfirmation_GWT.res +30 -0
  76. package/tests/Order/OutboundTranslationSlice/SendOrderConfirmation_GWT.res.mjs +102 -0
  77. package/tests/Order/StateChangeSlice/CancelOrder_GWT.res +45 -0
  78. package/tests/Order/StateChangeSlice/CancelOrder_GWT.res.mjs +131 -0
  79. package/tests/Order/StateChangeSlice/PlaceOrder_GWT.res +33 -0
  80. package/tests/Order/StateChangeSlice/PlaceOrder_GWT.res.mjs +139 -0
  81. package/tests/Order/StateChangeSlice/RefundOrder_GWT.res +31 -0
  82. package/tests/Order/StateChangeSlice/RefundOrder_GWT.res.mjs +100 -0
  83. package/tests/Order/StateChangeSlice/ShipOrder_GWT.res +27 -0
  84. package/tests/Order/StateChangeSlice/ShipOrder_GWT.res.mjs +91 -0
  85. package/tests/Order/StateViewSliceStream/Orders_GWT.res +36 -0
  86. package/tests/Order/StateViewSliceStream/Orders_GWT.res.mjs +114 -0
@@ -0,0 +1,139 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
4
+ import * as Delegate_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Delegate_GWT.res.mjs";
5
+ import * as Orders_ExtensionPoint$OrderingSpec from "@reventlessdev/online-shop-hybrid-ordering-spec/src/Orders_ExtensionPoint.res.mjs";
6
+ import * as Orders_ExtensionPointMapping$OrderingPlugin from "../../src/ExtensionPoint/Orders_ExtensionPointMapping.res.mjs";
7
+
8
+ let include = Delegate_GWT$ReventlessGwt.FromExtensionPoint({
9
+ ExtensionPoint: {
10
+ name: Orders_ExtensionPoint$OrderingSpec.name,
11
+ moduleUrl: Orders_ExtensionPoint$OrderingSpec.moduleUrl,
12
+ commandSchema: Orders_ExtensionPoint$OrderingSpec.commandSchema,
13
+ eventSchema: Orders_ExtensionPoint$OrderingSpec.eventSchema,
14
+ directiveSchema: Orders_ExtensionPoint$OrderingSpec.directiveSchema
15
+ },
16
+ Delegate: {
17
+ Id: Id$Reventless.$$String,
18
+ name: Orders_ExtensionPointMapping$OrderingPlugin.Delegate.name,
19
+ eventSchema: Orders_ExtensionPointMapping$OrderingPlugin.Delegate.eventSchema,
20
+ errorSchema: Orders_ExtensionPointMapping$OrderingPlugin.Delegate.errorSchema,
21
+ commandSchema: Orders_ExtensionPointMapping$OrderingPlugin.Delegate.commandSchema,
22
+ moduleUrl: Orders_ExtensionPointMapping$OrderingPlugin.Delegate.moduleUrl,
23
+ commandAuthorization: Orders_ExtensionPointMapping$OrderingPlugin.Delegate.commandAuthorization
24
+ },
25
+ moduleUrl: Orders_ExtensionPointMapping$OrderingPlugin.moduleUrl,
26
+ mapIncomingCommand: Orders_ExtensionPointMapping$OrderingPlugin.mapIncomingCommand,
27
+ mapOutgoingEvent: Orders_ExtensionPointMapping$OrderingPlugin.mapOutgoingEvent
28
+ });
29
+
30
+ let describe = include.describe;
31
+
32
+ let test = include.test;
33
+
34
+ let whenDelegateEvent = include.whenDelegateEvent;
35
+
36
+ let thenPublishesEvents = include.thenPublishesEvents;
37
+
38
+ describe("Orders ExtensionPoint mapping — per-product fan-out", () => {
39
+ test("OrderPlaced fans out to one ItemOrdered per product", undefined, () => thenPublishesEvents(whenDelegateEvent({
40
+ TAG: "OrderPlaced",
41
+ orderId: "o1",
42
+ customerId: "c1",
43
+ productIds: [
44
+ "p1",
45
+ "p2"
46
+ ]
47
+ }), [
48
+ [
49
+ "p1",
50
+ {
51
+ TAG: "ItemOrdered",
52
+ productId: "p1",
53
+ orderId: "o1",
54
+ customerId: "c1"
55
+ }
56
+ ],
57
+ [
58
+ "p2",
59
+ {
60
+ TAG: "ItemOrdered",
61
+ productId: "p2",
62
+ orderId: "o1",
63
+ customerId: "c1"
64
+ }
65
+ ]
66
+ ]));
67
+ test("OrderCancelled fans out to one ItemOrderCancelled per product", undefined, () => thenPublishesEvents(whenDelegateEvent({
68
+ TAG: "OrderCancelled",
69
+ orderId: "o1",
70
+ productIds: [
71
+ "p1",
72
+ "p2"
73
+ ]
74
+ }), [
75
+ [
76
+ "p1",
77
+ {
78
+ TAG: "ItemOrderCancelled",
79
+ productId: "p1",
80
+ orderId: "o1"
81
+ }
82
+ ],
83
+ [
84
+ "p2",
85
+ {
86
+ TAG: "ItemOrderCancelled",
87
+ productId: "p2",
88
+ orderId: "o1"
89
+ }
90
+ ]
91
+ ]));
92
+ });
93
+
94
+ let encEvent = include.encEvent;
95
+
96
+ let encCommand = include.encCommand;
97
+
98
+ let encDirective = include.encDirective;
99
+
100
+ let EvCore = include.EvCore;
101
+
102
+ let CmdCore = include.CmdCore;
103
+
104
+ let thenPublishesNothing = include.thenPublishesNothing;
105
+
106
+ let thenPublishesEvent = include.thenPublishesEvent;
107
+
108
+ let whenIncomingCommand = include.whenIncomingCommand;
109
+
110
+ let thenPublishesCommand = include.thenPublishesCommand;
111
+
112
+ let thenPublishesCommands = include.thenPublishesCommands;
113
+
114
+ let thenHandlesDirective = include.thenHandlesDirective;
115
+
116
+ let thenHandlesDirectives = include.thenHandlesDirectives;
117
+
118
+ let thenHandlesNoDirective = include.thenHandlesNoDirective;
119
+
120
+ export {
121
+ encEvent,
122
+ encCommand,
123
+ encDirective,
124
+ EvCore,
125
+ CmdCore,
126
+ describe,
127
+ test,
128
+ thenPublishesNothing,
129
+ whenDelegateEvent,
130
+ thenPublishesEvent,
131
+ thenPublishesEvents,
132
+ whenIncomingCommand,
133
+ thenPublishesCommand,
134
+ thenPublishesCommands,
135
+ thenHandlesDirective,
136
+ thenHandlesDirectives,
137
+ thenHandlesNoDirective,
138
+ }
139
+ /* include Not a pure module */
@@ -0,0 +1,69 @@
1
+ // Cross-slice flow GWT for the Ordering plugin: one declarative chain threads a
2
+ // single order through every tile of its Event Modeling lane —
3
+ //
4
+ // PlaceOrder ─→ OrderPlaced
5
+ // ├─ AutoShipOrder reacts → ShipOrder ─→ OrderShipped
6
+ // ├─ Orders (view) : status Placed → Shipped
7
+ // └─ SendOrderConfirmation : confirmation effect fired
8
+ //
9
+ // PlaceOrder only succeeds because the referenced product was synced first, so
10
+ // the flow seeds a CatalogProductSynced event before placing the order.
11
+ @@reventless.gwt
12
+
13
+ // Compose the automation onto a flat slice — the production split keeps
14
+ // collect/resolve inside the per-source mapping; the GWT needs them together.
15
+ let testContext: Reventless.AutomationSlice.context = {
16
+ environment: "test",
17
+ platformName: "test",
18
+ pluginName: "ordering",
19
+ sliceName: "AutoShipOrder",
20
+ }
21
+
22
+ module AutoShipOrderSlice = {
23
+ include AutoShipOrder
24
+ type consumedEvent = AutoShipOrder_Automation.FromOrderingDcb.sourceEvent
25
+ let consumedEventSchema = AutoShipOrder_Automation.FromOrderingDcb.sourceEventSchema
26
+ let collect = e => AutoShipOrder_Automation.FromOrderingDcb.collect(e, testContext)
27
+ let resolve = AutoShipOrder_Automation.FromOrderingDcb.resolve
28
+ let process = AutoShipOrder_Automation.process
29
+ }
30
+
31
+ module ConfirmSlice = {
32
+ include SendOrderConfirmation
33
+ let collect = SendOrderConfirmation_Translation.collect
34
+ }
35
+
36
+ module Sync = CommandStep(SyncCatalogProduct, SyncCatalogProduct_Behavior)
37
+ module Place = CommandStep(PlaceOrder, PlaceOrder_Behavior)
38
+ module Auto = AutomationStep(AutoShipOrderSlice)
39
+ module Ship = CommandStep(ShipOrder, ShipOrder_Behavior)
40
+ module OrdersView = ViewStep(Orders, Orders_Projection)
41
+ module Confirm = OutboundStep(ConfirmSlice)
42
+
43
+ describe("Ordering flow — place → auto-ship → confirm", () => {
44
+ test("an order is placed, auto-shipped, projected as Shipped, and confirmed", () =>
45
+ start
46
+ ->Sync.givenEvents([
47
+ SyncCatalogProduct.CatalogProductSynced({productId: "p1", name: "Book", price: 9.99}),
48
+ ])
49
+ ->Place.whenCommand(PlaceOrder.PlaceOrder({orderId: "o1", customerId: "c1", productIds: ["p1"]}))
50
+ ->Place.thenEvent(
51
+ PlaceOrder.OrderPlaced({orderId: "o1", customerId: "c1", productIds: ["p1"]}),
52
+ )
53
+ ->Auto.whenReacts
54
+ ->Auto.thenIssuesCommand(AutoShipOrder.ShipOrder({orderId: "o1"}))
55
+ ->Ship.whenCommand(ShipOrder.ShipOrder({orderId: "o1"}))
56
+ ->Ship.thenEvent(ShipOrder.OrderShipped({orderId: "o1"}))
57
+ ->OrdersView.thenViewState(
58
+ "o1",
59
+ {Orders.orderId: "o1", customerId: "c1", productIds: ["p1"], status: Shipped},
60
+ )
61
+ ->Confirm.thenOutbound([("o1", {SendOrderConfirmation.orderId: "o1", customerId: "c1"})])
62
+ )
63
+
64
+ test("placing an order for an unsynced product is rejected", () =>
65
+ start
66
+ ->Place.whenCommand(PlaceOrder.PlaceOrder({orderId: "o1", customerId: "c1", productIds: ["p1"]}))
67
+ ->Place.thenError(ProductsNotAvailable({missing: ["p1"]}))
68
+ )
69
+ })
@@ -0,0 +1,184 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Orders$OrderingPlugin from "../../src/Order/StateViewSliceStream/Orders.res.mjs";
4
+ import * as Flow_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Flow_GWT.res.mjs";
5
+ import * as ShipOrder$OrderingPlugin from "../../src/Order/StateChangeSlice/ShipOrder.res.mjs";
6
+ import * as PlaceOrder$OrderingPlugin from "../../src/Order/StateChangeSlice/PlaceOrder.res.mjs";
7
+ import * as AutoShipOrder$OrderingPlugin from "../../src/Order/AutomationSlice/AutoShipOrder.res.mjs";
8
+ import * as Orders_Projection$OrderingPlugin from "../../src/Order/StateViewSliceStream/Orders_Projection.res.mjs";
9
+ import * as ShipOrder_Behavior$OrderingPlugin from "../../src/Order/StateChangeSlice/ShipOrder_Behavior.res.mjs";
10
+ import * as SyncCatalogProduct$OrderingPlugin from "../../src/CatalogProduct/StateChangeSlice/SyncCatalogProduct.res.mjs";
11
+ import * as PlaceOrder_Behavior$OrderingPlugin from "../../src/Order/StateChangeSlice/PlaceOrder_Behavior.res.mjs";
12
+ import * as SendOrderConfirmation$OrderingPlugin from "../../src/Order/OutboundTranslationSlice/SendOrderConfirmation.res.mjs";
13
+ import * as AutoShipOrder_Automation$OrderingPlugin from "../../src/Order/AutomationSlice/AutoShipOrder_Automation.res.mjs";
14
+ import * as SyncCatalogProduct_Behavior$OrderingPlugin from "../../src/CatalogProduct/StateChangeSlice/SyncCatalogProduct_Behavior.res.mjs";
15
+ import * as SendOrderConfirmation_Translation$OrderingPlugin from "../../src/Order/OutboundTranslationSlice/SendOrderConfirmation_Translation.res.mjs";
16
+
17
+ let testContext = {
18
+ environment: "test",
19
+ platformName: "test",
20
+ pluginName: "ordering",
21
+ sliceName: "AutoShipOrder"
22
+ };
23
+
24
+ let consumedEventSchema = AutoShipOrder_Automation$OrderingPlugin.FromOrderingDcb.sourceEventSchema;
25
+
26
+ function collect(e) {
27
+ return AutoShipOrder_Automation$OrderingPlugin.FromOrderingDcb.collect(e, testContext);
28
+ }
29
+
30
+ let resolve = AutoShipOrder_Automation$OrderingPlugin.FromOrderingDcb.resolve;
31
+
32
+ let AutoShipOrderSlice = {
33
+ name: AutoShipOrder$OrderingPlugin.name,
34
+ Id: AutoShipOrder$OrderingPlugin.Id,
35
+ todoItemSchema: AutoShipOrder$OrderingPlugin.todoItemSchema,
36
+ commandSchema: AutoShipOrder$OrderingPlugin.commandSchema,
37
+ maxRetries: AutoShipOrder$OrderingPlugin.maxRetries,
38
+ heartbeatInterval: AutoShipOrder$OrderingPlugin.heartbeatInterval,
39
+ targetName: AutoShipOrder$OrderingPlugin.targetName,
40
+ moduleUrl: AutoShipOrder$OrderingPlugin.moduleUrl,
41
+ commandAuthorization: AutoShipOrder$OrderingPlugin.commandAuthorization,
42
+ consumedEventSchema: consumedEventSchema,
43
+ collect: collect,
44
+ resolve: resolve,
45
+ process: AutoShipOrder_Automation$OrderingPlugin.process
46
+ };
47
+
48
+ let ConfirmSlice = {
49
+ name: SendOrderConfirmation$OrderingPlugin.name,
50
+ Id: SendOrderConfirmation$OrderingPlugin.Id,
51
+ consumedEventSchema: SendOrderConfirmation$OrderingPlugin.consumedEventSchema,
52
+ outboundItemSchema: SendOrderConfirmation$OrderingPlugin.outboundItemSchema,
53
+ inboundCommandSchema: SendOrderConfirmation$OrderingPlugin.inboundCommandSchema,
54
+ maxRetries: SendOrderConfirmation$OrderingPlugin.maxRetries,
55
+ heartbeatInterval: SendOrderConfirmation$OrderingPlugin.heartbeatInterval,
56
+ targetName: undefined,
57
+ externalSystem: SendOrderConfirmation$OrderingPlugin.externalSystem,
58
+ moduleUrl: SendOrderConfirmation$OrderingPlugin.moduleUrl,
59
+ collect: SendOrderConfirmation_Translation$OrderingPlugin.collect
60
+ };
61
+
62
+ let Sync = Flow_GWT$ReventlessGwt.CommandStep({
63
+ name: SyncCatalogProduct$OrderingPlugin.name,
64
+ consumedEventSchema: SyncCatalogProduct$OrderingPlugin.consumedEventSchema,
65
+ commandSchema: SyncCatalogProduct$OrderingPlugin.commandSchema,
66
+ errorSchema: SyncCatalogProduct$OrderingPlugin.errorSchema,
67
+ eventSchema: SyncCatalogProduct$OrderingPlugin.eventSchema
68
+ })({
69
+ initialState: SyncCatalogProduct_Behavior$OrderingPlugin.initialState,
70
+ evolve: SyncCatalogProduct_Behavior$OrderingPlugin.evolve,
71
+ decide: SyncCatalogProduct_Behavior$OrderingPlugin.decide
72
+ });
73
+
74
+ let Place = Flow_GWT$ReventlessGwt.CommandStep({
75
+ name: PlaceOrder$OrderingPlugin.name,
76
+ consumedEventSchema: PlaceOrder$OrderingPlugin.consumedEventSchema,
77
+ commandSchema: PlaceOrder$OrderingPlugin.commandSchema,
78
+ errorSchema: PlaceOrder$OrderingPlugin.errorSchema,
79
+ eventSchema: PlaceOrder$OrderingPlugin.eventSchema
80
+ })({
81
+ initialState: PlaceOrder_Behavior$OrderingPlugin.initialState,
82
+ evolve: PlaceOrder_Behavior$OrderingPlugin.evolve,
83
+ decide: PlaceOrder_Behavior$OrderingPlugin.decide
84
+ });
85
+
86
+ let Auto = Flow_GWT$ReventlessGwt.AutomationStep({
87
+ name: AutoShipOrder$OrderingPlugin.name,
88
+ consumedEventSchema: consumedEventSchema,
89
+ todoItemSchema: AutoShipOrder$OrderingPlugin.todoItemSchema,
90
+ commandSchema: AutoShipOrder$OrderingPlugin.commandSchema,
91
+ collect: collect,
92
+ resolve: resolve,
93
+ process: AutoShipOrder_Automation$OrderingPlugin.process
94
+ });
95
+
96
+ let Ship = Flow_GWT$ReventlessGwt.CommandStep({
97
+ name: ShipOrder$OrderingPlugin.name,
98
+ consumedEventSchema: ShipOrder$OrderingPlugin.consumedEventSchema,
99
+ commandSchema: ShipOrder$OrderingPlugin.commandSchema,
100
+ errorSchema: ShipOrder$OrderingPlugin.errorSchema,
101
+ eventSchema: ShipOrder$OrderingPlugin.eventSchema
102
+ })({
103
+ initialState: ShipOrder_Behavior$OrderingPlugin.initialState,
104
+ evolve: ShipOrder_Behavior$OrderingPlugin.evolve,
105
+ decide: ShipOrder_Behavior$OrderingPlugin.decide
106
+ });
107
+
108
+ let OrdersView = Flow_GWT$ReventlessGwt.ViewStep({
109
+ name: Orders$OrderingPlugin.name,
110
+ stateSchema: Orders$OrderingPlugin.stateSchema,
111
+ consumedEventSchema: Orders$OrderingPlugin.consumedEventSchema,
112
+ subIdConfig: undefined
113
+ })({
114
+ project: Orders_Projection$OrderingPlugin.project
115
+ });
116
+
117
+ let Confirm = Flow_GWT$ReventlessGwt.OutboundStep({
118
+ name: SendOrderConfirmation$OrderingPlugin.name,
119
+ consumedEventSchema: SendOrderConfirmation$OrderingPlugin.consumedEventSchema,
120
+ outboundItemSchema: SendOrderConfirmation$OrderingPlugin.outboundItemSchema,
121
+ inboundCommandSchema: SendOrderConfirmation$OrderingPlugin.inboundCommandSchema,
122
+ collect: SendOrderConfirmation_Translation$OrderingPlugin.collect
123
+ });
124
+
125
+ Flow_GWT$ReventlessGwt.describe("Ordering flow — place → auto-ship → confirm", () => {
126
+ Flow_GWT$ReventlessGwt.test("an order is placed, auto-shipped, projected as Shipped, and confirmed", undefined, () => Confirm.thenOutbound(OrdersView.thenViewState(Ship.thenEvent(Ship.whenCommand(Auto.thenIssuesCommand(Auto.whenReacts(Place.thenEvent(Place.whenCommand(Sync.givenEvents(Flow_GWT$ReventlessGwt.start, [{
127
+ TAG: "CatalogProductSynced",
128
+ productId: "p1",
129
+ name: "Book",
130
+ price: 9.99
131
+ }]), {
132
+ TAG: "PlaceOrder",
133
+ orderId: "o1",
134
+ customerId: "c1",
135
+ productIds: ["p1"]
136
+ }), {
137
+ TAG: "OrderPlaced",
138
+ orderId: "o1",
139
+ customerId: "c1",
140
+ productIds: ["p1"]
141
+ })), {
142
+ TAG: "ShipOrder",
143
+ orderId: "o1"
144
+ }), {
145
+ TAG: "ShipOrder",
146
+ orderId: "o1"
147
+ }), {
148
+ TAG: "OrderShipped",
149
+ orderId: "o1"
150
+ }), "o1", {
151
+ orderId: "o1",
152
+ customerId: "c1",
153
+ productIds: ["p1"],
154
+ status: "Shipped"
155
+ }), [[
156
+ "o1",
157
+ {
158
+ orderId: "o1",
159
+ customerId: "c1"
160
+ }
161
+ ]]));
162
+ Flow_GWT$ReventlessGwt.test("placing an order for an unsynced product is rejected", undefined, () => Place.thenError(Place.whenCommand(Flow_GWT$ReventlessGwt.start, {
163
+ TAG: "PlaceOrder",
164
+ orderId: "o1",
165
+ customerId: "c1",
166
+ productIds: ["p1"]
167
+ }), {
168
+ TAG: "ProductsNotAvailable",
169
+ missing: ["p1"]
170
+ }));
171
+ });
172
+
173
+ export {
174
+ testContext,
175
+ AutoShipOrderSlice,
176
+ ConfirmSlice,
177
+ Sync,
178
+ Place,
179
+ Auto,
180
+ Ship,
181
+ OrdersView,
182
+ Confirm,
183
+ }
184
+ /* Sync Not a pure module */
@@ -0,0 +1,55 @@
1
+ // `Automation_GWT.Make` expects a single SliceSpec with `collect`, `resolve`
2
+ // and `process` as top-level bindings. Compose them onto the spec module
3
+ // locally — the production split form keeps `collect`/`resolve` inside the
4
+ // per-source mapping.
5
+
6
+ let testContext: Reventless.AutomationSlice.context = {
7
+ environment: "test",
8
+ platformName: "test",
9
+ pluginName: "ordering",
10
+ sliceName: "AutoShipOrder",
11
+ }
12
+
13
+ module AutoShipOrderSlice = {
14
+ include AutoShipOrder
15
+ type consumedEvent = AutoShipOrder_Automation.FromOrderingDcb.sourceEvent
16
+ let consumedEventSchema = AutoShipOrder_Automation.FromOrderingDcb.sourceEventSchema
17
+
18
+ let collect = e => AutoShipOrder_Automation.FromOrderingDcb.collect(e, testContext)
19
+ let resolve = AutoShipOrder_Automation.FromOrderingDcb.resolve
20
+ let process = AutoShipOrder_Automation.process
21
+ }
22
+
23
+ @@reventless.gwt
24
+
25
+ describe("AutoShipOrder AutomationSlice", () => {
26
+ test("collect: OrderPlaced creates a pending TODO", () =>
27
+ givenEvent(OrderPlaced({orderId: "o1"}))
28
+ ->whenCollect
29
+ ->thenTodos([("o1", {orderId: "o1"})])
30
+ )
31
+
32
+ test("collect: OrderShipped is ignored (no TODO)", () =>
33
+ givenEvent(OrderShipped({orderId: "o1"}))
34
+ ->whenCollect
35
+ ->thenTodos([])
36
+ )
37
+
38
+ test("resolve: OrderShipped marks the TODO done", () =>
39
+ givenEvent(OrderShipped({orderId: "o1"}))
40
+ ->whenResolve
41
+ ->thenResolved(Some("o1"))
42
+ )
43
+
44
+ test("resolve: OrderPlaced does not mark anything done", () =>
45
+ givenEvent(OrderPlaced({orderId: "o1"}))
46
+ ->whenResolve
47
+ ->thenResolved(None)
48
+ )
49
+
50
+ test("process: pending TODO emits ShipOrder for the same id", () =>
51
+ givenTodo("o1", {orderId: "o1"})
52
+ ->whenProcess
53
+ ->thenCommand("o1", ShipOrder({orderId: "o1"}))
54
+ )
55
+ })
@@ -0,0 +1,133 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as AutoShipOrder$OrderingPlugin from "../../../src/Order/AutomationSlice/AutoShipOrder.res.mjs";
4
+ import * as Automation_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Automation_GWT.res.mjs";
5
+ import * as AutoShipOrder_Automation$OrderingPlugin from "../../../src/Order/AutomationSlice/AutoShipOrder_Automation.res.mjs";
6
+
7
+ let testContext = {
8
+ environment: "test",
9
+ platformName: "test",
10
+ pluginName: "ordering",
11
+ sliceName: "AutoShipOrder"
12
+ };
13
+
14
+ let consumedEventSchema = AutoShipOrder_Automation$OrderingPlugin.FromOrderingDcb.sourceEventSchema;
15
+
16
+ function collect(e) {
17
+ return AutoShipOrder_Automation$OrderingPlugin.FromOrderingDcb.collect(e, testContext);
18
+ }
19
+
20
+ let resolve = AutoShipOrder_Automation$OrderingPlugin.FromOrderingDcb.resolve;
21
+
22
+ let AutoShipOrderSlice = {
23
+ name: AutoShipOrder$OrderingPlugin.name,
24
+ Id: AutoShipOrder$OrderingPlugin.Id,
25
+ todoItemSchema: AutoShipOrder$OrderingPlugin.todoItemSchema,
26
+ commandSchema: AutoShipOrder$OrderingPlugin.commandSchema,
27
+ maxRetries: AutoShipOrder$OrderingPlugin.maxRetries,
28
+ heartbeatInterval: AutoShipOrder$OrderingPlugin.heartbeatInterval,
29
+ targetName: AutoShipOrder$OrderingPlugin.targetName,
30
+ moduleUrl: AutoShipOrder$OrderingPlugin.moduleUrl,
31
+ commandAuthorization: AutoShipOrder$OrderingPlugin.commandAuthorization,
32
+ consumedEventSchema: consumedEventSchema,
33
+ collect: collect,
34
+ resolve: resolve,
35
+ process: AutoShipOrder_Automation$OrderingPlugin.process
36
+ };
37
+
38
+ let include = Automation_GWT$ReventlessGwt.Make({
39
+ name: AutoShipOrder$OrderingPlugin.name,
40
+ consumedEventSchema: consumedEventSchema,
41
+ todoItemSchema: AutoShipOrder$OrderingPlugin.todoItemSchema,
42
+ commandSchema: AutoShipOrder$OrderingPlugin.commandSchema,
43
+ collect: collect,
44
+ resolve: resolve,
45
+ process: AutoShipOrder_Automation$OrderingPlugin.process
46
+ });
47
+
48
+ let describe = include.describe;
49
+
50
+ let test = include.test;
51
+
52
+ let givenEvent = include.givenEvent;
53
+
54
+ let whenCollect = include.whenCollect;
55
+
56
+ let thenTodos = include.thenTodos;
57
+
58
+ let whenResolve = include.whenResolve;
59
+
60
+ let thenResolved = include.thenResolved;
61
+
62
+ let givenTodo = include.givenTodo;
63
+
64
+ let whenProcess = include.whenProcess;
65
+
66
+ let thenCommand = include.thenCommand;
67
+
68
+ describe("AutoShipOrder AutomationSlice", () => {
69
+ test("collect: OrderPlaced creates a pending TODO", () => thenTodos(whenCollect(givenEvent({
70
+ TAG: "OrderPlaced",
71
+ orderId: "o1"
72
+ })), [[
73
+ "o1",
74
+ {
75
+ orderId: "o1"
76
+ }
77
+ ]]));
78
+ test("collect: OrderShipped is ignored (no TODO)", () => thenTodos(whenCollect(givenEvent({
79
+ TAG: "OrderShipped",
80
+ orderId: "o1"
81
+ })), []));
82
+ test("resolve: OrderShipped marks the TODO done", () => thenResolved(whenResolve(givenEvent({
83
+ TAG: "OrderShipped",
84
+ orderId: "o1"
85
+ })), "o1"));
86
+ test("resolve: OrderPlaced does not mark anything done", () => thenResolved(whenResolve(givenEvent({
87
+ TAG: "OrderPlaced",
88
+ orderId: "o1"
89
+ })), undefined));
90
+ test("process: pending TODO emits ShipOrder for the same id", () => thenCommand(whenProcess(givenTodo("o1", {
91
+ orderId: "o1"
92
+ })), "o1", {
93
+ TAG: "ShipOrder",
94
+ orderId: "o1"
95
+ }));
96
+ });
97
+
98
+ let Spec = include.Spec;
99
+
100
+ let thenNoCommand = include.thenNoCommand;
101
+
102
+ let givenEvents = include.givenEvents;
103
+
104
+ let whenSweep = include.whenSweep;
105
+
106
+ let thenCommands = include.thenCommands;
107
+
108
+ let andThenEvents = include.andThenEvents;
109
+
110
+ let thenScenarioTodos = include.thenScenarioTodos;
111
+
112
+ export {
113
+ testContext,
114
+ AutoShipOrderSlice,
115
+ Spec,
116
+ describe,
117
+ test,
118
+ givenEvent,
119
+ whenCollect,
120
+ thenTodos,
121
+ whenResolve,
122
+ thenResolved,
123
+ givenTodo,
124
+ whenProcess,
125
+ thenCommand,
126
+ thenNoCommand,
127
+ givenEvents,
128
+ whenSweep,
129
+ thenCommands,
130
+ andThenEvents,
131
+ thenScenarioTodos,
132
+ }
133
+ /* include Not a pure module */
@@ -0,0 +1,30 @@
1
+ // `OutboundTranslation_GWT.Make` expects a single SliceSpec with `collect` at
2
+ // the top level. Compose `collect` onto the spec module locally — the real
3
+ // `translate` is mocked at test time via `whenTranslateMocked`.
4
+
5
+ module SendOrderConfirmationSlice = {
6
+ include SendOrderConfirmation
7
+ let collect = SendOrderConfirmation_Translation.collect
8
+ }
9
+
10
+ @@reventless.gwt
11
+
12
+ describe("SendOrderConfirmation OutboundTranslationSlice", () => {
13
+ testSync("collect: OrderPlaced queues an outbound TODO", () =>
14
+ givenEvent(OrderPlaced({orderId: "o1", customerId: "c1"}))
15
+ ->whenCollect
16
+ ->thenTodos([("o1", {orderId: "o1", customerId: "c1"})])
17
+ )
18
+
19
+ test("translate success marks the TODO Completed", () =>
20
+ givenTodo("o1", {orderId: "o1", customerId: "c1"})
21
+ ->whenTranslateMocked((_id, _item) => Promise.resolve(Ok(None)))
22
+ ->thenTodoStatus("o1", #Completed)
23
+ )
24
+
25
+ test("translate failure leaves the TODO Pending for retry", () =>
26
+ givenTodo("o1", {orderId: "o1", customerId: "c1"})
27
+ ->whenTranslateMocked((_id, _item) => Promise.resolve(Error("smtp down")))
28
+ ->thenTodoStatus("o1", #Pending)
29
+ )
30
+ })