@reventlessdev/online-shop-aggregates-catalog 3.0.0-alpha.166 → 3.0.0-alpha.168

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 (167) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/lib/bs/.compiler.log +2 -2
  3. package/lib/bs/compiler-info.json +1 -1
  4. package/lib/bs/src/Category/Aggregate/Category-CatalogPlugin.cmi +0 -0
  5. package/lib/bs/src/Category/Aggregate/Category-CatalogPlugin.cmt +0 -0
  6. package/lib/bs/src/Category/Aggregate/Category_Behavior-CatalogPlugin.cmi +0 -0
  7. package/lib/bs/src/Category/Aggregate/Category_Behavior-CatalogPlugin.cmt +0 -0
  8. package/lib/bs/src/Category/ReadModel/Categories-CatalogPlugin.cmi +0 -0
  9. package/lib/bs/src/Category/ReadModel/Categories-CatalogPlugin.cmt +0 -0
  10. package/lib/bs/src/Category/ReadModel/Categories_Projections-CatalogPlugin.cmi +0 -0
  11. package/lib/bs/src/Category/ReadModel/Categories_Projections-CatalogPlugin.cmt +0 -0
  12. package/lib/bs/src/Extension/Orders_Extension-CatalogPlugin.cmi +0 -0
  13. package/lib/bs/src/Extension/Orders_Extension-CatalogPlugin.cmt +0 -0
  14. package/lib/bs/src/ExtensionPoint/Products_ExtensionPointMapping-CatalogPlugin.cmi +0 -0
  15. package/lib/bs/src/ExtensionPoint/Products_ExtensionPointMapping-CatalogPlugin.cmt +0 -0
  16. package/lib/bs/src/ExtensionPoint/Products_ExtensionPointMapping.res.mjs +2 -3
  17. package/lib/bs/src/Plugin-CatalogPlugin.cmi +0 -0
  18. package/lib/bs/src/Plugin-CatalogPlugin.cmt +0 -0
  19. package/lib/bs/src/Product/Aggregate/Product-CatalogPlugin.cmi +0 -0
  20. package/lib/bs/src/Product/Aggregate/Product-CatalogPlugin.cmt +0 -0
  21. package/lib/bs/src/Product/Aggregate/Product.ast +0 -0
  22. package/lib/bs/src/Product/Aggregate/Product.res +21 -3
  23. package/lib/bs/src/Product/Aggregate/Product.res.mjs +13 -2
  24. package/lib/bs/src/Product/Aggregate/Product_Behavior-CatalogPlugin.cmi +0 -0
  25. package/lib/bs/src/Product/Aggregate/Product_Behavior-CatalogPlugin.cmt +0 -0
  26. package/lib/bs/src/Product/Aggregate/Product_Behavior.ast +0 -0
  27. package/lib/bs/src/Product/Aggregate/Product_Behavior.res +11 -5
  28. package/lib/bs/src/Product/Aggregate/Product_Behavior.res.mjs +38 -7
  29. package/lib/bs/src/Product/ReadModel/Products-CatalogPlugin.cmi +0 -0
  30. package/lib/bs/src/Product/ReadModel/Products-CatalogPlugin.cmt +0 -0
  31. package/lib/bs/src/Product/ReadModel/Products.ast +0 -0
  32. package/lib/bs/src/Product/ReadModel/Products.res +1 -0
  33. package/lib/bs/src/Product/ReadModel/Products.res.mjs +3 -1
  34. package/lib/bs/src/Product/ReadModel/Products_Projections-CatalogPlugin.cmi +0 -0
  35. package/lib/bs/src/Product/ReadModel/Products_Projections-CatalogPlugin.cmt +0 -0
  36. package/lib/bs/src/Product/ReadModel/Products_Projections.ast +0 -0
  37. package/lib/bs/src/Product/ReadModel/Products_Projections.res +3 -2
  38. package/lib/bs/src/Product/ReadModel/Products_Projections.res.mjs +20 -4
  39. package/lib/bs/src/ProductDemand/Aggregate/ProductDemand-CatalogPlugin.cmi +0 -0
  40. package/lib/bs/src/ProductDemand/Aggregate/ProductDemand-CatalogPlugin.cmt +0 -0
  41. package/lib/bs/src/ProductDemand/Aggregate/ProductDemand_Behavior-CatalogPlugin.cmi +0 -0
  42. package/lib/bs/src/ProductDemand/Aggregate/ProductDemand_Behavior-CatalogPlugin.cmt +0 -0
  43. package/lib/bs/src/ProductDemand/ReadModel/ProductDemands-CatalogPlugin.cmi +0 -0
  44. package/lib/bs/src/ProductDemand/ReadModel/ProductDemands-CatalogPlugin.cmt +0 -0
  45. package/lib/bs/src/ProductDemand/ReadModel/ProductDemands_Projections-CatalogPlugin.cmi +0 -0
  46. package/lib/bs/src/ProductDemand/ReadModel/ProductDemands_Projections-CatalogPlugin.cmt +0 -0
  47. package/lib/bs/src/Task/ImportProducts-CatalogPlugin.cmi +0 -0
  48. package/lib/bs/src/Task/ImportProducts-CatalogPlugin.cmt +0 -0
  49. package/lib/bs/src/Task/ImportProducts.ast +0 -0
  50. package/lib/bs/src/Task/ImportProducts.res +3 -0
  51. package/lib/bs/src/Task/ImportProducts.res.mjs +2 -1
  52. package/lib/bs/tests/Category/Aggregate/Category_GWT-CatalogPlugin.cmi +0 -0
  53. package/lib/bs/tests/Category/Aggregate/Category_GWT-CatalogPlugin.cmt +0 -0
  54. package/lib/bs/tests/Category/ReadModel/Categories_GWT-CatalogPlugin.cmi +0 -0
  55. package/lib/bs/tests/Category/ReadModel/Categories_GWT-CatalogPlugin.cmt +0 -0
  56. package/lib/bs/tests/Extension/Orders_Extension_GWT-CatalogPlugin.cmi +0 -0
  57. package/lib/bs/tests/Extension/Orders_Extension_GWT-CatalogPlugin.cmt +0 -0
  58. package/lib/bs/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT-CatalogPlugin.cmi +0 -0
  59. package/lib/bs/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT-CatalogPlugin.cmt +0 -0
  60. package/lib/bs/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT.ast +0 -0
  61. package/lib/bs/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT.res +1 -1
  62. package/lib/bs/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT.res.mjs +2 -1
  63. package/lib/bs/tests/Product/Aggregate/Product_GWT-CatalogPlugin.cmi +0 -0
  64. package/lib/bs/tests/Product/Aggregate/Product_GWT-CatalogPlugin.cmt +0 -0
  65. package/lib/bs/tests/Product/Aggregate/Product_GWT.ast +0 -0
  66. package/lib/bs/tests/Product/Aggregate/Product_GWT.res +49 -18
  67. package/lib/bs/tests/Product/Aggregate/Product_GWT.res.mjs +36 -50
  68. package/lib/bs/tests/Product/ReadModel/Products_GWT-CatalogPlugin.cmi +0 -0
  69. package/lib/bs/tests/Product/ReadModel/Products_GWT-CatalogPlugin.cmt +0 -0
  70. package/lib/bs/tests/Product/ReadModel/Products_GWT.ast +0 -0
  71. package/lib/bs/tests/Product/ReadModel/Products_GWT.res +46 -8
  72. package/lib/bs/tests/Product/ReadModel/Products_GWT.res.mjs +30 -28
  73. package/lib/bs/tests/ProductDemand/Aggregate/ProductDemand_GWT-CatalogPlugin.cmi +0 -0
  74. package/lib/bs/tests/ProductDemand/Aggregate/ProductDemand_GWT-CatalogPlugin.cmt +0 -0
  75. package/lib/bs/tests/ProductDemand/ReadModel/ProductDemands_GWT-CatalogPlugin.cmi +0 -0
  76. package/lib/bs/tests/ProductDemand/ReadModel/ProductDemands_GWT-CatalogPlugin.cmt +0 -0
  77. package/lib/bs/tests/ProductDemand/ReadModel/ProductDemands_GWT.ast +0 -0
  78. package/lib/bs/tests/ProductDemand/ReadModel/ProductDemands_GWT.res +4 -4
  79. package/lib/bs/tests/ProductDemand/ReadModel/ProductDemands_GWT.res.mjs +8 -4
  80. package/lib/ocaml/.compiler.log +2 -2
  81. package/lib/ocaml/Categories-CatalogPlugin.cmi +0 -0
  82. package/lib/ocaml/Categories-CatalogPlugin.cmt +0 -0
  83. package/lib/ocaml/Categories_GWT-CatalogPlugin.cmi +0 -0
  84. package/lib/ocaml/Categories_GWT-CatalogPlugin.cmt +0 -0
  85. package/lib/ocaml/Categories_Projections-CatalogPlugin.cmi +0 -0
  86. package/lib/ocaml/Categories_Projections-CatalogPlugin.cmt +0 -0
  87. package/lib/ocaml/Category-CatalogPlugin.cmi +0 -0
  88. package/lib/ocaml/Category-CatalogPlugin.cmt +0 -0
  89. package/lib/ocaml/Category_Behavior-CatalogPlugin.cmi +0 -0
  90. package/lib/ocaml/Category_Behavior-CatalogPlugin.cmt +0 -0
  91. package/lib/ocaml/Category_GWT-CatalogPlugin.cmi +0 -0
  92. package/lib/ocaml/Category_GWT-CatalogPlugin.cmt +0 -0
  93. package/lib/ocaml/ImportProducts-CatalogPlugin.cmi +0 -0
  94. package/lib/ocaml/ImportProducts-CatalogPlugin.cmt +0 -0
  95. package/lib/ocaml/ImportProducts.ast +0 -0
  96. package/lib/ocaml/ImportProducts.res +3 -0
  97. package/lib/ocaml/Orders_Extension-CatalogPlugin.cmi +0 -0
  98. package/lib/ocaml/Orders_Extension-CatalogPlugin.cmt +0 -0
  99. package/lib/ocaml/Orders_Extension_GWT-CatalogPlugin.cmi +0 -0
  100. package/lib/ocaml/Orders_Extension_GWT-CatalogPlugin.cmt +0 -0
  101. package/lib/ocaml/Plugin-CatalogPlugin.cmi +0 -0
  102. package/lib/ocaml/Plugin-CatalogPlugin.cmt +0 -0
  103. package/lib/ocaml/Product-CatalogPlugin.cmi +0 -0
  104. package/lib/ocaml/Product-CatalogPlugin.cmt +0 -0
  105. package/lib/ocaml/Product.ast +0 -0
  106. package/lib/ocaml/Product.res +21 -3
  107. package/lib/ocaml/ProductDemand-CatalogPlugin.cmi +0 -0
  108. package/lib/ocaml/ProductDemand-CatalogPlugin.cmt +0 -0
  109. package/lib/ocaml/ProductDemand_Behavior-CatalogPlugin.cmi +0 -0
  110. package/lib/ocaml/ProductDemand_Behavior-CatalogPlugin.cmt +0 -0
  111. package/lib/ocaml/ProductDemand_GWT-CatalogPlugin.cmi +0 -0
  112. package/lib/ocaml/ProductDemand_GWT-CatalogPlugin.cmt +0 -0
  113. package/lib/ocaml/ProductDemands-CatalogPlugin.cmi +0 -0
  114. package/lib/ocaml/ProductDemands-CatalogPlugin.cmt +0 -0
  115. package/lib/ocaml/ProductDemands_GWT-CatalogPlugin.cmi +0 -0
  116. package/lib/ocaml/ProductDemands_GWT-CatalogPlugin.cmt +0 -0
  117. package/lib/ocaml/ProductDemands_GWT.ast +0 -0
  118. package/lib/ocaml/ProductDemands_GWT.res +4 -4
  119. package/lib/ocaml/ProductDemands_Projections-CatalogPlugin.cmi +0 -0
  120. package/lib/ocaml/ProductDemands_Projections-CatalogPlugin.cmt +0 -0
  121. package/lib/ocaml/Product_Behavior-CatalogPlugin.cmi +0 -0
  122. package/lib/ocaml/Product_Behavior-CatalogPlugin.cmt +0 -0
  123. package/lib/ocaml/Product_Behavior.ast +0 -0
  124. package/lib/ocaml/Product_Behavior.res +11 -5
  125. package/lib/ocaml/Product_GWT-CatalogPlugin.cmi +0 -0
  126. package/lib/ocaml/Product_GWT-CatalogPlugin.cmt +0 -0
  127. package/lib/ocaml/Product_GWT.ast +0 -0
  128. package/lib/ocaml/Product_GWT.res +49 -18
  129. package/lib/ocaml/Products-CatalogPlugin.cmi +0 -0
  130. package/lib/ocaml/Products-CatalogPlugin.cmt +0 -0
  131. package/lib/ocaml/Products.ast +0 -0
  132. package/lib/ocaml/Products.res +1 -0
  133. package/lib/ocaml/Products_ExtensionPointMapping-CatalogPlugin.cmi +0 -0
  134. package/lib/ocaml/Products_ExtensionPointMapping-CatalogPlugin.cmt +0 -0
  135. package/lib/ocaml/Products_ExtensionPointMapping_GWT-CatalogPlugin.cmi +0 -0
  136. package/lib/ocaml/Products_ExtensionPointMapping_GWT-CatalogPlugin.cmt +0 -0
  137. package/lib/ocaml/Products_ExtensionPointMapping_GWT.ast +0 -0
  138. package/lib/ocaml/Products_ExtensionPointMapping_GWT.res +1 -1
  139. package/lib/ocaml/Products_GWT-CatalogPlugin.cmi +0 -0
  140. package/lib/ocaml/Products_GWT-CatalogPlugin.cmt +0 -0
  141. package/lib/ocaml/Products_GWT.ast +0 -0
  142. package/lib/ocaml/Products_GWT.res +46 -8
  143. package/lib/ocaml/Products_Projections-CatalogPlugin.cmi +0 -0
  144. package/lib/ocaml/Products_Projections-CatalogPlugin.cmt +0 -0
  145. package/lib/ocaml/Products_Projections.ast +0 -0
  146. package/lib/ocaml/Products_Projections.res +3 -2
  147. package/package.json +8 -7
  148. package/src/ExtensionPoint/Products_ExtensionPointMapping.res.mjs +2 -3
  149. package/src/Product/Aggregate/Product.res +21 -3
  150. package/src/Product/Aggregate/Product.res.mjs +13 -2
  151. package/src/Product/Aggregate/Product_Behavior.res +11 -5
  152. package/src/Product/Aggregate/Product_Behavior.res.mjs +38 -7
  153. package/src/Product/ReadModel/Products.res +1 -0
  154. package/src/Product/ReadModel/Products.res.mjs +3 -1
  155. package/src/Product/ReadModel/Products_Projections.res +3 -2
  156. package/src/Product/ReadModel/Products_Projections.res.mjs +20 -4
  157. package/src/Task/ImportProducts.res +3 -0
  158. package/src/Task/ImportProducts.res.mjs +2 -1
  159. package/src/capabilities.json +18 -0
  160. package/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT.res +1 -1
  161. package/tests/ExtensionPoint/Products_ExtensionPointMapping_GWT.res.mjs +2 -1
  162. package/tests/Product/Aggregate/Product_GWT.res +49 -18
  163. package/tests/Product/Aggregate/Product_GWT.res.mjs +36 -50
  164. package/tests/Product/ReadModel/Products_GWT.res +46 -8
  165. package/tests/Product/ReadModel/Products_GWT.res.mjs +30 -28
  166. package/tests/ProductDemand/ReadModel/ProductDemands_GWT.res +4 -4
  167. package/tests/ProductDemand/ReadModel/ProductDemands_GWT.res.mjs +8 -4
