@reventlessdev/online-shop-hybrid-catalog 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 (90) hide show
  1. package/CHANGELOG.md +878 -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/Category/StateChangeSlice/AddCategory.res +17 -0
  7. package/src/Category/StateChangeSlice/AddCategory.res.mjs +48 -0
  8. package/src/Category/StateChangeSlice/AddCategory_Behavior.res +21 -0
  9. package/src/Category/StateChangeSlice/AddCategory_Behavior.res.mjs +52 -0
  10. package/src/Category/StateChangeSlice/ArchiveCategory.res +18 -0
  11. package/src/Category/StateChangeSlice/ArchiveCategory.res.mjs +49 -0
  12. package/src/Category/StateChangeSlice/ArchiveCategory_Behavior.res +23 -0
  13. package/src/Category/StateChangeSlice/ArchiveCategory_Behavior.res.mjs +58 -0
  14. package/src/Category/StateChangeSlice/RenameCategory.res +23 -0
  15. package/src/Category/StateChangeSlice/RenameCategory.res.mjs +58 -0
  16. package/src/Category/StateChangeSlice/RenameCategory_Behavior.res +26 -0
  17. package/src/Category/StateChangeSlice/RenameCategory_Behavior.res.mjs +74 -0
  18. package/src/Category/StateViewSliceStream/Categories.res +13 -0
  19. package/src/Category/StateViewSliceStream/Categories.res.mjs +54 -0
  20. package/src/Category/StateViewSliceStream/Categories_Projection.res +8 -0
  21. package/src/Category/StateViewSliceStream/Categories_Projection.res.mjs +50 -0
  22. package/src/Extension/Orders_Extension.res +48 -0
  23. package/src/Extension/Orders_Extension.res.mjs +76 -0
  24. package/src/ExtensionPoint/Products_ExtensionPointMapping.res +59 -0
  25. package/src/ExtensionPoint/Products_ExtensionPointMapping.res.mjs +99 -0
  26. package/src/Plugin.res +63 -0
  27. package/src/Plugin.res.mjs +335 -0
  28. package/src/Product/InboundTranslationSlice/ImportProduct.res +28 -0
  29. package/src/Product/InboundTranslationSlice/ImportProduct.res.mjs +48 -0
  30. package/src/Product/InboundTranslationSlice/ImportProduct_Translation.res +23 -0
  31. package/src/Product/InboundTranslationSlice/ImportProduct_Translation.res.mjs +52 -0
  32. package/src/Product/StateChangeSlice/AddProduct.res +37 -0
  33. package/src/Product/StateChangeSlice/AddProduct.res.mjs +68 -0
  34. package/src/Product/StateChangeSlice/AddProduct_Behavior.res +35 -0
  35. package/src/Product/StateChangeSlice/AddProduct_Behavior.res.mjs +72 -0
  36. package/src/Product/StateChangeSlice/ChangeProductDescription.res +23 -0
  37. package/src/Product/StateChangeSlice/ChangeProductDescription.res.mjs +54 -0
  38. package/src/Product/StateChangeSlice/ChangeProductDescription_Behavior.res +26 -0
  39. package/src/Product/StateChangeSlice/ChangeProductDescription_Behavior.res.mjs +59 -0
  40. package/src/Product/StateChangeSlice/ChangeProductName.res +19 -0
  41. package/src/Product/StateChangeSlice/ChangeProductName.res.mjs +54 -0
  42. package/src/Product/StateChangeSlice/ChangeProductName_Behavior.res +23 -0
  43. package/src/Product/StateChangeSlice/ChangeProductName_Behavior.res.mjs +59 -0
  44. package/src/Product/StateChangeSlice/ChangeProductPrice.res +19 -0
  45. package/src/Product/StateChangeSlice/ChangeProductPrice.res.mjs +54 -0
  46. package/src/Product/StateChangeSlice/ChangeProductPrice_Behavior.res +23 -0
  47. package/src/Product/StateChangeSlice/ChangeProductPrice_Behavior.res.mjs +59 -0
  48. package/src/Product/StateViewSliceStream/ProductDemand.res +13 -0
  49. package/src/Product/StateViewSliceStream/ProductDemand.res.mjs +55 -0
  50. package/src/Product/StateViewSliceStream/ProductDemand_Projection.res +11 -0
  51. package/src/Product/StateViewSliceStream/ProductDemand_Projection.res.mjs +61 -0
  52. package/src/Product/StateViewSliceStream/Products.res +20 -0
  53. package/src/Product/StateViewSliceStream/Products.res.mjs +65 -0
  54. package/src/Product/StateViewSliceStream/Products_Projection.res +13 -0
  55. package/src/Product/StateViewSliceStream/Products_Projection.res.mjs +70 -0
  56. package/src/ProductDemand/StateChangeSlice/RecordProductDemand.res +24 -0
  57. package/src/ProductDemand/StateChangeSlice/RecordProductDemand.res.mjs +71 -0
  58. package/src/ProductDemand/StateChangeSlice/RecordProductDemand_Behavior.res +30 -0
  59. package/src/ProductDemand/StateChangeSlice/RecordProductDemand_Behavior.res.mjs +68 -0
  60. package/src/Task/ImportProducts.res +15 -0
  61. package/src/Task/ImportProducts.res.mjs +23 -0
  62. package/src/plugin.json +1 -0
  63. package/tests/Category/StateChangeSlice/AddCategory_GWT.res +21 -0
  64. package/tests/Category/StateChangeSlice/AddCategory_GWT.res.mjs +88 -0
  65. package/tests/Category/StateChangeSlice/ArchiveCategory_GWT.res +21 -0
  66. package/tests/Category/StateChangeSlice/ArchiveCategory_GWT.res.mjs +84 -0
  67. package/tests/Category/StateChangeSlice/RenameCategory_GWT.res +27 -0
  68. package/tests/Category/StateChangeSlice/RenameCategory_GWT.res.mjs +102 -0
  69. package/tests/Category/StateViewSliceStream/Categories_GWT.res +21 -0
  70. package/tests/Category/StateViewSliceStream/Categories_GWT.res.mjs +103 -0
  71. package/tests/Extension/Orders_Extension_GWT.res +40 -0
  72. package/tests/Extension/Orders_Extension_GWT.res.mjs +126 -0
  73. package/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT.res +37 -0
  74. package/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT.res.mjs +123 -0
  75. package/tests/Product/InboundTranslationSlice/ImportProduct_GWT.res +53 -0
  76. package/tests/Product/InboundTranslationSlice/ImportProduct_GWT.res.mjs +103 -0
  77. package/tests/Product/StateChangeSlice/AddProduct_GWT.res +64 -0
  78. package/tests/Product/StateChangeSlice/AddProduct_GWT.res.mjs +144 -0
  79. package/tests/Product/StateChangeSlice/ChangeProductDescription_GWT.res +21 -0
  80. package/tests/Product/StateChangeSlice/ChangeProductDescription_GWT.res.mjs +91 -0
  81. package/tests/Product/StateChangeSlice/ChangeProductName_GWT.res +21 -0
  82. package/tests/Product/StateChangeSlice/ChangeProductName_GWT.res.mjs +91 -0
  83. package/tests/Product/StateChangeSlice/ChangeProductPrice_GWT.res +21 -0
  84. package/tests/Product/StateChangeSlice/ChangeProductPrice_GWT.res.mjs +91 -0
  85. package/tests/Product/StateViewSliceStream/ProductDemand_GWT.res +31 -0
  86. package/tests/Product/StateViewSliceStream/ProductDemand_GWT.res.mjs +132 -0
  87. package/tests/Product/StateViewSliceStream/Products_GWT.res +47 -0
  88. package/tests/Product/StateViewSliceStream/Products_GWT.res.mjs +137 -0
  89. package/tests/ProductDemand/StateChangeSlice/RecordProductDemand_GWT.res +39 -0
  90. package/tests/ProductDemand/StateChangeSlice/RecordProductDemand_GWT.res.mjs +120 -0
