@labdigital/commercetools-mock 2.66.0 → 3.0.0-beta.0

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 (281) hide show
  1. package/README.md +31 -8
  2. package/dist/abstract-BKFcva6S.mjs +1044 -0
  3. package/dist/abstract-BKFcva6S.mjs.map +1 -0
  4. package/dist/config-BcNSzPZz.d.mts +1718 -0
  5. package/dist/index.d.mts +50 -1633
  6. package/dist/index.mjs +3769 -2653
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/storage/sqlite.d.mts +59 -0
  9. package/dist/storage/sqlite.mjs +234 -0
  10. package/dist/storage/sqlite.mjs.map +1 -0
  11. package/package.json +26 -29
  12. package/src/ctMock.ts +125 -136
  13. package/src/helpers.ts +14 -6
  14. package/src/index.ts +5 -0
  15. package/src/lib/masking.ts +4 -5
  16. package/src/lib/product-review-statistics.test.ts +257 -294
  17. package/src/lib/review-statistics.ts +17 -4
  18. package/src/oauth/helpers.ts +7 -4
  19. package/src/oauth/server.test.ts +102 -62
  20. package/src/oauth/server.ts +215 -213
  21. package/src/oauth/store.ts +20 -6
  22. package/src/orderSearch.ts +3 -3
  23. package/src/product-projection-search.ts +38 -20
  24. package/src/product-search-availability.test.ts +31 -52
  25. package/src/product-search.ts +19 -10
  26. package/src/projectAPI.ts +6 -22
  27. package/src/repositories/abstract.ts +182 -48
  28. package/src/repositories/as-associate.test.ts +19 -19
  29. package/src/repositories/associate-role.ts +12 -23
  30. package/src/repositories/attribute-group.test.ts +23 -23
  31. package/src/repositories/attribute-group.ts +6 -4
  32. package/src/repositories/business-unit.test.ts +63 -57
  33. package/src/repositories/business-unit.ts +107 -55
  34. package/src/repositories/cart/actions.ts +96 -65
  35. package/src/repositories/cart/helpers.ts +15 -11
  36. package/src/repositories/cart/index.test.ts +136 -30
  37. package/src/repositories/cart/index.ts +76 -59
  38. package/src/repositories/cart-discount/actions.ts +12 -44
  39. package/src/repositories/cart-discount/index.ts +20 -8
  40. package/src/repositories/category/actions.ts +27 -27
  41. package/src/repositories/category/index.test.ts +13 -9
  42. package/src/repositories/category/index.ts +40 -23
  43. package/src/repositories/channel.test.ts +53 -51
  44. package/src/repositories/channel.ts +12 -22
  45. package/src/repositories/custom-object.ts +34 -25
  46. package/src/repositories/customer/actions.ts +47 -25
  47. package/src/repositories/customer/index.test.ts +11 -11
  48. package/src/repositories/customer/index.ts +65 -35
  49. package/src/repositories/customer-group.test.ts +44 -42
  50. package/src/repositories/customer-group.ts +12 -22
  51. package/src/repositories/discount-code/actions.ts +3 -19
  52. package/src/repositories/discount-code/index.ts +9 -4
  53. package/src/repositories/discount-group/index.ts +8 -3
  54. package/src/repositories/extension.test.ts +27 -27
  55. package/src/repositories/extension.ts +10 -5
  56. package/src/repositories/helpers.ts +126 -47
  57. package/src/repositories/inventory-entry/actions.ts +3 -24
  58. package/src/repositories/inventory-entry/index.ts +19 -11
  59. package/src/repositories/my-customer.ts +13 -12
  60. package/src/repositories/my-order.ts +5 -2
  61. package/src/repositories/order/actions.ts +84 -56
  62. package/src/repositories/order/index.test.ts +36 -31
  63. package/src/repositories/order/index.ts +83 -49
  64. package/src/repositories/order-edit.ts +8 -3
  65. package/src/repositories/payment/actions.ts +64 -44
  66. package/src/repositories/payment/helpers.ts +3 -3
  67. package/src/repositories/payment/index.ts +28 -12
  68. package/src/repositories/product/actions.ts +133 -98
  69. package/src/repositories/product/helpers.ts +29 -16
  70. package/src/repositories/product/index.ts +42 -25
  71. package/src/repositories/product-discount.ts +6 -4
  72. package/src/repositories/product-projection.ts +41 -21
  73. package/src/repositories/product-selection.ts +8 -15
  74. package/src/repositories/product-tailoring.ts +22 -3
  75. package/src/repositories/product-type.ts +45 -4
  76. package/src/repositories/project.ts +57 -13
  77. package/src/repositories/quote/actions.ts +5 -28
  78. package/src/repositories/quote/index.ts +29 -6
  79. package/src/repositories/quote-request/actions.ts +5 -28
  80. package/src/repositories/quote-request/index.test.ts +3 -3
  81. package/src/repositories/quote-request/index.ts +31 -11
  82. package/src/repositories/quote-staged/actions.ts +5 -28
  83. package/src/repositories/quote-staged/index.ts +22 -8
  84. package/src/repositories/recurrence-policy/index.ts +6 -4
  85. package/src/repositories/recurring-order/actions.ts +7 -32
  86. package/src/repositories/recurring-order/index.ts +8 -6
  87. package/src/repositories/review.test.ts +147 -142
  88. package/src/repositories/review.ts +31 -37
  89. package/src/repositories/shipping-method/actions.ts +11 -28
  90. package/src/repositories/shipping-method/index.ts +26 -15
  91. package/src/repositories/shopping-list/actions.ts +21 -31
  92. package/src/repositories/shopping-list/index.ts +44 -22
  93. package/src/repositories/standalone-price.ts +6 -4
  94. package/src/repositories/state.ts +15 -9
  95. package/src/repositories/store.ts +21 -32
  96. package/src/repositories/subscription.test.ts +22 -22
  97. package/src/repositories/subscription.ts +8 -3
  98. package/src/repositories/tax-category/index.ts +8 -3
  99. package/src/repositories/type/actions.ts +21 -3
  100. package/src/repositories/type/index.ts +5 -3
  101. package/src/repositories/zone.test.ts +112 -77
  102. package/src/repositories/zone.ts +5 -3
  103. package/src/schemas/generated/associate-role.ts +13 -0
  104. package/src/schemas/generated/attribute-group.ts +12 -0
  105. package/src/schemas/generated/business-unit.ts +38 -0
  106. package/src/schemas/generated/cart-discount.ts +33 -0
  107. package/src/schemas/generated/cart.ts +61 -0
  108. package/src/schemas/generated/category.ts +25 -0
  109. package/src/schemas/generated/channel.ts +21 -0
  110. package/src/schemas/generated/common.ts +1372 -0
  111. package/src/schemas/generated/custom-object.ts +11 -0
  112. package/src/schemas/generated/customer-group.ts +11 -0
  113. package/src/schemas/generated/customer.ts +47 -0
  114. package/src/schemas/generated/discount-code.ts +25 -0
  115. package/src/schemas/generated/discount-group.ts +13 -0
  116. package/src/schemas/generated/extension.ts +15 -0
  117. package/src/schemas/generated/index.ts +42 -0
  118. package/src/schemas/generated/inventory-entry.ts +20 -0
  119. package/src/schemas/generated/my-quote-request.ts +10 -0
  120. package/src/schemas/generated/order-edit.ts +18 -0
  121. package/src/schemas/generated/order-from-cart.ts +25 -0
  122. package/src/schemas/generated/payment.ts +30 -0
  123. package/src/schemas/generated/product-discount.ts +20 -0
  124. package/src/schemas/generated/product-selection.ts +18 -0
  125. package/src/schemas/generated/product-tailoring.ts +26 -0
  126. package/src/schemas/generated/product-type.ts +12 -0
  127. package/src/schemas/generated/product.ts +37 -0
  128. package/src/schemas/generated/quote-request.ts +19 -0
  129. package/src/schemas/generated/quote.ts +18 -0
  130. package/src/schemas/generated/recurrence-policy.ts +15 -0
  131. package/src/schemas/generated/recurring-order.ts +19 -0
  132. package/src/schemas/generated/review.ts +24 -0
  133. package/src/schemas/generated/shipping-method.ts +24 -0
  134. package/src/schemas/generated/shopping-list.ts +28 -0
  135. package/src/schemas/generated/staged-quote.ts +18 -0
  136. package/src/schemas/generated/standalone-price.ts +32 -0
  137. package/src/schemas/generated/state.ts +20 -0
  138. package/src/schemas/generated/store.ts +23 -0
  139. package/src/schemas/generated/subscription.ts +20 -0
  140. package/src/schemas/generated/tax-category.ts +12 -0
  141. package/src/schemas/generated/type.ts +17 -0
  142. package/src/schemas/generated/zone.ts +12 -0
  143. package/src/schemas/update-request.ts +3 -5
  144. package/src/server.ts +32 -4
  145. package/src/services/abstract.ts +207 -101
  146. package/src/services/as-associate-cart.test.ts +28 -36
  147. package/src/services/as-associate-cart.ts +15 -12
  148. package/src/services/as-associate-order.test.ts +33 -40
  149. package/src/services/as-associate-order.ts +15 -12
  150. package/src/services/as-associate-quote-request.ts +15 -12
  151. package/src/services/as-associate-shopping-list.test.ts +25 -35
  152. package/src/services/as-associate-shopping-list.ts +15 -12
  153. package/src/services/as-associate.test.ts +21 -15
  154. package/src/services/as-associate.ts +23 -22
  155. package/src/services/associate-roles.test.ts +16 -22
  156. package/src/services/associate-roles.ts +2 -2
  157. package/src/services/attribute-group.test.ts +40 -44
  158. package/src/services/attribute-group.ts +2 -2
  159. package/src/services/business-units.test.ts +227 -163
  160. package/src/services/business-units.ts +2 -2
  161. package/src/services/cart-discount.test.ts +253 -187
  162. package/src/services/cart-discount.ts +2 -2
  163. package/src/services/cart.test.ts +833 -832
  164. package/src/services/cart.ts +31 -12
  165. package/src/services/category.test.ts +208 -130
  166. package/src/services/category.ts +2 -2
  167. package/src/services/channel.test.ts +39 -44
  168. package/src/services/channel.ts +2 -2
  169. package/src/services/custom-object.test.ts +103 -79
  170. package/src/services/custom-object.ts +106 -38
  171. package/src/services/customer-group.test.ts +39 -44
  172. package/src/services/customer-group.ts +2 -2
  173. package/src/services/customer.test.ts +357 -292
  174. package/src/services/customer.ts +70 -23
  175. package/src/services/discount-code.test.ts +57 -68
  176. package/src/services/discount-code.ts +2 -2
  177. package/src/services/discount-group.test.ts +111 -134
  178. package/src/services/discount-group.ts +2 -2
  179. package/src/services/draft-validation.test.ts +255 -0
  180. package/src/services/extension.test.ts +39 -44
  181. package/src/services/extension.ts +2 -2
  182. package/src/services/inventory-entry.test.ts +106 -87
  183. package/src/services/inventory-entry.ts +2 -2
  184. package/src/services/my-business-unit.test.ts +82 -112
  185. package/src/services/my-business-unit.ts +25 -19
  186. package/src/services/my-cart.test.ts +46 -41
  187. package/src/services/my-cart.ts +32 -28
  188. package/src/services/my-customer.test.ts +153 -88
  189. package/src/services/my-customer.ts +130 -61
  190. package/src/services/my-order.ts +15 -12
  191. package/src/services/my-payment.test.ts +30 -24
  192. package/src/services/my-payment.ts +2 -2
  193. package/src/services/my-shopping-list.ts +2 -2
  194. package/src/services/order.test.ts +332 -276
  195. package/src/services/order.ts +45 -27
  196. package/src/services/payment.test.ts +31 -29
  197. package/src/services/payment.ts +2 -2
  198. package/src/services/product-discount.test.ts +39 -46
  199. package/src/services/product-discount.ts +2 -2
  200. package/src/services/product-projection.test.ts +176 -166
  201. package/src/services/product-projection.ts +31 -15
  202. package/src/services/product-selection.test.ts +17 -9
  203. package/src/services/product-selection.ts +2 -2
  204. package/src/services/product-type.test.ts +80 -21
  205. package/src/services/product-type.ts +2 -2
  206. package/src/services/product.test.ts +569 -534
  207. package/src/services/product.ts +14 -7
  208. package/src/services/project.test.ts +22 -12
  209. package/src/services/project.ts +28 -13
  210. package/src/services/quote-request.test.ts +36 -39
  211. package/src/services/quote-request.ts +2 -2
  212. package/src/services/quote-staged.ts +2 -2
  213. package/src/services/quote.ts +2 -2
  214. package/src/services/recurrence-policy.test.ts +114 -139
  215. package/src/services/recurrence-policy.ts +2 -2
  216. package/src/services/recurring-order.test.ts +149 -194
  217. package/src/services/recurring-order.ts +2 -2
  218. package/src/services/reviews.test.ts +127 -106
  219. package/src/services/reviews.ts +2 -2
  220. package/src/services/shipping-method.test.ts +96 -125
  221. package/src/services/shipping-method.ts +24 -12
  222. package/src/services/shopping-list.test.ts +183 -141
  223. package/src/services/shopping-list.ts +2 -2
  224. package/src/services/standalone-price.test.ts +60 -46
  225. package/src/services/standalone-price.ts +2 -2
  226. package/src/services/state.test.ts +20 -25
  227. package/src/services/state.ts +2 -2
  228. package/src/services/store.test.ts +26 -45
  229. package/src/services/store.ts +2 -2
  230. package/src/services/subscription.test.ts +39 -44
  231. package/src/services/subscription.ts +2 -2
  232. package/src/services/tax-category.test.ts +33 -36
  233. package/src/services/tax-category.ts +2 -2
  234. package/src/services/type.test.ts +45 -44
  235. package/src/services/type.ts +2 -2
  236. package/src/services/zone.test.ts +40 -44
  237. package/src/services/zone.ts +2 -2
  238. package/src/shipping.ts +41 -11
  239. package/src/storage/abstract.ts +248 -17
  240. package/src/storage/in-memory.ts +147 -290
  241. package/src/storage/sqlite.ts +429 -0
  242. package/src/storage/storage-map.ts +75 -0
  243. package/src/storage/storage.test-helpers.ts +97 -0
  244. package/src/storage/storage.test.ts +802 -0
  245. package/src/testing/associate-role.ts +28 -0
  246. package/src/testing/attribute-group.ts +27 -0
  247. package/src/testing/business-unit.ts +9 -8
  248. package/src/testing/cart-discount.ts +34 -0
  249. package/src/testing/cart.ts +20 -0
  250. package/src/testing/category.ts +25 -0
  251. package/src/testing/channel.ts +23 -0
  252. package/src/testing/custom-object.ts +27 -0
  253. package/src/testing/customer-group.ts +26 -0
  254. package/src/testing/customer.ts +36 -33
  255. package/src/testing/discount-code.ts +29 -0
  256. package/src/testing/discount-group.ts +27 -0
  257. package/src/testing/extension.ts +32 -0
  258. package/src/testing/index.ts +33 -0
  259. package/src/testing/inventory-entry.ts +26 -0
  260. package/src/testing/order.ts +27 -0
  261. package/src/testing/payment.ts +23 -0
  262. package/src/testing/product-discount.ts +33 -0
  263. package/src/testing/product-selection.ts +28 -0
  264. package/src/testing/product-type.ts +27 -0
  265. package/src/testing/product.ts +38 -0
  266. package/src/testing/quote-request.ts +29 -0
  267. package/src/testing/recurrence-policy.ts +33 -0
  268. package/src/testing/recurring-order.ts +32 -0
  269. package/src/testing/review.ts +24 -0
  270. package/src/testing/shipping-method.ts +31 -0
  271. package/src/testing/shopping-list.ts +25 -0
  272. package/src/testing/standalone-price.ts +31 -0
  273. package/src/testing/state.ts +21 -0
  274. package/src/testing/store.ts +26 -0
  275. package/src/testing/subscription.ts +38 -0
  276. package/src/testing/tax-category.ts +27 -0
  277. package/src/testing/type.ts +9 -6
  278. package/src/testing/zone.ts +22 -0
  279. package/src/validate.test.ts +122 -0
  280. package/src/validate.ts +78 -7
  281. package/src/.env +0 -0