package/CHANGELOG.md CHANGED
@@ -3,6 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.0.0-alpha.168 (2026-07-30)
7
+
8
+ ### Features
9
+
10
+ * **spec,core,local:** emit capabilities.json from the plugin build ([57a3276](https://github.com/ReventlessDev/reventless-core/commit/57a3276a6b02af93490a8b460e3aa158b7e0e0f8))
11
+ * **spec,core:** derive the platform capability list — inference and generation (stage 3) ([8ab4d25](https://github.com/ReventlessDev/reventless-core/commit/8ab4d2504bd717487fbc87a0f5a053024c8258f9))
12
+
13
+
14
+ # 3.0.0-alpha.167 (2026-07-29)
15
+
16
+ ### Features
17
+
18
+ * **example:** serve declared object stores without a host shell ([27794df](https://github.com/ReventlessDev/reventless-core/commit/27794df37a177a29419e82e4fbe698a1489a1bd9))
19
+
20
+
6
21
  # 3.0.0-alpha.166 (2026-07-28)
7
22
 
8
23
  **Note:** Version bump only for package @reventlessdev/online-shop-aggregates-catalog
@@ -1,2 +1,2 @@
1
- #Start(1785258655386)
2
- #Done(1785258660835)
1
+ #Start(1785388949966)
2
+ #Done(1785388955348)
@@ -4,5 +4,5 @@
4
4
  "bsc_hash": "75e3a59c95cc953608fd3dd6ea6ed68141bba4414a20a52f114261b8a48385fa",
5
5
  "rescript_config_hash": "50d5358a2cbe328e82ae9b442e4615b86dbfe6b2ce05e9eca04a0c78da0e4708",
6
6
  "runtime_path": "/home/runner/work/reventless-core/reventless-core/node_modules/@rescript/runtime",
7
- "generated_at": "1785258660842"
7
+ "generated_at": "1785388955350"
8
8
  }
@@ -18,9 +18,6 @@ let mapOutgoingEvent = (id, event, _meta, _queryEngine) => {
18
18
  price: event.price
19
19
  }
20
20
  }];
21
- case "NameUpdated" :
22
- case "DescriptionUpdated" :
23
- return [];
24
21
  case "PriceUpdated" :
25
22
  return [{
26
23
  TAG: "PublishEvent",
@@ -31,6 +28,8 @@ let mapOutgoingEvent = (id, event, _meta, _queryEngine) => {
31
28
  price: event.price
32
29
  }
33
30
  }];
31
+ default:
32
+ return [];
34
33
  }
35
34
  };
36
35
 
Binary file
Binary file
@@ -1,21 +1,39 @@
1
1
  // Product aggregate specification.
2
- // A product listing with name, description, and price.
2
+ // A product listing with name, description, price and an image.
3
+ //
4
+ // `@storageRef("productImages")` on the command inputs is what makes `imageUrl`
5
+ // an upload rather than a free-text field: the store name is unqualified, so it
6
+ // resolves to this plugin's own `Catalog.productImages`, and the platform must
7
+ // provision it. Events carry the resulting ref as a plain string — the
8
+ // annotation describes an input, not a stored value.
3
9
 
4
10
  @@reventless.spec
5
11
 
6
12
  @schema
7
13
  type command =
8
- | Add({name: string, description: string, price: float})
14
+ | Add({
15
+ name: string,
16
+ description: string,
17
+ price: float,
18
+ @storageRef("productImages") imageUrl: string,
19
+ })
9
20
  | UpdateName({name: string})
10
21
  | UpdateDescription({description: string})
11
22
  | UpdatePrice({price: float})
23
+ | UpdateImage({@storageRef("productImages") imageUrl: string})
12
24
 
13
25
  @schema
14
26
  type event =
15
- | Added({name: string, description: string, price: float})
27
+ | Added({
28
+ name: string,
29
+ description: string,
30
+ price: float,
31
+ @storageRef("productImages") imageUrl: string,
32
+ })
16
33
  | NameUpdated({name: string})
17
34
  | DescriptionUpdated({description: string})
18
35
  | PriceUpdated({price: float})
36
+ | ImageUpdated({@storageRef("productImages") imageUrl: string})
19
37
 
20
38
  @schema
21
39
  type error =
@@ -1,13 +1,15 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as S from "sury/src/S.res.mjs";
4
+ import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
4
5
 
5
6
  let commandSchema = S.union([
6
7
  S.schema(s => ({
7
8
  TAG: "Add",
8
9
  name: s.m(S.string),
9
10
  description: s.m(S.string),
10
- price: s.m(S.float)
11
+ price: s.m(S.float),
12
+ imageUrl: s.m(StorageRef$Reventless.forStore(undefined, "productImages"))
11
13
  })),
12
14
  S.schema(s => ({
13
15
  TAG: "UpdateName",
@@ -20,6 +22,10 @@ let commandSchema = S.union([
20
22
  S.schema(s => ({
21
23
  TAG: "UpdatePrice",
22
24
  price: s.m(S.float)
25
+ })),
26
+ S.schema(s => ({
27
+ TAG: "UpdateImage",
28
+ imageUrl: s.m(StorageRef$Reventless.forStore(undefined, "productImages"))
23
29
  }))
24
30
  ]);
25
31
 
@@ -28,7 +34,8 @@ let eventSchema = S.union([
28
34
  TAG: "Added",
29
35
  name: s.m(S.string),
30
36
  description: s.m(S.string),
31
- price: s.m(S.float)
37
+ price: s.m(S.float),
38
+ imageUrl: s.m(StorageRef$Reventless.forStore(undefined, "productImages"))
32
39
  })),
33
40
  S.schema(s => ({
34
41
  TAG: "NameUpdated",
@@ -41,6 +48,10 @@ let eventSchema = S.union([
41
48
  S.schema(s => ({
42
49
  TAG: "PriceUpdated",
43
50
  price: s.m(S.float)
51
+ })),
52
+ S.schema(s => ({
53
+ TAG: "ImageUpdated",
54
+ imageUrl: s.m(StorageRef$Reventless.forStore(undefined, "productImages"))
44
55
  }))
45
56
  ]);
46
57
 
@@ -12,27 +12,31 @@
12
12
  @schema
13
13
  type state =
14
14
  | NotCreated
15
- | Created({name: string, description: string, price: float})
15
+ | Created({name: string, description: string, price: float, imageUrl: string})
16
16
 
17
17
  let initialState = NotCreated
18
18
 
19
19
  let evolve = (state, event) =>
20
20
  switch (state, event) {
21
- | (NotCreated, Added({name, description, price})) => Created({name, description, price})
22
- | (Created(_), Added({name, description, price})) => Created({name, description, price})
21
+ | (NotCreated, Added({name, description, price, imageUrl})) =>
22
+ Created({name, description, price, imageUrl})
23
+ | (Created(_), Added({name, description, price, imageUrl})) =>
24
+ Created({name, description, price, imageUrl})
23
25
  | (Created(s), NameUpdated({name})) => Created({...s, name})
24
26
  | (Created(s), DescriptionUpdated({description})) => Created({...s, description})
25
27
  | (Created(s), PriceUpdated({price})) => Created({...s, price})
28
+ | (Created(s), ImageUpdated({imageUrl})) => Created({...s, imageUrl})
26
29
  | (NotCreated, _) => state
27
30
  }
28
31
 
29
32
  let decide = (state, command) =>
30
33
  switch (state, command) {
31
- | (NotCreated, Add({name, description, price})) =>
32
- Ok([Added({name, description, price})])
34
+ | (NotCreated, Add({name, description, price, imageUrl})) =>
35
+ Ok([Added({name, description, price, imageUrl})])
33
36
  | (NotCreated, UpdateName(_)) => Error(ProductNotFound)
34
37
  | (NotCreated, UpdateDescription(_)) => Error(ProductNotFound)
35
38
  | (NotCreated, UpdatePrice(_)) => Error(ProductNotFound)
39
+ | (NotCreated, UpdateImage(_)) => Error(ProductNotFound)
36
40
  | (Created(_), Add(_)) => Error(ProductAlreadyExists)
37
41
  | (Created(s), UpdateName({name})) if name == s.name => Ok([])
38
42
  | (Created(_), UpdateName({name})) => Ok([NameUpdated({name: name})])
@@ -41,4 +45,6 @@ let decide = (state, command) =>
41
45
  Ok([DescriptionUpdated({description: description})])
42
46
  | (Created(s), UpdatePrice({price})) if price == s.price => Ok([])
43
47
  | (Created(_), UpdatePrice({price})) => Ok([PriceUpdated({price: price})])
48
+ | (Created(s), UpdateImage({imageUrl})) if imageUrl == s.imageUrl => Ok([])
49
+ | (Created(_), UpdateImage({imageUrl})) => Ok([ImageUpdated({imageUrl: imageUrl})])
44
50
  }
@@ -8,7 +8,8 @@ let stateSchema = S.union([
8
8
  TAG: "Created",
9
9
  name: s.m(S.string),
10
10
  description: s.m(S.string),
11
- price: s.m(S.float)
11
+ price: s.m(S.float),
12
+ imageUrl: s.m(S.string)
12
13
  }))
13
14
  ]);
14
15
 
@@ -19,7 +20,8 @@ function evolve(state, event) {
19
20
  TAG: "Created",
20
21
  name: event.name,
21
22
  description: event.description,
22
- price: event.price
23
+ price: event.price,
24
+ imageUrl: event.imageUrl
23
25
  };
24
26
  } else {
25
27
  return state;
@@ -31,28 +33,40 @@ function evolve(state, event) {
31
33
  TAG: "Created",
32
34
  name: event.name,
33
35
  description: event.description,
34
- price: event.price
36
+ price: event.price,
37
+ imageUrl: event.imageUrl
35
38
  };
36
39
  case "NameUpdated" :
37
40
  return {
38
41
  TAG: "Created",
39
42
  name: event.name,
40
43
  description: state.description,
41
- price: state.price
44
+ price: state.price,
45
+ imageUrl: state.imageUrl
42
46
  };
43
47
  case "DescriptionUpdated" :
44
48
  return {
45
49
  TAG: "Created",
46
50
  name: state.name,
47
51
  description: event.description,
48
- price: state.price
52
+ price: state.price,
53
+ imageUrl: state.imageUrl
49
54
  };
50
55
  case "PriceUpdated" :
51
56
  return {
52
57
  TAG: "Created",
53
58
  name: state.name,
54
59
  description: state.description,
55
- price: event.price
60
+ price: event.price,
61
+ imageUrl: state.imageUrl
62
+ };
63
+ case "ImageUpdated" :
64
+ return {
65
+ TAG: "Created",
66
+ name: state.name,
67
+ description: state.description,
68
+ price: state.price,
69
+ imageUrl: event.imageUrl
56
70
  };
57
71
  }
58
72
  }
@@ -66,7 +80,8 @@ function decide(state, command) {
66
80
  TAG: "Added",
67
81
  name: command.name,
68
82
  description: command.description,
69
- price: command.price
83
+ price: command.price,
84
+ imageUrl: command.imageUrl
70
85
  }]
71
86
  };
72
87
  } else {
@@ -130,6 +145,22 @@ function decide(state, command) {
130
145
  }]