@@ -0,0 +1,102 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Behavior_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Behavior_GWT.res.mjs";
4
+ import * as RenameCategory$CatalogPlugin from "../../../src/Category/StateChangeSlice/RenameCategory.res.mjs";
5
+ import * as RenameCategory_Behavior$CatalogPlugin from "../../../src/Category/StateChangeSlice/RenameCategory_Behavior.res.mjs";
6
+
7
+ let include = Behavior_GWT$ReventlessGwt.Make({
8
+ name: RenameCategory$CatalogPlugin.name,
9
+ consumedEventSchema: RenameCategory$CatalogPlugin.consumedEventSchema,
10
+ commandSchema: RenameCategory$CatalogPlugin.commandSchema,
11
+ errorSchema: RenameCategory$CatalogPlugin.errorSchema,
12
+ eventSchema: RenameCategory$CatalogPlugin.eventSchema
13
+ })({
14
+ initialState: RenameCategory_Behavior$CatalogPlugin.initialState,
15
+ evolve: RenameCategory_Behavior$CatalogPlugin.evolve,
16
+ decide: RenameCategory_Behavior$CatalogPlugin.decide
17
+ });
18
+
19
+ let describe = include.describe;
20
+
21
+ let test = include.test;
22
+
23
+ let givenEvents = include.givenEvents;
24
+
25
+ let whenCmd = include.whenCmd;
26
+
27
+ let thenEvent = include.thenEvent;
28
+
29
+ let thenNoEvent = include.thenNoEvent;
30
+
31
+ let thenError = include.thenError;
32
+
33
+ describe("RenameCategory StateChangeSlice", () => {
34
+ test("rename on non-existent category returns CategoryNotFound", () => thenError(whenCmd(givenEvents([]), {
35
+ TAG: "RenameCategory",
36
+ categoryId: "c1",
37
+ name: "Consumer Electronics"
38
+ }), "CategoryNotFound"));
39
+ test("rename on active category produces CategoryRenamed", () => thenEvent(whenCmd(givenEvents([{
40
+ TAG: "CategoryAdded",
41
+ name: "Electronics"
42
+ }]), {
43
+ TAG: "RenameCategory",
44
+ categoryId: "c1",
45
+ name: "Consumer Electronics"
46
+ }), {
47
+ TAG: "CategoryRenamed",
48
+ categoryId: "c1",
49
+ name: "Consumer Electronics"
50
+ }));
51
+ test("rename to same name produces no events (idempotent)", () => thenNoEvent(whenCmd(givenEvents([{
52
+ TAG: "CategoryAdded",
53
+ name: "Electronics"
54
+ }]), {
55
+ TAG: "RenameCategory",
56
+ categoryId: "c1",
57
+ name: "Electronics"
58
+ })));
59
+ test("rename on archived category returns CategoryAlreadyArchived", () => thenError(whenCmd(givenEvents([
60
+ {
61
+ TAG: "CategoryAdded",
62
+ name: "Electronics"
63
+ },
64
+ "CategoryArchived"
65
+ ]), {
66
+ TAG: "RenameCategory",
67
+ categoryId: "c1",
68
+ name: "X"
69
+ }), "CategoryAlreadyArchived"));
70
+ });
71
+
72
+ let Spec = include.Spec;
73
+
74
+ let todo = include.todo;
75
+
76
+ let thenEvents = include.thenEvents;
77
+
78
+ let thenEventWithError = include.thenEventWithError;
79
+
80
+ let thenEventsWithError = include.thenEventsWithError;
81
+
82
+ let thenAppendsConditionedOn = include.thenAppendsConditionedOn;
83
+
84
+ let thenAppendsConditionedOnExactly = include.thenAppendsConditionedOnExactly;
85
+
86
+ export {
87
+ Spec,
88
+ describe,
89
+ todo,
90
+ test,
91
+ givenEvents,
92
+ whenCmd,
93
+ thenEvent,
94
+ thenEvents,
95
+ thenNoEvent,
96
+ thenEventWithError,
97
+ thenEventsWithError,
98
+ thenError,
99
+ thenAppendsConditionedOn,
100
+ thenAppendsConditionedOnExactly,
101
+ }
102
+ /* include Not a pure module */
@@ -0,0 +1,21 @@
1
+ @@reventless.gwt
2
+
3
+ describe("Categories StateViewSliceStream", () => {
4
+ test("CategoryAdded creates a row", () =>
5
+ givenEvents([])
6
+ ->whenEvent(CategoryAdded({categoryId: "c1", name: "Electronics"}))
7
+ ->thenStateWithId("c1", {categoryId: "c1", name: "Electronics", archived: false})
8
+ )
9
+
10
+ test("CategoryRenamed updates the name", () =>
11
+ givenEvents([CategoryAdded({categoryId: "c1", name: "Electronics"})])
12
+ ->whenEvent(CategoryRenamed({categoryId: "c1", name: "Consumer Electronics"}))
13
+ ->thenStateWithId("c1", {categoryId: "c1", name: "Consumer Electronics", archived: false})
14
+ )
15
+
16
+ test("CategoryArchived sets archived flag", () =>
17
+ givenEvents([CategoryAdded({categoryId: "c1", name: "Electronics"})])
18
+ ->whenEvent(CategoryArchived({categoryId: "c1"}))
19
+ ->thenStateWithId("c1", {categoryId: "c1", name: "Electronics", archived: true})
20
+ )
21
+ })
@@ -0,0 +1,103 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Categories$CatalogPlugin from "../../../src/Category/StateViewSliceStream/Categories.res.mjs";
4
+ import * as Projection_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Projection_GWT.res.mjs";
5
+ import * as Categories_Projection$CatalogPlugin from "../../../src/Category/StateViewSliceStream/Categories_Projection.res.mjs";
6
+
7
+ let include = Projection_GWT$ReventlessGwt.Make({
8
+ name: Categories$CatalogPlugin.name,
9
+ stateSchema: Categories$CatalogPlugin.stateSchema,
10
+ consumedEventSchema: Categories$CatalogPlugin.consumedEventSchema,
11
+ subIdConfig: undefined
12
+ })({
13
+ project: Categories_Projection$CatalogPlugin.project
14
+ });
15
+
16
+ let describe = include.describe;
17
+
18
+ let test = include.test;
19
+
20
+ let givenEvents = include.givenEvents;
21
+
22
+ let whenEvent = include.whenEvent;
23
+
24
+ let thenStateWithId = include.thenStateWithId;
25
+
26
+ describe("Categories StateViewSliceStream", () => {
27
+ test("CategoryAdded creates a row", undefined, () => thenStateWithId(whenEvent(givenEvents([]), {
28
+ TAG: "CategoryAdded",
29
+ categoryId: "c1",
30
+ name: "Electronics"
31
+ }), "c1", {
32
+ categoryId: "c1",
33
+ name: "Electronics",
34
+ archived: false
35
+ }));
36
+ test("CategoryRenamed updates the name", undefined, () => thenStateWithId(whenEvent(givenEvents([{
37
+ TAG: "CategoryAdded",
38
+ categoryId: "c1",
39
+ name: "Electronics"
40
+ }]), {
41
+ TAG: "CategoryRenamed",
42
+ categoryId: "c1",
43
+ name: "Consumer Electronics"
44
+ }), "c1", {
45
+ categoryId: "c1",
46
+ name: "Consumer Electronics",
47
+ archived: false
48
+ }));
49
+ test("CategoryArchived sets archived flag", undefined, () => thenStateWithId(whenEvent(givenEvents([{
50
+ TAG: "CategoryAdded",
51
+ categoryId: "c1",
52
+ name: "Electronics"
53
+ }]), {
54
+ TAG: "CategoryArchived",
55
+ categoryId: "c1"
56
+ }), "c1", {
57
+ categoryId: "c1",
58
+ name: "Electronics",
59
+ archived: true
60
+ }));
61
+ });
62
+
63
+ let Spec = include.Spec;
64
+
65
+ let describeWithId = include.describeWithId;
66
+
67
+ let todo = include.todo;
68
+
69
+ let whenEvents = include.whenEvents;
70
+
71
+ let thenStates = include.thenStates;
72
+
73
+ let thenStatesWithId = include.thenStatesWithId;
74
+
75
+ let thenAllStates = include.thenAllStates;
76
+
77
+ let thenState = include.thenState;
78
+
79
+ let thenNoState = include.thenNoState;
80
+
81
+ let thenThrow = include.thenThrow;
82
+
83
+ let thenFail = include.thenFail;
84
+
85
+ export {
86
+ Spec,
87
+ describe,
88
+ describeWithId,
89
+ todo,
90
+ test,
91
+ givenEvents,
92
+ whenEvent,
93
+ whenEvents,
94
+ thenStates,
95
+ thenStatesWithId,
96
+ thenAllStates,
97
+ thenState,
98
+ thenStateWithId,
99
+ thenNoState,
100
+ thenThrow,
101
+ thenFail,
102
+ }
103
+ /* include Not a pure module */
@@ -0,0 +1,40 @@
1
+ // Boundary GWT for Catalog's Orders extension: public Ordering events become
2
+ // RecordProductDemand commands on Catalog's demand slice.
3
+ @@reventless.gwt
4
+
5
+ // `Mapping` is brought into scope by the PPX `open Orders_Extension`; opening
6
+ // it surfaces the extension point's events and the delegate's commands.
7
+ open Mapping
8
+
9
+ // Each `ItemOrdered` / `ItemOrderCancelled` produces TWO actions on disjoint
10
+ // channels: a `RecordDemand` / `RevokeDemand` command, and a telemetry
11
+ // directive. Per-channel tests project to one channel each.
12
+ describe("Orders Extension delegate", () => {
13
+ test("ItemOrdered records demand for the product", () =>
14
+ whenIncomingEvent(
15
+ ExtensionPoint.ItemOrdered({productId: "p1", orderId: "o1", customerId: "c1"}),
16
+ )->thenPublishesCommand(Delegate.RecordDemand({productId: "p1", orderId: "o1"}))
17
+ )
18
+
19
+ test("ItemOrdered fires an order-recorded telemetry directive", () =>
20
+ whenIncomingEvent(
21
+ ExtensionPoint.ItemOrdered({productId: "p1", orderId: "o1", customerId: "c1"}),
22
+ )->thenHandlesDirective(
23
+ ExtensionPoint.EmitOrderRecordedTelemetry({productId: "p1", orderId: "o1"}),
24
+ )
25
+ )
26
+
27
+ test("ItemOrderCancelled revokes demand for the product", () =>
28
+ whenIncomingEvent(
29
+ ExtensionPoint.ItemOrderCancelled({productId: "p1", orderId: "o1"}),
30
+ )->thenPublishesCommand(Delegate.RevokeDemand({productId: "p1", orderId: "o1"}))
31
+ )
32
+
33
+ test("ItemOrderCancelled fires an order-cancelled telemetry directive", () =>
34
+ whenIncomingEvent(
35
+ ExtensionPoint.ItemOrderCancelled({productId: "p1", orderId: "o1"}),
36
+ )->thenHandlesDirective(
37
+ ExtensionPoint.EmitOrderCancelledTelemetry({productId: "p1", orderId: "o1"}),
38
+ )
39
+ )
40
+ })
@@ -0,0 +1,126 @@
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_Extension$CatalogPlugin from "../../src/Extension/Orders_Extension.res.mjs";
6
+ import * as RecordProductDemand$CatalogPlugin from "../../src/ProductDemand/StateChangeSlice/RecordProductDemand.res.mjs";
7
+ import * as Orders_ExtensionPoint$OrderingSpec from "@reventlessdev/online-shop-hybrid-ordering-spec/src/Orders_ExtensionPoint.res.mjs";
8
+
9
+ let include = Delegate_GWT$ReventlessGwt.FromExtension({
10
+ ExtensionPoint: {
11
+ name: Orders_ExtensionPoint$OrderingSpec.name,
12
+ moduleUrl: Orders_ExtensionPoint$OrderingSpec.moduleUrl,
13
+ commandSchema: Orders_ExtensionPoint$OrderingSpec.commandSchema,
14
+ eventSchema: Orders_ExtensionPoint$OrderingSpec.eventSchema,
15
+ directiveSchema: Orders_ExtensionPoint$OrderingSpec.directiveSchema
16
+ },
17
+ Delegate: {
18
+ Id: Id$Reventless.$$String,
19
+ name: RecordProductDemand$CatalogPlugin.name,
20
+ eventSchema: RecordProductDemand$CatalogPlugin.eventSchema,
21
+ errorSchema: RecordProductDemand$CatalogPlugin.errorSchema,
22
+ commandSchema: RecordProductDemand$CatalogPlugin.commandSchema,
23
+ moduleUrl: RecordProductDemand$CatalogPlugin.moduleUrl,
24
+ commandAuthorization: RecordProductDemand$CatalogPlugin.commandAuthorization
25
+ },
26
+ moduleUrl: Orders_Extension$CatalogPlugin.Mapping.moduleUrl,
27
+ delegateModuleUrl: Orders_Extension$CatalogPlugin.Mapping.delegateModuleUrl,
28
+ mapIncomingEvent: Orders_Extension$CatalogPlugin.Mapping.mapIncomingEvent,
29
+ mapOutgoingEvent: Orders_Extension$CatalogPlugin.Mapping.mapOutgoingEvent
30
+ });
31
+
32
+ let describe = include.describe;
33
+
34
+ let test = include.test;
35
+
36
+ let whenIncomingEvent = include.whenIncomingEvent;
37
+
38
+ let thenPublishesCommand = include.thenPublishesCommand;
39
+
40
+ let thenHandlesDirective = include.thenHandlesDirective;
41
+
42
+ describe("Orders Extension delegate", () => {
43
+ test("ItemOrdered records demand for the product", undefined, () => thenPublishesCommand(whenIncomingEvent({
44
+ TAG: "ItemOrdered",
45
+ productId: "p1",
46
+ orderId: "o1",
47
+ customerId: "c1"
48
+ }), {
49
+ TAG: "RecordDemand",
50
+ productId: "p1",
51
+ orderId: "o1"
52
+ }));
53
+ test("ItemOrdered fires an order-recorded telemetry directive", undefined, () => thenHandlesDirective(whenIncomingEvent({
54
+ TAG: "ItemOrdered",
55
+ productId: "p1",
56
+ orderId: "o1",
57
+ customerId: "c1"
58
+ }), {
59
+ TAG: "EmitOrderRecordedTelemetry",
60
+ productId: "p1",
61
+ orderId: "o1"
62
+ }));
63
+ test("ItemOrderCancelled revokes demand for the product", undefined, () => thenPublishesCommand(whenIncomingEvent({
64
+ TAG: "ItemOrderCancelled",
65
+ productId: "p1",
66
+ orderId: "o1"
67
+ }), {
68
+ TAG: "RevokeDemand",
69
+ productId: "p1",
70
+ orderId: "o1"
71
+ }));
72
+ test("ItemOrderCancelled fires an order-cancelled telemetry directive", undefined, () => thenHandlesDirective(whenIncomingEvent({
73
+ TAG: "ItemOrderCancelled",
74
+ productId: "p1",
75
+ orderId: "o1"
76
+ }), {
77
+ TAG: "EmitOrderCancelledTelemetry",
78
+ productId: "p1",
79
+ orderId: "o1"
80
+ }));
81
+ });
82
+
83
+ let encCmd = include.encCmd;
84
+
85
+ let encEpCmd = include.encEpCmd;
86
+
87
+ let encDirective = include.encDirective;
88
+
89
+ let EvCore = include.EvCore;
90
+
91
+ let OutCore = include.OutCore;
92
+
93
+ let thenPublishesNothing = include.thenPublishesNothing;
94
+
95
+ let thenPublishesCommands = include.thenPublishesCommands;
96
+
97
+ let thenPublishesAggregateCommand = include.thenPublishesAggregateCommand;
98
+
99
+ let whenDelegateEvent = include.whenDelegateEvent;
100
+
101
+ let thenPublishesExtensionPointCommand = include.thenPublishesExtensionPointCommand;
102
+
103
+ let thenHandlesDirectives = include.thenHandlesDirectives;
104
+
105
+ let thenHandlesNoDirective = include.thenHandlesNoDirective;
106
+
107
+ export {
108
+ encCmd,
109
+ encEpCmd,
110
+ encDirective,
111
+ EvCore,
112
+ OutCore,
113
+ describe,
114
+ test,
115
+ thenPublishesNothing,
116
+ whenIncomingEvent,
117
+ thenPublishesCommand,
118
+ thenPublishesCommands,
119
+ thenPublishesAggregateCommand,
120
+ whenDelegateEvent,
121
+ thenPublishesExtensionPointCommand,
122
+ thenHandlesDirective,
123
+ thenHandlesDirectives,
124
+ thenHandlesNoDirective,
125
+ }
126
+ /* include Not a pure module */
@@ -0,0 +1,37 @@
1
+ // Boundary GWT for the Products extension point: internal Catalog events
2
+ // become the stable public events Ordering subscribes to.
3
+ @@reventless.gwt
4
+
5
+ // Published events and handled directives are disjoint channels on the same
6
+ // mapping run — each `test` projects to one channel and asserts on it.
7
+ describe("Products ExtensionPoint mapping", () => {
8
+ test("ProductAdded publishes ProductBecameAvailable", () =>
9
+ whenDelegateEvent(
10
+ Delegate.ProductAdded({productId: "p1", name: "Book", description: "A good book", price: 9.99}),
11
+ )->thenPublishesEvent(
12
+ "p1",
13
+ ExtensionPoint.ProductBecameAvailable({productId: "p1", name: "Book", price: 9.99}),
14
+ )
15
+ )
16
+
17
+ test("ProductAdded raises no directive", () =>
18
+ whenDelegateEvent(
19
+ Delegate.ProductAdded({productId: "p1", name: "Book", description: "A good book", price: 9.99}),
20
+ )->thenHandlesNoDirective
21
+ )
22
+
23
+ test("ProductPriceChanged is forwarded to the extension point", () =>
24
+ whenDelegateEvent(Delegate.ProductPriceChanged({productId: "p1", price: 7.5}))->thenPublishesEvent(
25
+ "p1",
26
+ ExtensionPoint.ProductPriceChanged({productId: "p1", price: 7.5}),
27
+ )
28
+ )
29
+
30
+ test("ProductPriceChanged also fires a pricing-update directive", () =>
31
+ whenDelegateEvent(
32
+ Delegate.ProductPriceChanged({productId: "p1", price: 7.5}),
33
+ )->thenHandlesDirective(
34
+ ExtensionPoint.EmitPricingUpdate({productId: "p1", price: 7.5}),
35
+ )
36
+ )
37
+ })
@@ -0,0 +1,123 @@
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 Products_ExtensionPoint$CatalogSpec from "@reventlessdev/online-shop-hybrid-catalog-spec/src/Products_ExtensionPoint.res.mjs";
6
+ import * as Products_ExtensionPointMapping$CatalogPlugin from "../../src/ExtensionPoint/Products_ExtensionPointMapping.res.mjs";
7
+
8
+ let include = Delegate_GWT$ReventlessGwt.FromExtensionPoint({
9
+ ExtensionPoint: {
10
+ name: Products_ExtensionPoint$CatalogSpec.name,
11
+ moduleUrl: Products_ExtensionPoint$CatalogSpec.moduleUrl,
12
+ commandSchema: Products_ExtensionPoint$CatalogSpec.commandSchema,
13
+ eventSchema: Products_ExtensionPoint$CatalogSpec.eventSchema,
14
+ directiveSchema: Products_ExtensionPoint$CatalogSpec.directiveSchema
15
+ },
16
+ Delegate: {
17
+ Id: Id$Reventless.$$String,
18
+ name: Products_ExtensionPointMapping$CatalogPlugin.Delegate.name,
19
+ eventSchema: Products_ExtensionPointMapping$CatalogPlugin.Delegate.eventSchema,
20
+ errorSchema: Products_ExtensionPointMapping$CatalogPlugin.Delegate.errorSchema,
21
+ commandSchema: Products_ExtensionPointMapping$CatalogPlugin.Delegate.commandSchema,
22
+ moduleUrl: Products_ExtensionPointMapping$CatalogPlugin.Delegate.moduleUrl,
23
+ commandAuthorization: Products_ExtensionPointMapping$CatalogPlugin.Delegate.commandAuthorization
24
+ },
25
+ moduleUrl: Products_ExtensionPointMapping$CatalogPlugin.moduleUrl,
26
+ mapIncomingCommand: Products_ExtensionPointMapping$CatalogPlugin.mapIncomingCommand,
27
+ mapOutgoingEvent: Products_ExtensionPointMapping$CatalogPlugin.mapOutgoingEvent
28
+ });
29
+
30
+ let describe = include.describe;
31
+
32
+ let test = include.test;
33
+
34
+ let whenDelegateEvent = include.whenDelegateEvent;
35
+
36
+ let thenPublishesEvent = include.thenPublishesEvent;
37
+
38
+ let thenHandlesDirective = include.thenHandlesDirective;
39
+
40
+ let thenHandlesNoDirective = include.thenHandlesNoDirective;
41
+
42
+ describe("Products ExtensionPoint mapping", () => {
43
+ test("ProductAdded publishes ProductBecameAvailable", undefined, () => thenPublishesEvent(whenDelegateEvent({
44
+ TAG: "ProductAdded",
45
+ productId: "p1",
46
+ name: "Book",
47
+ description: "A good book",
48
+ price: 9.99
49
+ }), "p1", {
50
+ TAG: "ProductBecameAvailable",
51
+ productId: "p1",
52
+ name: "Book",
53
+ price: 9.99
54
+ }));
55
+ test("ProductAdded raises no directive", undefined, () => thenHandlesNoDirective(whenDelegateEvent({
56
+ TAG: "ProductAdded",
57
+ productId: "p1",
58
+ name: "Book",
59
+ description: "A good book",
60
+ price: 9.99
61
+ })));
62
+ test("ProductPriceChanged is forwarded to the extension point", undefined, () => thenPublishesEvent(whenDelegateEvent({
63
+ TAG: "ProductPriceChanged",
64
+ productId: "p1",
65
+ price: 7.5
66
+ }), "p1", {
67
+ TAG: "ProductPriceChanged",
68
+ productId: "p1",
69
+ price: 7.5
70
+ }));
71
+ test("ProductPriceChanged also fires a pricing-update directive", undefined, () => thenHandlesDirective(whenDelegateEvent({
72
+ TAG: "ProductPriceChanged",
73
+ productId: "p1",
74
+ price: 7.5
75
+ }), {
76
+ TAG: "EmitPricingUpdate",
77
+ productId: "p1",
78
+ price: 7.5
79
+ }));
80
+ });
81
+
82
+ let encEvent = include.encEvent;
83
+
84
+ let encCommand = include.encCommand;
85
+
86
+ let encDirective = include.encDirective;
87
+
88
+ let EvCore = include.EvCore;
89
+
90
+ let CmdCore = include.CmdCore;
91
+
92
+ let thenPublishesNothing = include.thenPublishesNothing;
93
+
94
+ let thenPublishesEvents = include.thenPublishesEvents;
95
+
96
+ let whenIncomingCommand = include.whenIncomingCommand;
97
+
98
+ let thenPublishesCommand = include.thenPublishesCommand;
99
+
100
+ let thenPublishesCommands = include.thenPublishesCommands;
101
+
102
+ let thenHandlesDirectives = include.thenHandlesDirectives;
103
+
104
+ export {
105
+ encEvent,
106
+ encCommand,
107
+ encDirective,
108
+ EvCore,
109
+ CmdCore,
110
+ describe,
111
+ test,
112
+ thenPublishesNothing,
113
+ whenDelegateEvent,
114
+ thenPublishesEvent,
115
+ thenPublishesEvents,
116
+ whenIncomingCommand,
117
+ thenPublishesCommand,
118
+ thenPublishesCommands,
119
+ thenHandlesDirective,
120
+ thenHandlesDirectives,
121
+ thenHandlesNoDirective,
122
+ }
123
+ /* include Not a pure module */
@@ -0,0 +1,53 @@
1
+ // `InboundTranslation_GWT.Make` expects a single SliceSpec carrying both the
2
+ // types (from the spec file) and the `translate` function (from the body
3
+ // file). Compose them locally before handing the result to the DSL.
4
+
5
+ module ImportProductSlice = {
6
+ include ImportProduct
7
+ let translate = ImportProduct_Translation.translate
8
+ }
9
+
10
+ @@reventless.gwt
11
+
12
+ describe("ImportProduct InboundTranslationSlice", () => {
13
+ test("USD payload translates to AddProduct command", () =>
14
+ whenInput({
15
+ sku: "p-1",
16
+ title: "Laptop",
17
+ desc: "high-end",
18
+ unitPrice: 99999,
19
+ currency: "USD",
20
+ category: "cat1",
21
+ })
22
+ ->thenCommand(
23
+ "p-1",
24
+ AddProduct({
25
+ productId: "p-1",
26
+ name: "Laptop",
27
+ description: "high-end",
28
+ price: 999.99,
29
+ categoryId: "cat1",
30
+ }),
31
+ )
32
+ )
33
+
34
+ test("non-USD currency surfaces a translate error", () =>
35
+ whenInput({sku: "p-1", title: "Laptop", desc: "x", unitPrice: 1, currency: "EUR", category: "cat1"})
36
+ ->thenTranslateError("Unsupported currency: EUR")
37
+ )
38
+
39
+ test("non-positive price surfaces a translate error", () =>
40
+ whenInput({sku: "p-1", title: "Laptop", desc: "x", unitPrice: 0, currency: "USD", category: "cat1"})
41
+ ->thenTranslateError("Price must be positive")
42
+ )
43
+
44
+ test("empty SKU surfaces a translate error", () =>
45
+ whenInput({sku: "", title: "Laptop", desc: "x", unitPrice: 100, currency: "USD", category: "cat1"})
46
+ ->thenTranslateError("SKU is required")
47
+ )
48
+
49
+ test("empty category surfaces a translate error", () =>
50
+ whenInput({sku: "p-1", title: "Laptop", desc: "x", unitPrice: 100, currency: "USD", category: ""})
51
+ ->thenTranslateError("Category is required")
52
+ )
53
+ })