@@ -1,4 +1,3 @@
1
- import assert from "node:assert";
2
1
  import type {
3
2
  AssociateRole,
4
3
  AttributeGroup,
@@ -14,10 +13,8 @@ import type {
14
13
  DiscountGroup,
15
14
  Extension,
16
15
  InvalidInputError,
17
- InvalidJsonInputError,
18
16
  InventoryEntry,
19
17
  Order,
20
- PagedQueryResponse,
21
18
  Payment,
22
19
  Product,
23
20
  ProductDiscount,
@@ -29,12 +26,8 @@ import type {
29
26
  QuoteRequest,
30
27
  RecurrencePolicy,
31
28
  RecurringOrder,
32
- Reference,
33
- ReferencedResourceNotFoundError,
34
- ResourceIdentifier,
35
29
  ShippingMethod,
36
30
  ShoppingList,
37
- ShoppingListLineItem,
38
31
  StagedQuote,
39
32
  State,
40
33
  Store,
@@ -45,16 +38,15 @@ import type {
45
38
  } from "@commercetools/platform-sdk";
46
39
  import { CommercetoolsError } from "#src/exceptions.ts";
47
40
  import { cloneObject } from "../helpers.ts";
48
- import { parseExpandClause } from "../lib/expandParser.ts";
49
41
  import { parseQueryExpression } from "../lib/predicateParser.ts";
50
42
  import type {
51
43
  PagedQueryResponseMap,
52
44
  ResourceMap,
53
45
  ResourceType,
54
- Writable,
55
46
  } from "../types.ts";
56
47
  import type { GetParams, ProjectStorage, QueryParams } from "./abstract.ts";
57
48
  import { AbstractStorage } from "./abstract.ts";
49
+ import { StorageMap } from "./storage-map.ts";
58
50
 
59
51
  export class InMemoryStorage extends AbstractStorage {
60
52
  protected resources: {
@@ -65,7 +57,10 @@ export class InMemoryStorage extends AbstractStorage {
65
57
  [projectKey: string]: Project;
66
58
  } = {};
67
59
 
68
- addProject = (projectKey: string): Project => {
60
+ // Secondary index for custom objects: projectKey -> "container\0key" -> resource id
61
+ private _customObjectIndex: Map<string, Map<string, string>> = new Map();
62
+
63
+ async addProject(projectKey: string): Promise<Project> {
69
64
  if (!this.projects[projectKey]) {
70
65
  this.projects[projectKey] = {
71
66
  key: projectKey,
@@ -104,222 +99,221 @@ export class InMemoryStorage extends AbstractStorage {
104
99
  status: "Deactivated",
105
100
  },
106
101
  },
102
+ discounts: {
103
+ discountCombinationMode: "Stacking",
104
+ },
107
105
  version: 1,
108
106
  };
109
107
  }
110
108
  return this.projects[projectKey];
111
- };
109
+ }
112
110
 
113
- saveProject = (project: Project): Project => {
114
- this.projects[project.key] = project;
111
+ async saveProject(project: Project): Promise<Project> {
112
+ this.projects[project.key] = cloneObject(project);
115
113
  return project;
116
- };
117
-
118
- getProject = (projectKey: string): Project => this.addProject(projectKey);
119
-
120
- // Expand resolves a nested reference and injects the object in the given obj
121
- public expand = <T>(
122
- projectKey: string,
123
- obj: T,
124
- clause: undefined | string | string[],
125
- ): T => {
126
- if (!clause) return obj;
127
- const newObj = cloneObject(obj);
128
- if (Array.isArray(clause)) {
129
- for (const c of clause) {
130
- this._resolveResource(projectKey, newObj, c);
131
- }
132
- } else {
133
- this._resolveResource(projectKey, newObj, clause);
134
- }
135
- return newObj;
136
- };
137
-
138
- private _resolveResource = (projectKey: string, obj: any, expand: string) => {
139
- const params = parseExpandClause(expand);
140
-
141
- // 'lineItems[*].variant' on ShoppingList is an exception, these variants are not references
142
- if (params.index === "*") {
143
- const reference = obj[params.element];
144
- if (
145
- params.element === "lineItems" &&
146
- params.rest?.startsWith("variant") &&
147
- reference.every(
148
- (item: any) =>
149
- item.variant === undefined && item.variantId !== undefined,
150
- )
151
- ) {
152
- for (const item of reference as ShoppingListLineItem[]) {
153
- this._resolveShoppingListLineItemVariant(projectKey, item);
154
- }
155
- }
156
- }
114
+ }
157
115
 
158
- if (!params.index) {
159
- const reference = obj[params.element];
160
- if (reference === undefined) {
161
- return;
162
- }
163
- this._resolveReference(projectKey, reference, params.rest);
164
- } else if (params.index === "*") {
165
- const reference = obj[params.element];
166
- if (reference === undefined || !Array.isArray(reference)) return;
167
- for (const itemRef of reference as Writable<Reference>[]) {
168
- this._resolveReference(projectKey, itemRef, params.rest);
169
- }
170
- } else {
171
- const reference = obj[params.element][params.index];
172
- if (reference === undefined) return;
173
- this._resolveReference(projectKey, reference, params.rest);
174
- }
175
- };
116
+ async getProject(projectKey: string): Promise<Project> {
117
+ await this.addProject(projectKey);
118
+ return cloneObject(this.projects[projectKey]);
119
+ }
176
120
 
177
- private forProjectKey(projectKey: string): ProjectStorage {
178
- this.addProject(projectKey);
121
+ private async forProjectKey(projectKey: string): Promise<ProjectStorage> {
122
+ await this.addProject(projectKey);
179
123
 
180
124
  let projectStorage = this.resources[projectKey];
181
125
  if (!projectStorage) {
182
126
  projectStorage = this.resources[projectKey] = {
183
- "associate-role": new Map<string, AssociateRole>(),
184
- "attribute-group": new Map<string, AttributeGroup>(),
185
- "business-unit": new Map<string, BusinessUnit>(),
186
- cart: new Map<string, Cart>(),
187
- "cart-discount": new Map<string, CartDiscount>(),
188
- category: new Map<string, Category>(),
189
- channel: new Map<string, Channel>(),
190
- customer: new Map<string, Customer>(),
191
- "customer-group": new Map<string, CustomerGroup>(),
192
- "discount-code": new Map<string, DiscountCode>(),
193
- "discount-group": new Map<string, DiscountGroup>(),
194
- extension: new Map<string, Extension>(),
195
- "inventory-entry": new Map<string, InventoryEntry>(),
196
- "key-value-document": new Map<string, CustomObject>(),
197
- order: new Map<string, Order>(),
198
- "order-edit": new Map<string, any>(),
199
- payment: new Map<string, Payment>(),
200
- product: new Map<string, Product>(),
201
- quote: new Map<string, Quote>(),
202
- "quote-request": new Map<string, QuoteRequest>(),
203
- "product-discount": new Map<string, ProductDiscount>(),
204
- "product-selection": new Map<string, any>(),
205
- "product-type": new Map<string, ProductType>(),
206
- "product-projection": new Map<string, ProductProjection>(),
207
- "product-tailoring": new Map<string, ProductTailoring>(),
208
- "recurrence-policy": new Map<string, RecurrencePolicy>(),
209
- "recurring-order": new Map<string, RecurringOrder>(),
210
- review: new Map<string, any>(),
211
- "shipping-method": new Map<string, ShippingMethod>(),
212
- "staged-quote": new Map<string, StagedQuote>(),
213
- state: new Map<string, State>(),
214
- store: new Map<string, Store>(),
215
- "shopping-list": new Map<string, ShoppingList>(),
216
- "standalone-price": new Map<string, any>(),
217
- subscription: new Map<string, Subscription>(),
218
- "tax-category": new Map<string, TaxCategory>(),
219
- type: new Map<string, Type>(),
220
- zone: new Map<string, Zone>(),
127
+ "associate-role": new StorageMap<string, AssociateRole>(),
128
+ "attribute-group": new StorageMap<string, AttributeGroup>(),
129
+ "business-unit": new StorageMap<string, BusinessUnit>(),
130
+ cart: new StorageMap<string, Cart>(),
131
+ "cart-discount": new StorageMap<string, CartDiscount>(),
132
+ category: new StorageMap<string, Category>(),
133
+ channel: new StorageMap<string, Channel>(),
134
+ customer: new StorageMap<string, Customer>(),
135
+ "customer-group": new StorageMap<string, CustomerGroup>(),
136
+ "discount-code": new StorageMap<string, DiscountCode>(),
137
+ "discount-group": new StorageMap<string, DiscountGroup>(),
138
+ extension: new StorageMap<string, Extension>(),
139
+ "inventory-entry": new StorageMap<string, InventoryEntry>(),
140
+ "key-value-document": new StorageMap<string, CustomObject>(),
141
+ order: new StorageMap<string, Order>(),
142
+ "order-edit": new StorageMap<string, any>(),
143
+ payment: new StorageMap<string, Payment>(),
144
+ product: new StorageMap<string, Product>(),
145
+ quote: new StorageMap<string, Quote>(),
146
+ "quote-request": new StorageMap<string, QuoteRequest>(),
147
+ "product-discount": new StorageMap<string, ProductDiscount>(),
148
+ "product-selection": new StorageMap<string, any>(),
149
+ "product-type": new StorageMap<string, ProductType>(),
150
+ "product-projection": new StorageMap<string, ProductProjection>(),
151
+ "product-tailoring": new StorageMap<string, ProductTailoring>(),
152
+ "recurrence-policy": new StorageMap<string, RecurrencePolicy>(),
153
+ "recurring-order": new StorageMap<string, RecurringOrder>(),
154
+ review: new StorageMap<string, any>(),
155
+ "shipping-method": new StorageMap<string, ShippingMethod>(),
156
+ "staged-quote": new StorageMap<string, StagedQuote>(),
157
+ state: new StorageMap<string, State>(),
158
+ store: new StorageMap<string, Store>(),
159
+ "shopping-list": new StorageMap<string, ShoppingList>(),
160
+ "standalone-price": new StorageMap<string, any>(),
161
+ subscription: new StorageMap<string, Subscription>(),
162
+ "tax-category": new StorageMap<string, TaxCategory>(),
163
+ type: new StorageMap<string, Type>(),
164
+ zone: new StorageMap<string, Zone>(),
221
165
  };
222
166
  }
223
167
  return projectStorage;
224
168
  }
225
169
 
226
- clear() {
170
+ async clear(): Promise<void> {
227
171
  for (const [, projectStorage] of Object.entries(this.resources)) {
228
172
  for (const [, value] of Object.entries(projectStorage)) {
229
173
  value?.clear();
230
174
  }
231
175
  }
176
+ this._customObjectIndex.clear();
232
177
  }
233
178
 
234
- all<RT extends ResourceType>(
179
+ async all<RT extends ResourceType>(
235
180
  projectKey: string,
236
181
  typeId: RT,
237
- ): ResourceMap[RT][] {
238
- const store = this.forProjectKey(projectKey)[typeId];
182
+ ): Promise<ResourceMap[RT][]> {
183
+ const projectStorage = await this.forProjectKey(projectKey);
184
+ const store = projectStorage[typeId];
239
185
  if (store) {
240
- return Array.from(store.values()).map(cloneObject) as ResourceMap[RT][];
186
+ // StorageMap.values() already returns cloned values
187
+ return Array.from(store.values()) as ResourceMap[RT][];
241
188
  }
242
189
  return [];
243
190
  }
244
191
 
245
- add<RT extends ResourceType>(
192
+ async count(projectKey: string, typeId: ResourceType): Promise<number> {
193
+ const projectStorage = await this.forProjectKey(projectKey);
194
+ const store = projectStorage[typeId];
195
+ return store ? store.size : 0;
196
+ }
197
+
198
+ async add<RT extends ResourceType>(
246
199
  projectKey: string,
247
200
  typeId: RT,
248
201
  obj: ResourceMap[RT],
249
202
  params: GetParams = {},
250
- ): ResourceMap[RT] {
251
- const store = this.forProjectKey(projectKey);
203
+ ): Promise<ResourceMap[RT]> {
204
+ const store = await this.forProjectKey(projectKey);
205
+ // StorageMap.set() clones the value before storing
252
206
  store[typeId]?.set(obj.id, obj);
253
207
 
254
- const resource = this.get(projectKey, typeId, obj.id, params);
255
- assert(
256
- resource,
257
- `resource of type ${typeId} with id ${obj.id} not created`,
258
- );
259
- return cloneObject(resource);
208
+ // Maintain secondary index for custom objects
209
+ if (typeId === "key-value-document") {
210
+ const co = obj as unknown as CustomObject;
211
+ let projectIndex = this._customObjectIndex.get(projectKey);
212
+ if (!projectIndex) {
213
+ projectIndex = new Map();
214
+ this._customObjectIndex.set(projectKey, projectIndex);
215
+ }
216
+ projectIndex.set(`${co.container}\0${co.key}`, co.id);
217
+ }
218
+
219
+ // StorageMap.get() returns a clone, so we get a fresh copy for expand
220
+ const clone = store[typeId]?.get(obj.id) as ResourceMap[RT];
221
+ return this.expand(projectKey, clone, params.expand);
260
222
  }
261
223
 
262
- get<RT extends ResourceType>(
224
+ async get<RT extends ResourceType>(
263
225
  projectKey: string,
264
226
  typeId: RT,
265
227
  id: string,
266
228
  params: GetParams = {},
267
- ): ResourceMap[RT] | null {
268
- const resource = this.forProjectKey(projectKey)[typeId]?.get(id);
229
+ ): Promise<ResourceMap[RT] | null> {
230
+ const projectStorage = await this.forProjectKey(projectKey);
231
+ // StorageMap.get() already returns a clone
232
+ const resource = projectStorage[typeId]?.get(id);
269
233
  if (resource) {
270
- const clone = cloneObject(resource);
271
- return this.expand(projectKey, clone, params.expand) as ResourceMap[RT];
234
+ const expanded = await this.expand(projectKey, resource, params.expand);
235
+ return expanded as ResourceMap[RT];
272
236
  }
273
237
  return null;
274
238
  }
275
239
 
276
- getByKey<RT extends ResourceType>(
240
+ async getByKey<RT extends ResourceType>(
277
241
  projectKey: string,
278
242
  typeId: RT,
279
243
  key: string,
280
244
  params: GetParams = {},
281
- ): ResourceMap[RT] | null {
282
- const store = this.forProjectKey(projectKey);
283
- const resourceStore = store[typeId];
245
+ ): Promise<ResourceMap[RT] | null> {
246
+ const store = await this.forProjectKey(projectKey);
284
247
  if (!store) {
285
248
  throw new Error("No type");
286
249
  }
250
+ const resourceStore = store[typeId];
287
251
 
252
+ // StorageMap.values() already returns cloned values
288
253
  const resources: any[] = Array.from(resourceStore.values());
289
254
  const resource = resources.find((e) => e.key === key);
290
255
  if (resource) {
291
- const clone = cloneObject(resource);
292
- return this.expand(projectKey, clone, params.expand) as ResourceMap[RT];
256
+ const expanded = await this.expand(projectKey, resource, params.expand);
257
+ return expanded as ResourceMap[RT];
293
258
  }
294
259
  return null;
295
260
  }
296
261
 
297
- delete<RT extends ResourceType>(
262
+ async delete<RT extends ResourceType>(
298
263
  projectKey: string,
299
264
  typeId: RT,
300
265
  id: string,
301
266
  params: GetParams = {},
302
- ): ResourceMap[RT] | null {
303
- const resource = this.get(projectKey, typeId, id);
267
+ ): Promise<ResourceMap[RT] | null> {
268
+ const resource = await this.get(projectKey, typeId, id);
304
269
 
305
270
  if (resource) {
306
- this.forProjectKey(projectKey)[typeId]?.delete(id);
271
+ const projectStorage = await this.forProjectKey(projectKey);
272
+ projectStorage[typeId]?.delete(id);
273
+
274
+ // Remove from secondary index for custom objects
275
+ if (typeId === "key-value-document") {
276
+ const co = resource as unknown as CustomObject;
277
+ this._customObjectIndex
278
+ .get(projectKey)
279
+ ?.delete(`${co.container}\0${co.key}`);
280
+ }
281
+
307
282
  return this.expand(projectKey, resource, params.expand);
308
283
  }
309
284
  return resource;
310
285
  }
311
286
 
312
- query<RT extends ResourceType>(
287
+ async getByContainerAndKey(
288
+ projectKey: string,
289
+ container: string,
290
+ key: string,
291
+ ): Promise<CustomObject | null> {
292
+ const projectIndex = this._customObjectIndex.get(projectKey);
293
+ if (!projectIndex) {
294
+ return null;
295
+ }
296
+ const id = projectIndex.get(`${container}\0${key}`);
297
+ if (!id) {
298
+ return null;
299
+ }
300
+ const resource = await this.get(projectKey, "key-value-document", id);
301
+ return resource as CustomObject | null;
302
+ }
303
+
304
+ async query<RT extends ResourceType>(
313
305
  projectKey: string,
314
306
  typeId: RT,
315
307
  params: QueryParams,
316
- ): PagedQueryResponseMap[RT] {
317
- const store = this.forProjectKey(projectKey)[typeId];
308
+ ): Promise<PagedQueryResponseMap[RT]> {
309
+ const projectStorage = await this.forProjectKey(projectKey);
310
+ const store = projectStorage[typeId];
318
311
  if (!store) {
319
312
  throw new Error("No type");
320
313
  }
321
314
 
322
- let resources = this.all<RT>(projectKey, typeId);
315
+ // all() already returns cloned values via StorageMap
316
+ let resources = await this.all<RT>(projectKey, typeId);
323
317
 
324
318
  // Apply predicates
325
319
  if (params.where) {
@@ -355,157 +349,20 @@ export class InMemoryStorage extends AbstractStorage {
355
349
 
356
350
  // Expand the resources
357
351
  if (params.expand !== undefined) {
358
- resources = resources.map((resource) =>
359
- this.expand(projectKey, resource, params.expand),
352
+ resources = await Promise.all(
353
+ resources.map((resource) =>
354
+ this.expand(projectKey, resource, params.expand),
355
+ ),
360
356
  );
361
357
  }
362
358
 
363
359
  return {
364
- count: totalResources,
365
- total: resources.length,
366
- offset: offset,
367
- limit: limit,
368
- results: resources.map(cloneObject),
369
- } as PagedQueryResponseMap[RT];
370
- }
371
-
372
- search(
373
- projectKey: string,
374
- typeId: ResourceType,
375
- params: QueryParams,
376
- ): PagedQueryResponse {
377
- let resources = this.all(projectKey, typeId);
378
-
379
- // Apply predicates
380
- if (params.where) {
381
- try {
382
- const filterFunc = parseQueryExpression(params.where);
383
- resources = resources.filter((resource) => filterFunc(resource, {}));
384
- } catch (err) {
385
- throw new CommercetoolsError<InvalidInputError>(
386
- {
387
- code: "InvalidInput",
388
- message: (err as any).message,
389
- },
390
- 400,
391
- );
392
- }
393
- }
394
-
395
- // Get the total before slicing the array
396
- const totalResources = resources.length;
397
-
398
- // Apply offset, limit
399
- const offset = params.offset || 0;
400
- const limit = params.limit || 20;
401
- resources = resources.slice(offset, offset + limit);
402
-
403
- // Expand the resources
404
- if (params.expand !== undefined) {
405
- resources = resources.map((resource) =>
406
- this.expand(projectKey, resource, params.expand),
407
- );
408
- }
409
-
410
- return {
411
- count: totalResources,
412
- total: resources.length,
360
+ count: resources.length,
361
+ total: totalResources,
413
362
  offset: offset,
414
363
  limit: limit,
364
+ // Resources are already clones from StorageMap
415
365
  results: resources,
416
- };
417
- }
418
-
419
- getByResourceIdentifier<RT extends ResourceType>(
420
- projectKey: string,
421
- identifier: ResourceIdentifier,
422
- ): ResourceMap[RT] {
423
- if (identifier.id) {
424
- const resource = this.get(projectKey, identifier.typeId, identifier.id);
425
- if (resource) {
426
- return resource as ResourceMap[RT];
427
- }
428
-
429
- throw new CommercetoolsError<ReferencedResourceNotFoundError>({
430
- code: "ReferencedResourceNotFound",
431
- message: `The referenced object of type '${identifier.typeId}' with id '${identifier.id}' was not found. It either doesn't exist, or it can't be accessed from this endpoint (e.g., if the endpoint filters by store or customer account).`,
432
- typeId: identifier.typeId,
433
- id: identifier.id,
434
- });
435
- }
436
-
437
- if (identifier.key) {
438
- const resource = this.getByKey(
439
- projectKey,
440
- identifier.typeId,
441
- identifier.key,
442
- );
443
- if (resource) {
444
- return resource as ResourceMap[RT];
445
- }
446
-
447
- throw new CommercetoolsError<ReferencedResourceNotFoundError>({
448
- code: "ReferencedResourceNotFound",
449
- message: `The referenced object of type '${identifier.typeId}' with key '${identifier.key}' was not found. It either doesn't exist, or it can't be accessed from this endpoint (e.g., if the endpoint filters by store or customer account).`,
450
- typeId: identifier.typeId,
451
- key: identifier.key,
452
- });
453
- }
454
- throw new CommercetoolsError<InvalidJsonInputError>({
455
- code: "InvalidJsonInput",
456
- message: "Request body does not contain valid JSON.",
457
- detailedErrorMessage: "ResourceIdentifier requires an 'id' xor a 'key'",
458
- });
459
- }
460
-
461
- private _resolveReference(
462
- projectKey: string,
463
- reference: any,
464
- expand: string | undefined,
465
- ) {
466
- if (reference === undefined) return;
467
-
468
- if (
469
- reference.typeId !== undefined &&
470
- (reference.id !== undefined || reference.key !== undefined)
471
- ) {
472
- // First check if the object is already resolved. This is the case when
473
- // the complete resource is pushed via the .add() method.
474
- if (!reference.obj) {
475
- reference.obj = this.getByResourceIdentifier(projectKey, {
476
- typeId: reference.typeId,
477
- id: reference.id,
478
- key: reference.key,
479
- } as ResourceIdentifier);
480
- }
481
- if (expand) {
482
- this._resolveResource(projectKey, reference.obj, expand);
483
- }
484
- } else {
485
- if (expand) {
486
- this._resolveResource(projectKey, reference, expand);
487
- }
488
- }
489
- }
490
-
491
- private _resolveShoppingListLineItemVariant(
492
- projectKey: string,
493
- lineItem: ShoppingListLineItem,
494
- ) {
495
- const product = this.getByResourceIdentifier(projectKey, {
496
- typeId: "product",
497
- id: lineItem.productId,
498
- }) as Product | undefined;
499
-
500
- if (!product) {
501
- return;
502
- }
503
-
504
- const variant = [
505
- product.masterData.current.masterVariant,
506
- ...product.masterData.current.variants,
507
- ].find((e) => e.id === lineItem.variantId);
508
- // @ts-expect-error
509
- lineItem.variant = variant;
366
+ } as PagedQueryResponseMap[RT];
510
367
  }
511
368
  }