131
146
  };
132
147
  }
148
+ case "UpdateImage" :
149
+ let imageUrl = command.imageUrl;
150
+ if (imageUrl === state.imageUrl) {
151
+ return {
152
+ TAG: "Ok",
153
+ _0: []
154
+ };
155
+ } else {
156
+ return {
157
+ TAG: "Ok",
158
+ _0: [{
159
+ TAG: "ImageUpdated",
160
+ imageUrl: imageUrl
161
+ }]
162
+ };
163
+ }
133
164
  }
134
165
  }
135
166
 
@@ -8,5 +8,6 @@ type state = {
8
8
  name: string,
9
9
  description: string,
10
10
  price: float,
11
+ @storageRef("productImages") imageUrl: string,
11
12
  }
12
13
 
@@ -2,11 +2,13 @@
2
2
 
3
3
  import * as S from "sury/src/S.res.mjs";
4
4
  import * as ReadModel$Reventless from "@reventlessdev/reventless-spec/src/components/ReadModel.res.mjs";
5
+ import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
5
6
 
6
7
  let stateSchema = S.schema(s => ({
7
8
  name: s.m(S.string),
8
9
  description: s.m(S.string),
9
- price: s.m(S.float)
10
+ price: s.m(S.float),
11
+ imageUrl: s.m(StorageRef$Reventless.forStore(undefined, "productImages"))
10
12
  }));
