@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,64 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+
5
+ let commandSchema = S.union([
6
+ S.schema(s => ({
7
+ TAG: "Register",
8
+ email: s.m(S.string),
9
+ address: s.m(S.string)
10
+ })),
11
+ S.schema(s => ({
12
+ TAG: "UpdateEmail",
13
+ email: s.m(S.string)
14
+ })),
15
+ S.schema(s => ({
16
+ TAG: "UpdateAddress",
17
+ address: s.m(S.string)
18
+ })),
19
+ S.literal("Deactivate")
20
+ ]);
21
+
22
+ let eventSchema = S.union([
23
+ S.schema(s => ({
24
+ TAG: "Registered",
25
+ email: s.m(S.string),
26
+ address: s.m(S.string)
27
+ })),
28
+ S.schema(s => ({
29
+ TAG: "EmailUpdated",
30
+ email: s.m(S.string)
31
+ })),
32
+ S.schema(s => ({
33
+ TAG: "AddressUpdated",
34
+ address: s.m(S.string)
35
+ })),
36
+ S.literal("Deactivated")
37
+ ]);
38
+
39
+ let errorSchema = S.union([
40
+ S.literal("CustomerAlreadyRegistered"),
41
+ S.literal("CustomerNotFound"),
42
+ S.literal("CustomerAlreadyDeactivated")
43
+ ]);
44
+
45
+ function commandAuthorization(param) {
46
+ return "AllowAuthenticated";
47
+ }
48
+
49
+ let name = "Customer";
50
+
51
+ let Id;
52
+
53
+ let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Customer/Aggregate/Customer.res.mjs";
54
+
55
+ export {
56
+ name,
57
+ Id,
58
+ commandSchema,
59
+ eventSchema,
60
+ errorSchema,
61
+ moduleUrl,
62
+ commandAuthorization,
63
+ }
64
+ /* commandSchema Not a pure module */
@@ -0,0 +1,41 @@
1
+ // Customer aggregate behavior.
2
+ // Implements the state machine for registering and managing customers.
3
+
4
+ @@reventless.behavior
5
+
6
+ @schema
7
+ type state =
8
+ | NotCreated
9
+ | Active({email: string, address: string})
10
+ | Deactivated
11
+
12
+ let initialState = NotCreated
13
+
14
+ let evolve = (state, event) =>
15
+ switch (state, event) {
16
+ | (NotCreated, Registered({email, address})) => Active({email, address})
17
+ | (Active(_), Registered({email, address})) => Active({email, address})
18
+ | (Active(s), EmailUpdated({email})) => Active({...s, email})
19
+ | (Active(s), AddressUpdated({address})) => Active({...s, address})
20
+ | (Active(_), Customer.Deactivated) => Deactivated
21
+ | (Deactivated, _) => state
22
+ | (NotCreated, _) => state
23
+ }
24
+
25
+ let decide = (state, command) =>
26
+ switch (state, command) {
27
+ | (NotCreated, Register({email, address})) => Ok([Registered({email, address})])
28
+ | (NotCreated, UpdateEmail(_)) => Error(CustomerNotFound)
29
+ | (NotCreated, UpdateAddress(_)) => Error(CustomerNotFound)
30
+ | (NotCreated, Deactivate) => Error(CustomerNotFound)
31
+ | (Active(_), Register(_)) => Error(CustomerAlreadyRegistered)
32
+ | (Active(s), UpdateEmail({email})) if email == s.email => Ok([])
33
+ | (Active(_), UpdateEmail({email})) => Ok([EmailUpdated({email: email})])
34
+ | (Active(s), UpdateAddress({address})) if address == s.address => Ok([])
35
+ | (Active(_), UpdateAddress({address})) => Ok([AddressUpdated({address: address})])
36
+ | (Active(_), Deactivate) => Ok([Customer.Deactivated])
37
+ | (Deactivated, Register(_)) => Error(CustomerAlreadyDeactivated)
38
+ | (Deactivated, UpdateEmail(_)) => Error(CustomerAlreadyDeactivated)
39
+ | (Deactivated, UpdateAddress(_)) => Error(CustomerAlreadyDeactivated)
40
+ | (Deactivated, Deactivate) => Ok([]) // idempotent
41
+ }
@@ -0,0 +1,143 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+
5
+ let stateSchema = S.union([
6
+ S.literal("NotCreated"),
7
+ S.schema(s => ({
8
+ TAG: "Active",
9
+ email: s.m(S.string),
10
+ address: s.m(S.string)
11
+ })),
12
+ S.literal("Deactivated")
13
+ ]);
14
+
15
+ function evolve(state, event) {
16
+ if (typeof state !== "object") {
17
+ if (state === "NotCreated" && typeof event === "object" && event.TAG === "Registered") {
18
+ return {
19
+ TAG: "Active",
20
+ email: event.email,
21
+ address: event.address
22
+ };
23
+ } else {
24
+ return state;
25
+ }
26
+ }
27
+ if (typeof event !== "object") {
28
+ return "Deactivated";
29
+ }
30
+ switch (event.TAG) {
31
+ case "Registered" :
32
+ return {
33
+ TAG: "Active",
34
+ email: event.email,
35
+ address: event.address
36
+ };
37
+ case "EmailUpdated" :
38
+ return {
39
+ TAG: "Active",
40
+ email: event.email,
41
+ address: state.address
42
+ };
43
+ case "AddressUpdated" :
44
+ return {
45
+ TAG: "Active",
46
+ email: state.email,
47
+ address: event.address
48
+ };
49
+ }
50
+ }
51
+
52
+ function decide(state, command) {
53
+ if (typeof state !== "object") {
54
+ if (state === "NotCreated") {
55
+ if (typeof command !== "object" || command.TAG !== "Register") {
56
+ return {
57
+ TAG: "Error",
58
+ _0: "CustomerNotFound"
59
+ };
60
+ } else {
61
+ return {
62
+ TAG: "Ok",
63
+ _0: [{
64
+ TAG: "Registered",
65
+ email: command.email,
66
+ address: command.address
67
+ }]
68
+ };
69
+ }
70
+ } else if (typeof command !== "object") {
71
+ return {
72
+ TAG: "Ok",
73
+ _0: []
74
+ };
75
+ } else {
76
+ return {
77
+ TAG: "Error",
78
+ _0: "CustomerAlreadyDeactivated"
79
+ };
80
+ }
81
+ }
82
+ if (typeof command !== "object") {
83
+ return {
84
+ TAG: "Ok",
85
+ _0: ["Deactivated"]
86
+ };
87
+ }
88
+ switch (command.TAG) {
89
+ case "Register" :
90
+ return {
91
+ TAG: "Error",
92
+ _0: "CustomerAlreadyRegistered"
93
+ };
94
+ case "UpdateEmail" :
95
+ let email = command.email;
96
+ if (email === state.email) {
97
+ return {
98
+ TAG: "Ok",
99
+ _0: []
100
+ };
101
+ } else {
102
+ return {
103
+ TAG: "Ok",
104
+ _0: [{
105
+ TAG: "EmailUpdated",
106
+ email: email
107
+ }]
108
+ };
109
+ }
110
+ case "UpdateAddress" :
111
+ let address = command.address;
112
+ if (address === state.address) {
113
+ return {
114
+ TAG: "Ok",
115
+ _0: []
116
+ };
117
+ } else {
118
+ return {
119
+ TAG: "Ok",
120
+ _0: [{
121
+ TAG: "AddressUpdated",
122
+ address: address
123
+ }]
124
+ };
125
+ }
126
+ }
127
+ }
128
+
129
+ let Spec;
130
+
131
+ let initialState = "NotCreated";
132
+
133
+ let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Customer/Aggregate/Customer_Behavior.res.mjs";
134
+
135
+ export {
136
+ Spec,
137
+ stateSchema,
138
+ initialState,
139
+ evolve,
140
+ decide,
141
+ moduleUrl,
142
+ }
143
+ /* stateSchema Not a pure module */
@@ -0,0 +1,15 @@
1
+ // Customers read model specification.
2
+ // Query-side state for registered customers. This is a **mixed-source** read
3
+ // model: the customer profile fields come from the Customer aggregate, while
4
+ // `orderCount` is fed by the Ordering DCB log's `OrderPlaced` events (keyed by
5
+ // `customerId`). See `Customers_Projections.res` for the two source mappings.
6
+
7
+ @@reventless.spec
8
+
9
+ @schema
10
+ type state = {
11
+ @displayName email: string,
12
+ address: string,
13
+ deactivated: bool,
14
+ orderCount: int,
15
+ }
@@ -0,0 +1,44 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+ import * as ReadModel$Reventless from "@reventlessdev/reventless-spec/src/components/ReadModel.res.mjs";
5
+ import * as DisplayName$Reventless from "@reventlessdev/reventless-spec/src/components/DisplayName.res.mjs";
6
+
7
+ let stateSchema = S.schema(s => ({
8
+ email: s.m(S.string),
9
+ address: s.m(S.string),
10
+ deactivated: s.m(S.bool),
11
+ orderCount: s.m(S.int),
12
+ displayName: s.m(S.option(S.string))
13
+ }));
14
+
15
+ let stateSchema$1 = S.Metadata.set(stateSchema, DisplayName$Reventless.displayNameId, {
16
+ fields: ["email"],
17
+ separator: " "
18
+ });
19
+
20
+ let config = ReadModel$Reventless.config(undefined, undefined, undefined);
21
+
22
+ let name = "Customers";
23
+
24
+ let Id;
25
+
26
+ let subIdConfig;
27
+
28
+ let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Customer/ReadModelStream/Customers.res.mjs";
29
+
30
+ let authorization = "AllowAuthenticated";
31
+
32
+ let visibility = "Public";
33
+
34
+ export {
35
+ name,
36
+ Id,
37
+ stateSchema$1 as stateSchema,
38
+ config,
39
+ subIdConfig,
40
+ moduleUrl,
41
+ authorization,
42
+ visibility,
43
+ }
44
+ /* stateSchema Not a pure module */
@@ -0,0 +1,78 @@
1
+ // Customer projection mappings — a single read model fed by TWO sources:
2
+ //
3
+ // 1. the **Customer aggregate** (profile: email, address, deactivated), and
4
+ // 2. the **Ordering DCB EventLog** (`orderCount`, from `OrderPlaced` events).
5
+ //
6
+ // This is the canonical mixed **aggregate + DCB** read model: an aggregate's
7
+ // per-instance state correlated with DCB events that reference it by a shared
8
+ // key (`customerId`). Both mappings write to the same row id, so the framework
9
+ // merges them into one `Customers` record.
10
+ //
11
+ // The DCB source's `name` MUST equal `<pluginName>DcbEventLog`
12
+ // ("OrderingDcbEventLog") — the key under which `Plugin_Builder` registers the
13
+ // ordering plugin's DCB EventTopic AND the `meta.service` DcbEventLog stamps on
14
+ // every published event.
15
+ //
16
+ // Both mappings use `UpdateWithDefault` so the merge is order-independent: an
17
+ // `OrderPlaced` that arrives before its customer's `Registered` still creates a
18
+ // row (and vice-versa), and neither source clobbers the other's fields.
19
+
20
+ @@reventless.mappings
21
+
22
+ // ─────────────────────────────────────────────────────────────
23
+ // DCB source view — Order-side events (only what this read model needs)
24
+ // ─────────────────────────────────────────────────────────────
25
+
26
+ module OrderEvents = {
27
+ let name = "OrderingDcbEventLog"
28
+
29
+ @schema
30
+ type event = OrderPlaced({orderId: string, customerId: string})
31
+ }
32
+
33
+ // ─────────────────────────────────────────────────────────────
34
+ // Source 1 — Customer aggregate (profile)
35
+ // ─────────────────────────────────────────────────────────────
36
+
37
+ module CustomerMapping = Mapping.Make(
38
+ Customer,
39
+ Customers,
40
+ {
41
+ open Customer
42
+ let project = ({event, id, _}) =>
43
+ switch event {
44
+ | Registered({email, address}) =>
45
+ UpdateWithDefault(
46
+ id,
47
+ {Customers.email: email, address, deactivated: false, orderCount: 0},
48
+ state => {...state, email, address, deactivated: false},
49
+ )
50
+ | EmailUpdated({email}) => Update(id, state => {...state, email})
51
+ | AddressUpdated({address}) => Update(id, state => {...state, address})
52
+ | Deactivated => Update(id, state => {...state, deactivated: true})
53
+ }
54
+ },
55
+ )
56
+
57
+ // ─────────────────────────────────────────────────────────────
58
+ // Source 2 — Ordering DCB EventLog (order count, keyed by customerId)
59
+ // ─────────────────────────────────────────────────────────────
60
+
61
+ module CustomerOrdersMapping = Mapping.Make(
62
+ OrderEvents,
63
+ Customers,
64
+ {
65
+ open OrderEvents
66
+ let project = ({event, _}) =>
67
+ switch event {
68
+ | OrderPlaced({customerId}) =>
69
+ UpdateWithDefault(
70
+ customerId,
71
+ {Customers.email: "", address: "", deactivated: false, orderCount: 1},
72
+ state => {...state, orderCount: state.orderCount + 1},
73
+ )
74
+ }
75
+ },
76
+ )
77
+
78
+ let mappings: array<module(Mapping)> = [module(CustomerMapping), module(CustomerOrdersMapping)]
@@ -0,0 +1,153 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+ import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
5
+ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
6
+ import * as Projection$Reventless from "@reventlessdev/reventless-spec/src/types/Projection.res.mjs";
7
+ import * as Customer$OrderingPlugin from "../Aggregate/Customer.res.mjs";
8
+ import * as Customers$OrderingPlugin from "./Customers.res.mjs";
9
+
10
+ let M = Projection$Reventless.Mappings.Make({
11
+ Id: Id$Reventless.$$String,
12
+ name: Customers$OrderingPlugin.name,
13
+ stateSchema: Customers$OrderingPlugin.stateSchema,
14
+ subIdConfig: undefined
15
+ });
16
+
17
+ let name = "OrderingDcbEventLog";
18
+
19
+ let eventSchema = S.schema(s => ({
20
+ TAG: "OrderPlaced",
21
+ orderId: s.m(DcbTag$Reventless.string),
22
+ customerId: s.m(DcbTag$Reventless.string)
23
+ }));
24
+
25
+ let OrderEvents = {
26
+ Id: undefined,
27
+ name: name,
28
+ eventSchema: eventSchema
29
+ };
30
+
31
+ function project(param) {
32
+ let event = param.event;
33
+ let id = param.id;
34
+ if (typeof event !== "object") {
35
+ return {
36
+ TAG: "Update",
37
+ _0: id,
38
+ _1: state => {
39
+ let newrecord = {...state};
40
+ newrecord.deactivated = true;
41
+ return newrecord;
42
+ }
43
+ };
44
+ }
45
+ switch (event.TAG) {
46
+ case "Registered" :
47
+ let address = event.address;
48
+ let email = event.email;
49
+ return {
50
+ TAG: "UpdateWithDefault",
51
+ _0: id,
52
+ _1: {
53
+ email: email,
54
+ address: address,
55
+ deactivated: false,
56
+ orderCount: 0
57
+ },
58
+ _2: state => {
59
+ let newrecord = {...state};
60
+ newrecord.deactivated = false;
61
+ newrecord.address = address;
62
+ newrecord.email = email;
63
+ return newrecord;
64
+ }
65
+ };
66
+ case "EmailUpdated" :
67
+ let email$1 = event.email;
68
+ return {
69
+ TAG: "Update",
70
+ _0: id,
71
+ _1: state => {
72
+ let newrecord = {...state};
73
+ newrecord.email = email$1;
74
+ return newrecord;
75
+ }
76
+ };
77
+ case "AddressUpdated" :
78
+ let address$1 = event.address;
79
+ return {
80
+ TAG: "Update",
81
+ _0: id,
82
+ _1: state => {
83
+ let newrecord = {...state};
84
+ newrecord.address = address$1;
85
+ return newrecord;
86
+ }
87
+ };
88
+ }
89
+ }
90
+
91
+ let CustomerMapping = Projection$Reventless.Mapping.Make({
92
+ Id: Id$Reventless.$$String,
93
+ name: Customer$OrderingPlugin.name,
94
+ eventSchema: Customer$OrderingPlugin.eventSchema
95
+ })({
96
+ Id: Id$Reventless.$$String,
97
+ name: Customers$OrderingPlugin.name,
98
+ stateSchema: Customers$OrderingPlugin.stateSchema,
99
+ subIdConfig: undefined
100
+ })({
101
+ project: project
102
+ });
103
+
104
+ function project$1(param) {
105
+ return {
106
+ TAG: "UpdateWithDefault",
107
+ _0: param.event.customerId,
108
+ _1: {
109
+ email: "",
110
+ address: "",
111
+ deactivated: false,
112
+ orderCount: 1
113
+ },
114
+ _2: state => {
115
+ let newrecord = {...state};
116
+ newrecord.orderCount = state.orderCount + 1 | 0;
117
+ return newrecord;
118
+ }
119
+ };
120
+ }
121
+
122
+ let CustomerOrdersMapping = Projection$Reventless.Mapping.Make({
123
+ Id: Id$Reventless.$$String,
124
+ name: name,
125
+ eventSchema: eventSchema
126
+ })({
127
+ Id: Id$Reventless.$$String,
128
+ name: Customers$OrderingPlugin.name,
129
+ stateSchema: Customers$OrderingPlugin.stateSchema,
130
+ subIdConfig: undefined
131
+ })({
132
+ project: project$1
133
+ });
134
+
135
+ let mappings = [
136
+ CustomerMapping,
137
+ CustomerOrdersMapping
138
+ ];
139
+
140
+ let Target;
141
+
142
+ let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Customer/ReadModelStream/Customers_Projections.res.mjs";
143
+
144
+ export {
145
+ Target,
146
+ M,
147
+ OrderEvents,
148
+ CustomerMapping,
149
+ CustomerOrdersMapping,
150
+ mappings,
151
+ moduleUrl,
152
+ }
153
+ /* M Not a pure module */
@@ -0,0 +1,23 @@
1
+ // Ordering's extension subscribing to Catalog's Products_ExtensionPoint.
2
+ // Routes ProductBecameAvailable / ProductPriceChanged events to SyncCatalogProduct commands.
3
+
4
+ @@reventless.extension
5
+
6
+ module Mapping = {
7
+ module ExtensionPoint = CatalogSpec.Products_ExtensionPoint
8
+ module Delegate = SyncCatalogProduct
9
+
10
+ open ExtensionPoint
11
+ open SyncCatalogProduct
12
+ let mapIncomingEvent = (_id, event, _meta, _pluginDef, _queryEngine) =>
13
+ switch event {
14
+ | ProductBecameAvailable({productId, name, price}) => [
15
+ PublishStateChangeSliceCommand(SyncNewProduct({productId, name, price})),
16
+ ]
17
+ | ProductPriceChanged({productId, price}) => [
18
+ PublishStateChangeSliceCommand(ChangeSyncedPrice({productId, price})),
19
+ ]
20
+ }
21
+
22
+ let mapOutgoingEvent = None
23
+ }
@@ -0,0 +1,43 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as SyncCatalogProduct$OrderingPlugin from "../CatalogProduct/StateChangeSlice/SyncCatalogProduct.res.mjs";
4
+
5
+ function mapIncomingEvent(_id, event, _meta, _pluginDef, _queryEngine) {
6
+ if (event.TAG === "ProductBecameAvailable") {
7
+ return [{
8
+ TAG: "PublishStateChangeSliceCommand",
9
+ _0: {
10
+ TAG: "SyncNewProduct",
11
+ productId: event.productId,
12
+ name: event.name,
13
+ price: event.price
14
+ }
15
+ }];
16
+ } else {
17
+ return [{
18
+ TAG: "PublishStateChangeSliceCommand",
19
+ _0: {
20
+ TAG: "ChangeSyncedPrice",
21
+ productId: event.productId,
22
+ price: event.price
23
+ }
24
+ }];
25
+ }
26
+ }
27
+
28
+ let Mapping = {
29
+ ExtensionPoint: undefined,
30
+ Delegate: undefined,
31
+ mapIncomingEvent: mapIncomingEvent,
32
+ mapOutgoingEvent: undefined,
33
+ delegateModuleUrl: SyncCatalogProduct$OrderingPlugin.moduleUrl,
34
+ moduleUrl: "@reventlessdev/online-shop-hybrid-ordering/src/Extension/Products_Extension.res.mjs"
35
+ };
36
+
37
+ let moduleUrl = "@reventlessdev/online-shop-hybrid-ordering/src/Extension/Products_Extension.res.mjs";
38
+
39
+ export {
40
+ Mapping,
41
+ moduleUrl,
42
+ }
43
+ /* SyncCatalogProduct-OrderingPlugin Not a pure module */
@@ -0,0 +1,33 @@
1
+ // Maps internal Ordering events to the stable Orders_ExtensionPoint public API.
2
+ // Decomposes batch OrderPlaced / OrderCancelled events into per-product EP events.
3
+ @@reventless.spec
4
+
5
+ module ExtensionPoint = OrderingSpec.Orders_ExtensionPoint
6
+
7
+ // DCB adapter: defines the event type used for outgoing event mapping.
8
+ // Only the events relevant to the extension point are included.
9
+ module Delegate = {
10
+ let name = "OrderingDcbEventLog"
11
+ @schema
12
+ type event =
13
+ | OrderPlaced({orderId: string, customerId: string, productIds: array<string>})
14
+ | OrderCancelled({orderId: string, productIds: array<string>})
15
+ }
16
+
17
+ let mapIncomingCommand = (_id, _command, _meta) => []
18
+
19
+ let mapOutgoingEvent = Some((_id, event, _meta, _queryEngine) =>
20
+ switch event {
21
+ | Delegate.OrderPlaced({orderId, customerId, productIds}) =>
22
+ productIds->Array.map(pid =>
23
+ PublishEvent(
24
+ pid,
25
+ OrderingSpec.Orders_ExtensionPoint.ItemOrdered({productId: pid, orderId, customerId}),
26
+ )
27
+ )
28
+ | Delegate.OrderCancelled({orderId, productIds}) =>
29
+ productIds->Array.map(pid =>
30
+ PublishEvent(pid, OrderingSpec.Orders_ExtensionPoint.ItemOrderCancelled({productId: pid, orderId}))
31
+ )
32
+ }
33
+ )