@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.
- package/CHANGELOG.md +878 -0
- package/LICENSE +202 -0
- package/__mocks__/emptyModule.js +1 -0
- package/package.json +57 -0
- package/rescript.json +37 -0
- package/src/Category/StateChangeSlice/AddCategory.res +17 -0
- package/src/Category/StateChangeSlice/AddCategory.res.mjs +48 -0
- package/src/Category/StateChangeSlice/AddCategory_Behavior.res +21 -0
- package/src/Category/StateChangeSlice/AddCategory_Behavior.res.mjs +52 -0
- package/src/Category/StateChangeSlice/ArchiveCategory.res +18 -0
- package/src/Category/StateChangeSlice/ArchiveCategory.res.mjs +49 -0
- package/src/Category/StateChangeSlice/ArchiveCategory_Behavior.res +23 -0
- package/src/Category/StateChangeSlice/ArchiveCategory_Behavior.res.mjs +58 -0
- package/src/Category/StateChangeSlice/RenameCategory.res +23 -0
- package/src/Category/StateChangeSlice/RenameCategory.res.mjs +58 -0
- package/src/Category/StateChangeSlice/RenameCategory_Behavior.res +26 -0
- package/src/Category/StateChangeSlice/RenameCategory_Behavior.res.mjs +74 -0
- package/src/Category/StateViewSliceStream/Categories.res +13 -0
- package/src/Category/StateViewSliceStream/Categories.res.mjs +54 -0
- package/src/Category/StateViewSliceStream/Categories_Projection.res +8 -0
- package/src/Category/StateViewSliceStream/Categories_Projection.res.mjs +50 -0
- package/src/Extension/Orders_Extension.res +48 -0
- package/src/Extension/Orders_Extension.res.mjs +76 -0
- package/src/ExtensionPoint/Products_ExtensionPointMapping.res +59 -0
- package/src/ExtensionPoint/Products_ExtensionPointMapping.res.mjs +99 -0
- package/src/Plugin.res +63 -0
- package/src/Plugin.res.mjs +335 -0
- package/src/Product/InboundTranslationSlice/ImportProduct.res +28 -0
- package/src/Product/InboundTranslationSlice/ImportProduct.res.mjs +48 -0
- package/src/Product/InboundTranslationSlice/ImportProduct_Translation.res +23 -0
- package/src/Product/InboundTranslationSlice/ImportProduct_Translation.res.mjs +52 -0
- package/src/Product/StateChangeSlice/AddProduct.res +37 -0
- package/src/Product/StateChangeSlice/AddProduct.res.mjs +68 -0
- package/src/Product/StateChangeSlice/AddProduct_Behavior.res +35 -0
- package/src/Product/StateChangeSlice/AddProduct_Behavior.res.mjs +72 -0
- package/src/Product/StateChangeSlice/ChangeProductDescription.res +23 -0
- package/src/Product/StateChangeSlice/ChangeProductDescription.res.mjs +54 -0
- package/src/Product/StateChangeSlice/ChangeProductDescription_Behavior.res +26 -0
- package/src/Product/StateChangeSlice/ChangeProductDescription_Behavior.res.mjs +59 -0
- package/src/Product/StateChangeSlice/ChangeProductName.res +19 -0
- package/src/Product/StateChangeSlice/ChangeProductName.res.mjs +54 -0
- package/src/Product/StateChangeSlice/ChangeProductName_Behavior.res +23 -0
- package/src/Product/StateChangeSlice/ChangeProductName_Behavior.res.mjs +59 -0
- package/src/Product/StateChangeSlice/ChangeProductPrice.res +19 -0
- package/src/Product/StateChangeSlice/ChangeProductPrice.res.mjs +54 -0
- package/src/Product/StateChangeSlice/ChangeProductPrice_Behavior.res +23 -0
- package/src/Product/StateChangeSlice/ChangeProductPrice_Behavior.res.mjs +59 -0
- package/src/Product/StateViewSliceStream/ProductDemand.res +13 -0
- package/src/Product/StateViewSliceStream/ProductDemand.res.mjs +55 -0
- package/src/Product/StateViewSliceStream/ProductDemand_Projection.res +11 -0
- package/src/Product/StateViewSliceStream/ProductDemand_Projection.res.mjs +61 -0
- package/src/Product/StateViewSliceStream/Products.res +20 -0
- package/src/Product/StateViewSliceStream/Products.res.mjs +65 -0
- package/src/Product/StateViewSliceStream/Products_Projection.res +13 -0
- package/src/Product/StateViewSliceStream/Products_Projection.res.mjs +70 -0
- package/src/ProductDemand/StateChangeSlice/RecordProductDemand.res +24 -0
- package/src/ProductDemand/StateChangeSlice/RecordProductDemand.res.mjs +71 -0
- package/src/ProductDemand/StateChangeSlice/RecordProductDemand_Behavior.res +30 -0
- package/src/ProductDemand/StateChangeSlice/RecordProductDemand_Behavior.res.mjs +68 -0
- package/src/Task/ImportProducts.res +15 -0
- package/src/Task/ImportProducts.res.mjs +23 -0
- package/src/plugin.json +1 -0
- package/tests/Category/StateChangeSlice/AddCategory_GWT.res +21 -0
- package/tests/Category/StateChangeSlice/AddCategory_GWT.res.mjs +88 -0
- package/tests/Category/StateChangeSlice/ArchiveCategory_GWT.res +21 -0
- package/tests/Category/StateChangeSlice/ArchiveCategory_GWT.res.mjs +84 -0
- package/tests/Category/StateChangeSlice/RenameCategory_GWT.res +27 -0
- package/tests/Category/StateChangeSlice/RenameCategory_GWT.res.mjs +102 -0
- package/tests/Category/StateViewSliceStream/Categories_GWT.res +21 -0
- package/tests/Category/StateViewSliceStream/Categories_GWT.res.mjs +103 -0
- package/tests/Extension/Orders_Extension_GWT.res +40 -0
- package/tests/Extension/Orders_Extension_GWT.res.mjs +126 -0
- package/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT.res +37 -0
- package/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT.res.mjs +123 -0
- package/tests/Product/InboundTranslationSlice/ImportProduct_GWT.res +53 -0
- package/tests/Product/InboundTranslationSlice/ImportProduct_GWT.res.mjs +103 -0
- package/tests/Product/StateChangeSlice/AddProduct_GWT.res +64 -0
- package/tests/Product/StateChangeSlice/AddProduct_GWT.res.mjs +144 -0
- package/tests/Product/StateChangeSlice/ChangeProductDescription_GWT.res +21 -0
- package/tests/Product/StateChangeSlice/ChangeProductDescription_GWT.res.mjs +91 -0
- package/tests/Product/StateChangeSlice/ChangeProductName_GWT.res +21 -0
- package/tests/Product/StateChangeSlice/ChangeProductName_GWT.res.mjs +91 -0
- package/tests/Product/StateChangeSlice/ChangeProductPrice_GWT.res +21 -0
- package/tests/Product/StateChangeSlice/ChangeProductPrice_GWT.res.mjs +91 -0
- package/tests/Product/StateViewSliceStream/ProductDemand_GWT.res +31 -0
- package/tests/Product/StateViewSliceStream/ProductDemand_GWT.res.mjs +132 -0
- package/tests/Product/StateViewSliceStream/Products_GWT.res +47 -0
- package/tests/Product/StateViewSliceStream/Products_GWT.res.mjs +137 -0
- package/tests/ProductDemand/StateChangeSlice/RecordProductDemand_GWT.res +39 -0
- package/tests/ProductDemand/StateChangeSlice/RecordProductDemand_GWT.res.mjs +120 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
@@reventless.behavior
|
|
2
|
+
|
|
3
|
+
type state = {exists: bool, archived: bool, name: string}
|
|
4
|
+
|
|
5
|
+
let initialState = {exists: false, archived: false, name: ""}
|
|
6
|
+
|
|
7
|
+
let evolve = (state, event: consumedEvent) =>
|
|
8
|
+
switch event {
|
|
9
|
+
| CategoryAdded({name}) => {exists: true, archived: false, name}
|
|
10
|
+
| CategoryRenamed({name}) => {...state, name}
|
|
11
|
+
| CategoryArchived => {...state, archived: true}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let decide = (state, command) =>
|
|
15
|
+
switch command {
|
|
16
|
+
| RenameCategory({categoryId, name}) =>
|
|
17
|
+
if !state.exists {
|
|
18
|
+
Error(CategoryNotFound)
|
|
19
|
+
} else if state.archived {
|
|
20
|
+
Error(CategoryAlreadyArchived)
|
|
21
|
+
} else if name == state.name {
|
|
22
|
+
Ok([])
|
|
23
|
+
} else {
|
|
24
|
+
Ok([CategoryRenamed({categoryId, name})])
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function evolve(state, event) {
|
|
5
|
+
if (typeof event !== "object") {
|
|
6
|
+
return {
|
|
7
|
+
exists: state.exists,
|
|
8
|
+
archived: true,
|
|
9
|
+
name: state.name
|
|
10
|
+
};
|
|
11
|
+
} else if (event.TAG === "CategoryAdded") {
|
|
12
|
+
return {
|
|
13
|
+
exists: true,
|
|
14
|
+
archived: false,
|
|
15
|
+
name: event.name
|
|
16
|
+
};
|
|
17
|
+
} else {
|
|
18
|
+
return {
|
|
19
|
+
exists: state.exists,
|
|
20
|
+
archived: state.archived,
|
|
21
|
+
name: event.name
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function decide(state, command) {
|
|
27
|
+
if (!state.exists) {
|
|
28
|
+
return {
|
|
29
|
+
TAG: "Error",
|
|
30
|
+
_0: "CategoryNotFound"
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (state.archived) {
|
|
34
|
+
return {
|
|
35
|
+
TAG: "Error",
|
|
36
|
+
_0: "CategoryAlreadyArchived"
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
let name = command.name;
|
|
40
|
+
if (name === state.name) {
|
|
41
|
+
return {
|
|
42
|
+
TAG: "Ok",
|
|
43
|
+
_0: []
|
|
44
|
+
};
|
|
45
|
+
} else {
|
|
46
|
+
return {
|
|
47
|
+
TAG: "Ok",
|
|
48
|
+
_0: [{
|
|
49
|
+
TAG: "CategoryRenamed",
|
|
50
|
+
categoryId: command.categoryId,
|
|
51
|
+
name: name
|
|
52
|
+
}]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let Spec;
|
|
58
|
+
|
|
59
|
+
let initialState = {
|
|
60
|
+
exists: false,
|
|
61
|
+
archived: false,
|
|
62
|
+
name: ""
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-catalog/src/Category/StateChangeSlice/RenameCategory_Behavior.res.mjs";
|
|
66
|
+
|
|
67
|
+
export {
|
|
68
|
+
Spec,
|
|
69
|
+
initialState,
|
|
70
|
+
evolve,
|
|
71
|
+
decide,
|
|
72
|
+
moduleUrl,
|
|
73
|
+
}
|
|
74
|
+
/* No side effect */
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Categories StateViewSliceStream.
|
|
2
|
+
// Projects category events from the shared catalog event log into a Categories read model.
|
|
3
|
+
|
|
4
|
+
@@reventless.spec
|
|
5
|
+
|
|
6
|
+
@schema
|
|
7
|
+
type consumedEvent =
|
|
8
|
+
| CategoryAdded({categoryId: string, name: string})
|
|
9
|
+
| CategoryRenamed({categoryId: string, name: string})
|
|
10
|
+
| CategoryArchived({categoryId: string})
|
|
11
|
+
|
|
12
|
+
@schema
|
|
13
|
+
type state = {categoryId: string, name: string, archived: bool}
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
|
|
6
|
+
let consumedEventSchema = S.union([
|
|
7
|
+
S.schema(s => ({
|
|
8
|
+
TAG: "CategoryAdded",
|
|
9
|
+
categoryId: s.m(S.string),
|
|
10
|
+
name: s.m(S.string)
|
|
11
|
+
})),
|
|
12
|
+
S.schema(s => ({
|
|
13
|
+
TAG: "CategoryRenamed",
|
|
14
|
+
categoryId: s.m(S.string),
|
|
15
|
+
name: s.m(S.string)
|
|
16
|
+
})),
|
|
17
|
+
S.schema(s => ({
|
|
18
|
+
TAG: "CategoryArchived",
|
|
19
|
+
categoryId: s.m(S.string)
|
|
20
|
+
}))
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
let stateSchema = S.schema(s => ({
|
|
24
|
+
categoryId: s.m(S.string),
|
|
25
|
+
name: s.m(S.string),
|
|
26
|
+
archived: s.m(S.bool)
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
let config = ReadModel$Reventless.config(undefined, undefined, undefined);
|
|
30
|
+
|
|
31
|
+
let name = "Categories";
|
|
32
|
+
|
|
33
|
+
let Id;
|
|
34
|
+
|
|
35
|
+
let subIdConfig;
|
|
36
|
+
|
|
37
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-catalog/src/Category/StateViewSliceStream/Categories.res.mjs";
|
|
38
|
+
|
|
39
|
+
let authorization = "AllowAuthenticated";
|
|
40
|
+
|
|
41
|
+
let visibility = "Public";
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
name,
|
|
45
|
+
Id,
|
|
46
|
+
consumedEventSchema,
|
|
47
|
+
stateSchema,
|
|
48
|
+
config,
|
|
49
|
+
subIdConfig,
|
|
50
|
+
moduleUrl,
|
|
51
|
+
authorization,
|
|
52
|
+
visibility,
|
|
53
|
+
}
|
|
54
|
+
/* consumedEventSchema Not a pure module */
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
@@reventless.projection
|
|
2
|
+
|
|
3
|
+
let project = event =>
|
|
4
|
+
switch event {
|
|
5
|
+
| CategoryAdded({categoryId, name}) => [Set(categoryId, {categoryId, name, archived: false})]
|
|
6
|
+
| CategoryRenamed({categoryId, name}) => [Update(categoryId, state => {...state, name})]
|
|
7
|
+
| CategoryArchived({categoryId}) => [Update(categoryId, state => {...state, archived: true})]
|
|
8
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function project(event) {
|
|
5
|
+
switch (event.TAG) {
|
|
6
|
+
case "CategoryAdded" :
|
|
7
|
+
let categoryId = event.categoryId;
|
|
8
|
+
return [{
|
|
9
|
+
TAG: "Set",
|
|
10
|
+
_0: categoryId,
|
|
11
|
+
_1: {
|
|
12
|
+
categoryId: categoryId,
|
|
13
|
+
name: event.name,
|
|
14
|
+
archived: false
|
|
15
|
+
}
|
|
16
|
+
}];
|
|
17
|
+
case "CategoryRenamed" :
|
|
18
|
+
let name = event.name;
|
|
19
|
+
return [{
|
|
20
|
+
TAG: "Update",
|
|
21
|
+
_0: event.categoryId,
|
|
22
|
+
_1: state => ({
|
|
23
|
+
categoryId: state.categoryId,
|
|
24
|
+
name: name,
|
|
25
|
+
archived: state.archived
|
|
26
|
+
})
|
|
27
|
+
}];
|
|
28
|
+
case "CategoryArchived" :
|
|
29
|
+
return [{
|
|
30
|
+
TAG: "Update",
|
|
31
|
+
_0: event.categoryId,
|
|
32
|
+
_1: state => ({
|
|
33
|
+
categoryId: state.categoryId,
|
|
34
|
+
name: state.name,
|
|
35
|
+
archived: true
|
|
36
|
+
})
|
|
37
|
+
}];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let Spec;
|
|
42
|
+
|
|
43
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-catalog/src/Category/StateViewSliceStream/Categories_Projection.res.mjs";
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
Spec,
|
|
47
|
+
project,
|
|
48
|
+
moduleUrl,
|
|
49
|
+
}
|
|
50
|
+
/* No side effect */
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Catalog's extension subscribing to Ordering's Orders_ExtensionPoint.
|
|
2
|
+
// Routes ItemOrdered / ItemOrderCancelled events to RecordProductDemand commands.
|
|
3
|
+
|
|
4
|
+
@@reventless.extension
|
|
5
|
+
|
|
6
|
+
module Mapping = {
|
|
7
|
+
module ExtensionPoint = OrderingSpec.Orders_ExtensionPoint
|
|
8
|
+
module Delegate = RecordProductDemand
|
|
9
|
+
|
|
10
|
+
open ExtensionPoint
|
|
11
|
+
open RecordProductDemand
|
|
12
|
+
|
|
13
|
+
// Extension-side directive handler: pure fire-and-forget
|
|
14
|
+
// (`'directive => promise<unit>`). Query-based decisions live in
|
|
15
|
+
// `mapIncomingEvent` (which has `_queryEngine`); the handler executes the
|
|
16
|
+
// resulting side effect.
|
|
17
|
+
let directiveHandler = async (directive: ExtensionPoint.directive) =>
|
|
18
|
+
switch directive {
|
|
19
|
+
| EmitOrderRecordedTelemetry({productId, orderId}) =>
|
|
20
|
+
Console.log(
|
|
21
|
+
`[Catalog.OrdersExtension] telemetry: order recorded product=${productId} order=${orderId}`,
|
|
22
|
+
)
|
|
23
|
+
| EmitOrderCancelledTelemetry({productId, orderId}) =>
|
|
24
|
+
Console.log(
|
|
25
|
+
`[Catalog.OrdersExtension] telemetry: order cancelled product=${productId} order=${orderId}`,
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let mapIncomingEvent = (_id, event, _meta, _pluginDef, _queryEngine) =>
|
|
30
|
+
switch event {
|
|
31
|
+
| ItemOrdered({productId, orderId}) => [
|
|
32
|
+
PublishStateChangeSliceCommand(RecordDemand({productId, orderId})),
|
|
33
|
+
HandleDirective(
|
|
34
|
+
directiveHandler,
|
|
35
|
+
EmitOrderRecordedTelemetry({productId, orderId}),
|
|
36
|
+
),
|
|
37
|
+
]
|
|
38
|
+
| ItemOrderCancelled({productId, orderId}) => [
|
|
39
|
+
PublishStateChangeSliceCommand(RevokeDemand({productId, orderId})),
|
|
40
|
+
HandleDirective(
|
|
41
|
+
directiveHandler,
|
|
42
|
+
EmitOrderCancelledTelemetry({productId, orderId}),
|
|
43
|
+
),
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let mapOutgoingEvent = None
|
|
48
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as RecordProductDemand$CatalogPlugin from "../ProductDemand/StateChangeSlice/RecordProductDemand.res.mjs";
|
|
4
|
+
|
|
5
|
+
async function directiveHandler(directive) {
|
|
6
|
+
if (directive.TAG === "EmitOrderRecordedTelemetry") {
|
|
7
|
+
console.log(`[Catalog.OrdersExtension] telemetry: order recorded product=` + directive.productId + ` order=` + directive.orderId);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
console.log(`[Catalog.OrdersExtension] telemetry: order cancelled product=` + directive.productId + ` order=` + directive.orderId);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function mapIncomingEvent(_id, event, _meta, _pluginDef, _queryEngine) {
|
|
14
|
+
if (event.TAG === "ItemOrdered") {
|
|
15
|
+
let orderId = event.orderId;
|
|
16
|
+
let productId = event.productId;
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
TAG: "PublishStateChangeSliceCommand",
|
|
20
|
+
_0: {
|
|
21
|
+
TAG: "RecordDemand",
|
|
22
|
+
productId: productId,
|
|
23
|
+
orderId: orderId
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
TAG: "HandleDirective",
|
|
28
|
+
_0: directiveHandler,
|
|
29
|
+
_1: {
|
|
30
|
+
TAG: "EmitOrderRecordedTelemetry",
|
|
31
|
+
productId: productId,
|
|
32
|
+
orderId: orderId
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
let orderId$1 = event.orderId;
|
|
38
|
+
let productId$1 = event.productId;
|
|
39
|
+
return [
|
|
40
|
+
{
|
|
41
|
+
TAG: "PublishStateChangeSliceCommand",
|
|
42
|
+
_0: {
|
|
43
|
+
TAG: "RevokeDemand",
|
|
44
|
+
productId: productId$1,
|
|
45
|
+
orderId: orderId$1
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
TAG: "HandleDirective",
|
|
50
|
+
_0: directiveHandler,
|
|
51
|
+
_1: {
|
|
52
|
+
TAG: "EmitOrderCancelledTelemetry",
|
|
53
|
+
productId: productId$1,
|
|
54
|
+
orderId: orderId$1
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let Mapping = {
|
|
61
|
+
ExtensionPoint: undefined,
|
|
62
|
+
Delegate: undefined,
|
|
63
|
+
directiveHandler: directiveHandler,
|
|
64
|
+
mapIncomingEvent: mapIncomingEvent,
|
|
65
|
+
mapOutgoingEvent: undefined,
|
|
66
|
+
delegateModuleUrl: RecordProductDemand$CatalogPlugin.moduleUrl,
|
|
67
|
+
moduleUrl: "@reventlessdev/online-shop-hybrid-catalog/src/Extension/Orders_Extension.res.mjs"
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-catalog/src/Extension/Orders_Extension.res.mjs";
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
Mapping,
|
|
74
|
+
moduleUrl,
|
|
75
|
+
}
|
|
76
|
+
/* RecordProductDemand-CatalogPlugin Not a pure module */
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Maps internal Catalog events to the stable Products_ExtensionPoint public API.
|
|
2
|
+
@@reventless.spec
|
|
3
|
+
|
|
4
|
+
module ExtensionPoint = CatalogSpec.Products_ExtensionPoint
|
|
5
|
+
|
|
6
|
+
// DCB adapter: defines the event type used for outgoing event mapping.
|
|
7
|
+
// Only the events relevant to the extension point are included.
|
|
8
|
+
// `name` MUST equal `<pluginName>DcbEventLog` so the dispatch in
|
|
9
|
+
// `Plugin_Callback` resolves it to the topic key `Plugin_Builder` registers
|
|
10
|
+
// under (`name ++ "DcbEventLog"`).
|
|
11
|
+
module Delegate = {
|
|
12
|
+
let name = "CatalogDcbEventLog"
|
|
13
|
+
@schema
|
|
14
|
+
type event =
|
|
15
|
+
| ProductAdded({productId: string, name: string, description: string, price: float})
|
|
16
|
+
| ProductPriceChanged({productId: string, price: float})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let mapIncomingCommand = (_id, _command, _meta) => []
|
|
20
|
+
|
|
21
|
+
// EP-side directive handler: receives Schedule.create / Schedule.delete /
|
|
22
|
+
// QueryEngine.operations as well as the directive itself. A real handler might
|
|
23
|
+
// post telemetry to an external sink, schedule a follow-up command, or query
|
|
24
|
+
// state. For this demo we only log; see
|
|
25
|
+
// `reventless-core/src/plugin/connect/PluginExtensionPoint_Plugin.res` for a canonical
|
|
26
|
+
// multi-capability EP-side handler.
|
|
27
|
+
let directiveHandler = async (
|
|
28
|
+
_createSchedule: Reventless.Schedule.create,
|
|
29
|
+
_deleteSchedule: Reventless.Schedule.delete,
|
|
30
|
+
_queryEngine: Reventless.QueryEngine.operations,
|
|
31
|
+
directive: CatalogSpec.Products_ExtensionPoint.directive,
|
|
32
|
+
) =>
|
|
33
|
+
switch directive {
|
|
34
|
+
| EmitPricingUpdate({productId, price}) =>
|
|
35
|
+
Console.log(
|
|
36
|
+
`[Catalog.ProductsExtensionPoint] telemetry: pricing update product=${productId} price=${price->Float.toString}`,
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let mapOutgoingEvent = Some((_id, event, _meta, _queryEngine) =>
|
|
41
|
+
switch event {
|
|
42
|
+
| Delegate.ProductAdded({productId, name, price}) => [
|
|
43
|
+
PublishEvent(
|
|
44
|
+
productId,
|
|
45
|
+
CatalogSpec.Products_ExtensionPoint.ProductBecameAvailable({productId, name, price}),
|
|
46
|
+
),
|
|
47
|
+
]
|
|
48
|
+
| Delegate.ProductPriceChanged({productId, price}) => [
|
|
49
|
+
PublishEvent(
|
|
50
|
+
productId,
|
|
51
|
+
CatalogSpec.Products_ExtensionPoint.ProductPriceChanged({productId, price}),
|
|
52
|
+
),
|
|
53
|
+
HandleDirective(
|
|
54
|
+
directiveHandler,
|
|
55
|
+
CatalogSpec.Products_ExtensionPoint.EmitPricingUpdate({productId, price}),
|
|
56
|
+
),
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
5
|
+
|
|
6
|
+
let eventSchema = S.union([
|
|
7
|
+
S.schema(s => ({
|
|
8
|
+
TAG: "ProductAdded",
|
|
9
|
+
productId: s.m(DcbTag$Reventless.string),
|
|
10
|
+
name: s.m(S.string),
|
|
11
|
+
description: s.m(S.string),
|
|
12
|
+
price: s.m(S.float)
|
|
13
|
+
})),
|
|
14
|
+
S.schema(s => ({
|
|
15
|
+
TAG: "ProductPriceChanged",
|
|
16
|
+
productId: s.m(DcbTag$Reventless.string),
|
|
17
|
+
price: s.m(S.float)
|
|
18
|
+
}))
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
function commandAuthorization(param) {
|
|
22
|
+
return "AllowAuthenticated";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let Delegate = {
|
|
26
|
+
Id: undefined,
|
|
27
|
+
commandSchema: S.unit,
|
|
28
|
+
name: "CatalogDcbEventLog",
|
|
29
|
+
eventSchema: eventSchema,
|
|
30
|
+
errorSchema: S.unit,
|
|
31
|
+
moduleUrl: "@reventlessdev/online-shop-hybrid-catalog/src/ExtensionPoint/Products_ExtensionPointMapping.res.mjs",
|
|
32
|
+
commandAuthorization: commandAuthorization
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function mapIncomingCommand(_id, _command, _meta) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function directiveHandler(_createSchedule, _deleteSchedule, _queryEngine, directive) {
|
|
40
|
+
console.log(`[Catalog.ProductsExtensionPoint] telemetry: pricing update product=` + directive.productId + ` price=` + directive.price.toString());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let mapOutgoingEvent = (_id, event, _meta, _queryEngine) => {
|
|
44
|
+
if (event.TAG === "ProductAdded") {
|
|
45
|
+
let productId = event.productId;
|
|
46
|
+
return [{
|
|
47
|
+
TAG: "PublishEvent",
|
|
48
|
+
_0: productId,
|
|
49
|
+
_1: {
|
|
50
|
+
TAG: "ProductBecameAvailable",
|
|
51
|
+
productId: productId,
|
|
52
|
+
name: event.name,
|
|
53
|
+
price: event.price
|
|
54
|
+
}
|
|
55
|
+
}];
|
|
56
|
+
}
|
|
57
|
+
let price = event.price;
|
|
58
|
+
let productId$1 = event.productId;
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
TAG: "PublishEvent",
|
|
62
|
+
_0: productId$1,
|
|
63
|
+
_1: {
|
|
64
|
+
TAG: "ProductPriceChanged",
|
|
65
|
+
productId: productId$1,
|
|
66
|
+
price: price
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
TAG: "HandleDirective",
|
|
71
|
+
_0: directiveHandler,
|
|
72
|
+
_1: {
|
|
73
|
+
TAG: "EmitPricingUpdate",
|
|
74
|
+
productId: productId$1,
|
|
75
|
+
price: price
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
];
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
let name = "Products";
|
|
82
|
+
|
|
83
|
+
let Id;
|
|
84
|
+
|
|
85
|
+
let ExtensionPoint;
|
|
86
|
+
|
|
87
|
+
let moduleUrl = "@reventlessdev/online-shop-hybrid-catalog/src/ExtensionPoint/Products_ExtensionPointMapping.res.mjs";
|
|
88
|
+
|
|
89
|
+
export {
|
|
90
|
+
name,
|
|
91
|
+
Id,
|
|
92
|
+
ExtensionPoint,
|
|
93
|
+
Delegate,
|
|
94
|
+
mapIncomingCommand,
|
|
95
|
+
directiveHandler,
|
|
96
|
+
mapOutgoingEvent,
|
|
97
|
+
moduleUrl,
|
|
98
|
+
}
|
|
99
|
+
/* eventSchema Not a pure module */
|
package/src/Plugin.res
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// AUTO-GENERATED — do not edit. Run `npm run generate` to update.
|
|
2
|
+
|
|
3
|
+
@val external uiBundleUrl: option<string> = "process.env.CATALOG_UI_BUNDLE_URL"
|
|
4
|
+
|
|
5
|
+
module Make = (Platform: ReventlessInfra.Platform.T) => {
|
|
6
|
+
// StateChangeSlices
|
|
7
|
+
module AddCategorySlice = Platform.StateChangeSlice.Make(AddCategory, AddCategory_Behavior)
|
|
8
|
+
module AddProductSlice = Platform.StateChangeSlice.Make(AddProduct, AddProduct_Behavior)
|
|
9
|
+
module ArchiveCategorySlice = Platform.StateChangeSlice.Make(ArchiveCategory, ArchiveCategory_Behavior)
|
|
10
|
+
module ChangeProductDescriptionSlice = Platform.StateChangeSlice.Make(ChangeProductDescription, ChangeProductDescription_Behavior)
|
|
11
|
+
module ChangeProductNameSlice = Platform.StateChangeSlice.Make(ChangeProductName, ChangeProductName_Behavior)
|
|
12
|
+
module ChangeProductPriceSlice = Platform.StateChangeSlice.Make(ChangeProductPrice, ChangeProductPrice_Behavior)
|
|
13
|
+
module RecordProductDemandSlice = Platform.StateChangeSlice.Make(RecordProductDemand, RecordProductDemand_Behavior)
|
|
14
|
+
module RenameCategorySlice = Platform.StateChangeSlice.Make(RenameCategory, RenameCategory_Behavior)
|
|
15
|
+
|
|
16
|
+
// StateViewSliceStreams
|
|
17
|
+
module CategoriesStreamSlice = Platform.StateViewSliceStream.Make(Categories, Categories_Projection)
|
|
18
|
+
module ProductDemandStreamSlice = Platform.StateViewSliceStream.Make(ProductDemand, ProductDemand_Projection)
|
|
19
|
+
module ProductsStreamSlice = Platform.StateViewSliceStream.Make(Products, Products_Projection)
|
|
20
|
+
|
|
21
|
+
// InboundTranslationSlices
|
|
22
|
+
module ImportProductSlice = Platform.InboundTranslationSlice.Make(ImportProduct, ImportProduct_Translation)
|
|
23
|
+
|
|
24
|
+
// Tasks
|
|
25
|
+
module ImportProductsTask = Platform.Task.Make(ImportProducts)
|
|
26
|
+
|
|
27
|
+
// ExtensionPoints
|
|
28
|
+
module Products_ExtensionPoint = Platform.ExtensionPoint.Make(Products_ExtensionPointMapping)
|
|
29
|
+
|
|
30
|
+
// Extensions
|
|
31
|
+
module Orders_Extension = Platform.Extension.Make(Orders_Extension.Mapping)
|
|
32
|
+
|
|
33
|
+
let pluginStructure = Platform.Plugin.makePluginDefinition(
|
|
34
|
+
~name="Catalog",
|
|
35
|
+
~stateViewSlices=[module(CategoriesStreamSlice), module(ProductDemandStreamSlice), module(ProductsStreamSlice)],
|
|
36
|
+
~stateChangeSlices=[module(AddCategorySlice), module(AddProductSlice), module(ArchiveCategorySlice), module(ChangeProductDescriptionSlice), module(ChangeProductNameSlice), module(ChangeProductPriceSlice), module(RecordProductDemandSlice), module(RenameCategorySlice)],
|
|
37
|
+
~inboundTranslationSlices=[module(ImportProductSlice)],
|
|
38
|
+
~extensions=[module(Orders_Extension)],
|
|
39
|
+
~extensionPoints=[module(Products_ExtensionPointMapping)],
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
let make = () =>
|
|
43
|
+
Platform.Plugin.make(
|
|
44
|
+
~name="Catalog",
|
|
45
|
+
~heartbeatInterval=5,
|
|
46
|
+
~extensionPoints=[module(Products_ExtensionPoint)],
|
|
47
|
+
~extensions=[module(Orders_Extension)],
|
|
48
|
+
~tasks=[module(ImportProductsTask)],
|
|
49
|
+
~stateChangeSlices=[module(AddCategorySlice), module(AddProductSlice), module(ArchiveCategorySlice), module(ChangeProductDescriptionSlice), module(ChangeProductNameSlice), module(ChangeProductPriceSlice), module(RecordProductDemandSlice), module(RenameCategorySlice)],
|
|
50
|
+
~stateViewSlices=[module(CategoriesStreamSlice), module(ProductDemandStreamSlice), module(ProductsStreamSlice)],
|
|
51
|
+
~inboundTranslationSlices=[module(ImportProductSlice)],
|
|
52
|
+
~pluginStructure=pluginStructure,
|
|
53
|
+
~uiFragments=?uiBundleUrl->Option.map(url =>
|
|
54
|
+
Platform.Plugin.makeAutoUIManifest(
|
|
55
|
+
~remoteEntryUrl=url,
|
|
56
|
+
~name="Catalog",
|
|
57
|
+
~pluginStructure,
|
|
58
|
+
~readModelPositions=["platform-summary"],
|
|
59
|
+
~aggregatePositions=["resource-detail"],
|
|
60
|
+
)
|
|
61
|
+
),
|
|
62
|
+
)
|
|
63
|
+
}
|