11
13
 
12
14
  let config = ReadModel$Reventless.config(undefined, undefined, undefined);
@@ -9,12 +9,13 @@ module ProductMapping = Mapping.Make(
9
9
  open Product
10
10
  let project = ({event, id, _}) =>
11
11
  switch event {
12
- | Added({name, description, price}) =>
13
- Set(id, {Products.name: name, description, price})
12
+ | Added({name, description, price, imageUrl}) =>
13
+ Set(id, {Products.name: name, description, price, imageUrl})
14
14
  | NameUpdated({name}) => Update(id, state => {...state, name})
15
15
  | DescriptionUpdated({description}) =>
16
16
  Update(id, state => {...state, description})
17
17
  | PriceUpdated({price}) => Update(id, state => {...state, price})
18
+ | ImageUpdated({imageUrl}) => Update(id, state => {...state, imageUrl})
18
19
  }
19
20
  },
20
21
  )
@@ -23,7 +23,8 @@ function project(param) {
23
23
  _1: {
24
24
  name: event.name,
25
25
  description: event.description,
26
- price: event.price
26
+ price: event.price,
27
+ imageUrl: event.imageUrl
27
28
  }
28
29
  };
29
30
  case "NameUpdated" :
@@ -34,7 +35,8 @@ function project(param) {
34
35
  _1: state => ({
35
36
  name: name,
36
37
  description: state.description,
37
- price: state.price
38
+ price: state.price,
39
+ imageUrl: state.imageUrl
38
40
  })
39
41
  };
40
42
  case "DescriptionUpdated" :
@@ -45,7 +47,8 @@ function project(param) {
45
47
  _1: state => ({
46
48
  name: state.name,
47
49
  description: description,
48
- price: state.price
50
+ price: state.price,
51
+ imageUrl: state.imageUrl
49
52
  })
50
53
  };
51
54
  case "PriceUpdated" :
@@ -56,7 +59,20 @@ function project(param) {
56
59
  _1: state => ({
57
60
  name: state.name,
58
61
  description: state.description,
59
- price: price
62
+ price: price,
63
+ imageUrl: state.imageUrl
64
+ })
65
+ };
66
+ case "ImageUpdated" :
67
+ let imageUrl = event.imageUrl;
68
+ return {
69
+ TAG: "Update",
70
+ _0: id,
71
+ _1: state => ({
72
+ name: state.name,
73
+ description: state.description,
74
+ price: state.price,
75
+ imageUrl: imageUrl
60
76
  })
61
77
  };
62
78
  }
Binary file
@@ -27,6 +27,9 @@ let importCallback = (~eventName, ~key) => {
27
27
  name: "Imported Product",
28
28
  description: "Imported from " ++ key,
29
29
  price: 9.99,
30
+ // A CSV row carries no upload, so the ref is empty until someone
31
+ // issues UpdateImage against the presigned store.
32
+ imageUrl: "",
30
33
  })->Message.encode(Product.commandSchema),
31
34
  },
32
35
  ],
@@ -29,7 +29,8 @@ function importCallback(eventName, key) {
29
29
  TAG: "Add",
30
30
  name: "Imported Product",
31
31
  description: "Imported from " + key,
32
- price: 9.99
32
+ price: 9.99,
33
+ imageUrl: ""
33
34
  }, Product$CatalogPlugin.commandSchema)
34
35
  }]
35
36
  }]);
@@ -5,7 +5,7 @@
5
5
  describe("Products ExtensionPoint mapping", () => {
6
6
  test("Added publishes ProductBecameAvailable", () =>
7
7
  whenDelegateEvent(
8
- Delegate.Added({name: "Book", description: "A good book", price: 9.99}),
8
+ Delegate.Added({name: "Book", description: "A good book", price: 9.99, imageUrl: "/productImages/book.jpg"}),
9
9
  )->thenPublishesEvent(
10
10
  "gwt-id",
11
11
  ExtensionPoint.ProductBecameAvailable({productId: "gwt-id", name: "Book", price: 9.99}),
@@ -43,7 +43,8 @@ describe("Products ExtensionPoint mapping", () => {
43
43
  TAG: "Added",
44
44
  name: "Book",
45
45
  description: "A good book",
46
- price: 9.99
46
+ price: 9.99,
47
+ imageUrl: "/productImages/book.jpg"
47
48
  }), "gwt-id", {
48
49
  TAG: "ProductBecameAvailable",
49
50
  productId: "gwt-id",