@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.
- package/README.md +31 -8
- package/dist/abstract-BKFcva6S.mjs +1044 -0
- package/dist/abstract-BKFcva6S.mjs.map +1 -0
- package/dist/config-BcNSzPZz.d.mts +1718 -0
- package/dist/index.d.mts +50 -1633
- package/dist/index.mjs +3769 -2653
- package/dist/index.mjs.map +1 -1
- package/dist/storage/sqlite.d.mts +59 -0
- package/dist/storage/sqlite.mjs +234 -0
- package/dist/storage/sqlite.mjs.map +1 -0
- package/package.json +26 -29
- package/src/ctMock.ts +125 -136
- package/src/helpers.ts +14 -6
- package/src/index.ts +5 -0
- package/src/lib/masking.ts +4 -5
- package/src/lib/product-review-statistics.test.ts +257 -294
- package/src/lib/review-statistics.ts +17 -4
- package/src/oauth/helpers.ts +7 -4
- package/src/oauth/server.test.ts +102 -62
- package/src/oauth/server.ts +215 -213
- package/src/oauth/store.ts +20 -6
- package/src/orderSearch.ts +3 -3
- package/src/product-projection-search.ts +38 -20
- package/src/product-search-availability.test.ts +31 -52
- package/src/product-search.ts +19 -10
- package/src/projectAPI.ts +6 -22
- package/src/repositories/abstract.ts +182 -48
- package/src/repositories/as-associate.test.ts +19 -19
- package/src/repositories/associate-role.ts +12 -23
- package/src/repositories/attribute-group.test.ts +23 -23
- package/src/repositories/attribute-group.ts +6 -4
- package/src/repositories/business-unit.test.ts +63 -57
- package/src/repositories/business-unit.ts +107 -55
- package/src/repositories/cart/actions.ts +96 -65
- package/src/repositories/cart/helpers.ts +15 -11
- package/src/repositories/cart/index.test.ts +136 -30
- package/src/repositories/cart/index.ts +76 -59
- package/src/repositories/cart-discount/actions.ts +12 -44
- package/src/repositories/cart-discount/index.ts +20 -8
- package/src/repositories/category/actions.ts +27 -27
- package/src/repositories/category/index.test.ts +13 -9
- package/src/repositories/category/index.ts +40 -23
- package/src/repositories/channel.test.ts +53 -51
- package/src/repositories/channel.ts +12 -22
- package/src/repositories/custom-object.ts +34 -25
- package/src/repositories/customer/actions.ts +47 -25
- package/src/repositories/customer/index.test.ts +11 -11
- package/src/repositories/customer/index.ts +65 -35
- package/src/repositories/customer-group.test.ts +44 -42
- package/src/repositories/customer-group.ts +12 -22
- package/src/repositories/discount-code/actions.ts +3 -19
- package/src/repositories/discount-code/index.ts +9 -4
- package/src/repositories/discount-group/index.ts +8 -3
- package/src/repositories/extension.test.ts +27 -27
- package/src/repositories/extension.ts +10 -5
- package/src/repositories/helpers.ts +126 -47
- package/src/repositories/inventory-entry/actions.ts +3 -24
- package/src/repositories/inventory-entry/index.ts +19 -11
- package/src/repositories/my-customer.ts +13 -12
- package/src/repositories/my-order.ts +5 -2
- package/src/repositories/order/actions.ts +84 -56
- package/src/repositories/order/index.test.ts +36 -31
- package/src/repositories/order/index.ts +83 -49
- package/src/repositories/order-edit.ts +8 -3
- package/src/repositories/payment/actions.ts +64 -44
- package/src/repositories/payment/helpers.ts +3 -3
- package/src/repositories/payment/index.ts +28 -12
- package/src/repositories/product/actions.ts +133 -98
- package/src/repositories/product/helpers.ts +29 -16
- package/src/repositories/product/index.ts +42 -25
- package/src/repositories/product-discount.ts +6 -4
- package/src/repositories/product-projection.ts +41 -21
- package/src/repositories/product-selection.ts +8 -15
- package/src/repositories/product-tailoring.ts +22 -3
- package/src/repositories/product-type.ts +45 -4
- package/src/repositories/project.ts +57 -13
- package/src/repositories/quote/actions.ts +5 -28
- package/src/repositories/quote/index.ts +29 -6
- package/src/repositories/quote-request/actions.ts +5 -28
- package/src/repositories/quote-request/index.test.ts +3 -3
- package/src/repositories/quote-request/index.ts +31 -11
- package/src/repositories/quote-staged/actions.ts +5 -28
- package/src/repositories/quote-staged/index.ts +22 -8
- package/src/repositories/recurrence-policy/index.ts +6 -4
- package/src/repositories/recurring-order/actions.ts +7 -32
- package/src/repositories/recurring-order/index.ts +8 -6
- package/src/repositories/review.test.ts +147 -142
- package/src/repositories/review.ts +31 -37
- package/src/repositories/shipping-method/actions.ts +11 -28
- package/src/repositories/shipping-method/index.ts +26 -15
- package/src/repositories/shopping-list/actions.ts +21 -31
- package/src/repositories/shopping-list/index.ts +44 -22
- package/src/repositories/standalone-price.ts +6 -4
- package/src/repositories/state.ts +15 -9
- package/src/repositories/store.ts +21 -32
- package/src/repositories/subscription.test.ts +22 -22
- package/src/repositories/subscription.ts +8 -3
- package/src/repositories/tax-category/index.ts +8 -3
- package/src/repositories/type/actions.ts +21 -3
- package/src/repositories/type/index.ts +5 -3
- package/src/repositories/zone.test.ts +112 -77
- package/src/repositories/zone.ts +5 -3
- package/src/schemas/generated/associate-role.ts +13 -0
- package/src/schemas/generated/attribute-group.ts +12 -0
- package/src/schemas/generated/business-unit.ts +38 -0
- package/src/schemas/generated/cart-discount.ts +33 -0
- package/src/schemas/generated/cart.ts +61 -0
- package/src/schemas/generated/category.ts +25 -0
- package/src/schemas/generated/channel.ts +21 -0
- package/src/schemas/generated/common.ts +1372 -0
- package/src/schemas/generated/custom-object.ts +11 -0
- package/src/schemas/generated/customer-group.ts +11 -0
- package/src/schemas/generated/customer.ts +47 -0
- package/src/schemas/generated/discount-code.ts +25 -0
- package/src/schemas/generated/discount-group.ts +13 -0
- package/src/schemas/generated/extension.ts +15 -0
- package/src/schemas/generated/index.ts +42 -0
- package/src/schemas/generated/inventory-entry.ts +20 -0
- package/src/schemas/generated/my-quote-request.ts +10 -0
- package/src/schemas/generated/order-edit.ts +18 -0
- package/src/schemas/generated/order-from-cart.ts +25 -0
- package/src/schemas/generated/payment.ts +30 -0
- package/src/schemas/generated/product-discount.ts +20 -0
- package/src/schemas/generated/product-selection.ts +18 -0
- package/src/schemas/generated/product-tailoring.ts +26 -0
- package/src/schemas/generated/product-type.ts +12 -0
- package/src/schemas/generated/product.ts +37 -0
- package/src/schemas/generated/quote-request.ts +19 -0
- package/src/schemas/generated/quote.ts +18 -0
- package/src/schemas/generated/recurrence-policy.ts +15 -0
- package/src/schemas/generated/recurring-order.ts +19 -0
- package/src/schemas/generated/review.ts +24 -0
- package/src/schemas/generated/shipping-method.ts +24 -0
- package/src/schemas/generated/shopping-list.ts +28 -0
- package/src/schemas/generated/staged-quote.ts +18 -0
- package/src/schemas/generated/standalone-price.ts +32 -0
- package/src/schemas/generated/state.ts +20 -0
- package/src/schemas/generated/store.ts +23 -0
- package/src/schemas/generated/subscription.ts +20 -0
- package/src/schemas/generated/tax-category.ts +12 -0
- package/src/schemas/generated/type.ts +17 -0
- package/src/schemas/generated/zone.ts +12 -0
- package/src/schemas/update-request.ts +3 -5
- package/src/server.ts +32 -4
- package/src/services/abstract.ts +207 -101
- package/src/services/as-associate-cart.test.ts +28 -36
- package/src/services/as-associate-cart.ts +15 -12
- package/src/services/as-associate-order.test.ts +33 -40
- package/src/services/as-associate-order.ts +15 -12
- package/src/services/as-associate-quote-request.ts +15 -12
- package/src/services/as-associate-shopping-list.test.ts +25 -35
- package/src/services/as-associate-shopping-list.ts +15 -12
- package/src/services/as-associate.test.ts +21 -15
- package/src/services/as-associate.ts +23 -22
- package/src/services/associate-roles.test.ts +16 -22
- package/src/services/associate-roles.ts +2 -2
- package/src/services/attribute-group.test.ts +40 -44
- package/src/services/attribute-group.ts +2 -2
- package/src/services/business-units.test.ts +227 -163
- package/src/services/business-units.ts +2 -2
- package/src/services/cart-discount.test.ts +253 -187
- package/src/services/cart-discount.ts +2 -2
- package/src/services/cart.test.ts +833 -832
- package/src/services/cart.ts +31 -12
- package/src/services/category.test.ts +208 -130
- package/src/services/category.ts +2 -2
- package/src/services/channel.test.ts +39 -44
- package/src/services/channel.ts +2 -2
- package/src/services/custom-object.test.ts +103 -79
- package/src/services/custom-object.ts +106 -38
- package/src/services/customer-group.test.ts +39 -44
- package/src/services/customer-group.ts +2 -2
- package/src/services/customer.test.ts +357 -292
- package/src/services/customer.ts +70 -23
- package/src/services/discount-code.test.ts +57 -68
- package/src/services/discount-code.ts +2 -2
- package/src/services/discount-group.test.ts +111 -134
- package/src/services/discount-group.ts +2 -2
- package/src/services/draft-validation.test.ts +255 -0
- package/src/services/extension.test.ts +39 -44
- package/src/services/extension.ts +2 -2
- package/src/services/inventory-entry.test.ts +106 -87
- package/src/services/inventory-entry.ts +2 -2
- package/src/services/my-business-unit.test.ts +82 -112
- package/src/services/my-business-unit.ts +25 -19
- package/src/services/my-cart.test.ts +46 -41
- package/src/services/my-cart.ts +32 -28
- package/src/services/my-customer.test.ts +153 -88
- package/src/services/my-customer.ts +130 -61
- package/src/services/my-order.ts +15 -12
- package/src/services/my-payment.test.ts +30 -24
- package/src/services/my-payment.ts +2 -2
- package/src/services/my-shopping-list.ts +2 -2
- package/src/services/order.test.ts +332 -276
- package/src/services/order.ts +45 -27
- package/src/services/payment.test.ts +31 -29
- package/src/services/payment.ts +2 -2
- package/src/services/product-discount.test.ts +39 -46
- package/src/services/product-discount.ts +2 -2
- package/src/services/product-projection.test.ts +176 -166
- package/src/services/product-projection.ts +31 -15
- package/src/services/product-selection.test.ts +17 -9
- package/src/services/product-selection.ts +2 -2
- package/src/services/product-type.test.ts +80 -21
- package/src/services/product-type.ts +2 -2
- package/src/services/product.test.ts +569 -534
- package/src/services/product.ts +14 -7
- package/src/services/project.test.ts +22 -12
- package/src/services/project.ts +28 -13
- package/src/services/quote-request.test.ts +36 -39
- package/src/services/quote-request.ts +2 -2
- package/src/services/quote-staged.ts +2 -2
- package/src/services/quote.ts +2 -2
- package/src/services/recurrence-policy.test.ts +114 -139
- package/src/services/recurrence-policy.ts +2 -2
- package/src/services/recurring-order.test.ts +149 -194
- package/src/services/recurring-order.ts +2 -2
- package/src/services/reviews.test.ts +127 -106
- package/src/services/reviews.ts +2 -2
- package/src/services/shipping-method.test.ts +96 -125
- package/src/services/shipping-method.ts +24 -12
- package/src/services/shopping-list.test.ts +183 -141
- package/src/services/shopping-list.ts +2 -2
- package/src/services/standalone-price.test.ts +60 -46
- package/src/services/standalone-price.ts +2 -2
- package/src/services/state.test.ts +20 -25
- package/src/services/state.ts +2 -2
- package/src/services/store.test.ts +26 -45
- package/src/services/store.ts +2 -2
- package/src/services/subscription.test.ts +39 -44
- package/src/services/subscription.ts +2 -2
- package/src/services/tax-category.test.ts +33 -36
- package/src/services/tax-category.ts +2 -2
- package/src/services/type.test.ts +45 -44
- package/src/services/type.ts +2 -2
- package/src/services/zone.test.ts +40 -44
- package/src/services/zone.ts +2 -2
- package/src/shipping.ts +41 -11
- package/src/storage/abstract.ts +248 -17
- package/src/storage/in-memory.ts +147 -290
- package/src/storage/sqlite.ts +429 -0
- package/src/storage/storage-map.ts +75 -0
- package/src/storage/storage.test-helpers.ts +97 -0
- package/src/storage/storage.test.ts +802 -0
- package/src/testing/associate-role.ts +28 -0
- package/src/testing/attribute-group.ts +27 -0
- package/src/testing/business-unit.ts +9 -8
- package/src/testing/cart-discount.ts +34 -0
- package/src/testing/cart.ts +20 -0
- package/src/testing/category.ts +25 -0
- package/src/testing/channel.ts +23 -0
- package/src/testing/custom-object.ts +27 -0
- package/src/testing/customer-group.ts +26 -0
- package/src/testing/customer.ts +36 -33
- package/src/testing/discount-code.ts +29 -0
- package/src/testing/discount-group.ts +27 -0
- package/src/testing/extension.ts +32 -0
- package/src/testing/index.ts +33 -0
- package/src/testing/inventory-entry.ts +26 -0
- package/src/testing/order.ts +27 -0
- package/src/testing/payment.ts +23 -0
- package/src/testing/product-discount.ts +33 -0
- package/src/testing/product-selection.ts +28 -0
- package/src/testing/product-type.ts +27 -0
- package/src/testing/product.ts +38 -0
- package/src/testing/quote-request.ts +29 -0
- package/src/testing/recurrence-policy.ts +33 -0
- package/src/testing/recurring-order.ts +32 -0
- package/src/testing/review.ts +24 -0
- package/src/testing/shipping-method.ts +31 -0
- package/src/testing/shopping-list.ts +25 -0
- package/src/testing/standalone-price.ts +31 -0
- package/src/testing/state.ts +21 -0
- package/src/testing/store.ts +26 -0
- package/src/testing/subscription.ts +38 -0
- package/src/testing/tax-category.ts +27 -0
- package/src/testing/type.ts +9 -6
- package/src/testing/zone.ts +22 -0
- package/src/validate.test.ts +122 -0
- package/src/validate.ts +78 -7
- package/src/.env +0 -0
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { isDeepStrictEqual } from "node:util";
|
|
2
2
|
import type {
|
|
3
3
|
BaseResource,
|
|
4
|
+
CustomFields,
|
|
5
|
+
FieldContainer,
|
|
4
6
|
InvalidInputError,
|
|
7
|
+
InvalidOperationError,
|
|
5
8
|
Project,
|
|
6
9
|
QueryParam,
|
|
7
10
|
ResourceNotFoundError,
|
|
11
|
+
TypeResourceIdentifier,
|
|
8
12
|
UpdateAction,
|
|
9
13
|
} from "@commercetools/platform-sdk";
|
|
14
|
+
import type { z } from "zod";
|
|
10
15
|
import type { Config } from "#src/config.ts";
|
|
11
16
|
import { CommercetoolsError } from "#src/exceptions.ts";
|
|
12
17
|
import { cloneObject } from "../helpers.ts";
|
|
@@ -18,6 +23,7 @@ import type {
|
|
|
18
23
|
Writable,
|
|
19
24
|
} from "./../types.ts";
|
|
20
25
|
import { checkConcurrentModification } from "./errors.ts";
|
|
26
|
+
import { createCustomFields } from "./helpers.ts";
|
|
21
27
|
|
|
22
28
|
export type QueryParams = {
|
|
23
29
|
expand?: string[];
|
|
@@ -36,6 +42,7 @@ export type GetParams = {
|
|
|
36
42
|
export type RepositoryContext = {
|
|
37
43
|
projectKey: string;
|
|
38
44
|
storeKey?: string;
|
|
45
|
+
clientId?: string;
|
|
39
46
|
};
|
|
40
47
|
|
|
41
48
|
export abstract class AbstractRepository<R extends BaseResource | Project> {
|
|
@@ -50,27 +57,36 @@ export abstract class AbstractRepository<R extends BaseResource | Project> {
|
|
|
50
57
|
this._storage = config.storage;
|
|
51
58
|
}
|
|
52
59
|
|
|
53
|
-
|
|
60
|
+
async saveNew({ projectKey }: RepositoryContext, resource: R): Promise<R> {
|
|
61
|
+
throw new Error("Not implemented");
|
|
62
|
+
}
|
|
54
63
|
|
|
55
|
-
|
|
64
|
+
async saveUpdate(
|
|
56
65
|
{ projectKey }: RepositoryContext,
|
|
57
66
|
version: number,
|
|
58
67
|
resource: R,
|
|
59
|
-
):
|
|
68
|
+
): Promise<R> {
|
|
69
|
+
throw new Error("Not implemented");
|
|
70
|
+
}
|
|
60
71
|
|
|
61
|
-
|
|
72
|
+
async postProcessResource(
|
|
73
|
+
context: RepositoryContext,
|
|
74
|
+
resource: any,
|
|
75
|
+
): Promise<any> {
|
|
76
|
+
throw new Error("Not implemented");
|
|
77
|
+
}
|
|
62
78
|
|
|
63
|
-
processUpdateActions(
|
|
79
|
+
async processUpdateActions(
|
|
64
80
|
context: RepositoryContext,
|
|
65
81
|
resource: R,
|
|
66
82
|
version: number,
|
|
67
83
|
actions: UpdateAction[],
|
|
68
|
-
): R {
|
|
84
|
+
): Promise<R> {
|
|
69
85
|
if (!this.actions) {
|
|
70
86
|
throw new Error("No actions defined");
|
|
71
87
|
}
|
|
72
88
|
|
|
73
|
-
const updatedResource = this.actions.apply(
|
|
89
|
+
const updatedResource = await this.actions.apply(
|
|
74
90
|
context,
|
|
75
91
|
resource,
|
|
76
92
|
version,
|
|
@@ -80,10 +96,10 @@ export abstract class AbstractRepository<R extends BaseResource | Project> {
|
|
|
80
96
|
// If all actions succeeded we write the new version
|
|
81
97
|
// to the storage.
|
|
82
98
|
if (resource.version !== updatedResource.version) {
|
|
83
|
-
this.saveUpdate(context, version, updatedResource);
|
|
99
|
+
await this.saveUpdate(context, version, updatedResource);
|
|
84
100
|
}
|
|
85
101
|
|
|
86
|
-
const result = this.postProcessResource(context, updatedResource);
|
|
102
|
+
const result = await this.postProcessResource(context, updatedResource);
|
|
87
103
|
if (!result) {
|
|
88
104
|
throw new Error("invalid post process action");
|
|
89
105
|
}
|
|
@@ -96,82 +112,120 @@ export abstract class AbstractResourceRepository<
|
|
|
96
112
|
> extends AbstractRepository<ResourceMap[T]> {
|
|
97
113
|
protected _typeId: T;
|
|
98
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Optional Zod schema for validating creation drafts.
|
|
117
|
+
* When set and strict mode is enabled, the service layer will
|
|
118
|
+
* validate incoming request bodies against this schema before
|
|
119
|
+
* passing them to create().
|
|
120
|
+
*/
|
|
121
|
+
draftSchema?: z.ZodType;
|
|
122
|
+
|
|
99
123
|
constructor(typeId: T, config: Config) {
|
|
100
124
|
super(config);
|
|
101
125
|
this._typeId = typeId;
|
|
102
126
|
}
|
|
103
127
|
|
|
104
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Whether strict validation is enabled.
|
|
130
|
+
*/
|
|
131
|
+
get strict(): boolean {
|
|
132
|
+
return this.config.strict;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
abstract create(
|
|
136
|
+
context: RepositoryContext,
|
|
137
|
+
draft: any,
|
|
138
|
+
): Promise<ResourceMap[T]>;
|
|
105
139
|
|
|
106
140
|
protected getTypeId(): T {
|
|
107
141
|
return this._typeId;
|
|
108
142
|
}
|
|
109
143
|
|
|
110
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Apply expand clauses to a resource without re-fetching from storage.
|
|
146
|
+
*/
|
|
147
|
+
async expand(
|
|
148
|
+
context: RepositoryContext,
|
|
149
|
+
resource: ResourceMap[T],
|
|
150
|
+
expand: string[] | undefined,
|
|
151
|
+
): Promise<ResourceMap[T]> {
|
|
152
|
+
if (!expand || expand.length === 0) {
|
|
153
|
+
return resource;
|
|
154
|
+
}
|
|
155
|
+
return this._storage.expand(context.projectKey, resource, expand);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async delete(
|
|
111
159
|
context: RepositoryContext,
|
|
112
160
|
id: string,
|
|
113
161
|
params: GetParams = {},
|
|
114
|
-
): ResourceMap[T] | null {
|
|
115
|
-
const resource = this._storage.delete(
|
|
162
|
+
): Promise<ResourceMap[T] | null> {
|
|
163
|
+
const resource = await this._storage.delete(
|
|
116
164
|
context.projectKey,
|
|
117
165
|
this.getTypeId(),
|
|
118
166
|
id,
|
|
119
167
|
params,
|
|
120
168
|
);
|
|
121
169
|
return resource
|
|
122
|
-
? this.postProcessResource(context, resource, params)
|
|
170
|
+
? await this.postProcessResource(context, resource, params)
|
|
123
171
|
: null;
|
|
124
172
|
}
|
|
125
173
|
|
|
126
|
-
get(
|
|
174
|
+
async get(
|
|
127
175
|
context: RepositoryContext,
|
|
128
176
|
id: string,
|
|
129
177
|
params: GetParams = {},
|
|
130
|
-
): ResourceMap[T] | null {
|
|
131
|
-
const resource = this._storage.get(
|
|
178
|
+
): Promise<ResourceMap[T] | null> {
|
|
179
|
+
const resource = await this._storage.get(
|
|
132
180
|
context.projectKey,
|
|
133
181
|
this.getTypeId(),
|
|
134
182
|
id,
|
|
135
183
|
params,
|
|
136
184
|
);
|
|
137
185
|
return resource
|
|
138
|
-
? this.postProcessResource(context, resource, params)
|
|
186
|
+
? await this.postProcessResource(context, resource, params)
|
|
139
187
|
: null;
|
|
140
188
|
}
|
|
141
189
|
|
|
142
|
-
getByKey(
|
|
190
|
+
async getByKey(
|
|
143
191
|
context: RepositoryContext,
|
|
144
192
|
key: string,
|
|
145
193
|
params: GetParams = {},
|
|
146
|
-
): ResourceMap[T] | null {
|
|
147
|
-
const resource = this._storage.getByKey(
|
|
194
|
+
): Promise<ResourceMap[T] | null> {
|
|
195
|
+
const resource = await this._storage.getByKey(
|
|
148
196
|
context.projectKey,
|
|
149
197
|
this.getTypeId(),
|
|
150
198
|
key,
|
|
151
199
|
params,
|
|
152
200
|
);
|
|
153
201
|
return resource
|
|
154
|
-
? this.postProcessResource(context, resource, params)
|
|
202
|
+
? await this.postProcessResource(context, resource, params)
|
|
155
203
|
: null;
|
|
156
204
|
}
|
|
157
205
|
|
|
158
|
-
postProcessResource(
|
|
206
|
+
async postProcessResource(
|
|
159
207
|
context: RepositoryContext,
|
|
160
208
|
resource: ResourceMap[T],
|
|
161
209
|
params?: GetParams,
|
|
162
|
-
): ResourceMap[T] {
|
|
210
|
+
): Promise<ResourceMap[T]> {
|
|
163
211
|
return resource;
|
|
164
212
|
}
|
|
165
213
|
|
|
166
|
-
query(context: RepositoryContext, params: QueryParams = {}) {
|
|
167
|
-
const result = this._storage.query(
|
|
168
|
-
|
|
169
|
-
|
|
214
|
+
async query(context: RepositoryContext, params: QueryParams = {}) {
|
|
215
|
+
const result = await this._storage.query(
|
|
216
|
+
context.projectKey,
|
|
217
|
+
this.getTypeId(),
|
|
218
|
+
{
|
|
219
|
+
...params,
|
|
220
|
+
},
|
|
221
|
+
);
|
|
170
222
|
|
|
171
|
-
const data =
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
223
|
+
const data = await Promise.all(
|
|
224
|
+
result.results.map((r) =>
|
|
225
|
+
this.postProcessResource(context, r as ResourceMap[T], {
|
|
226
|
+
expand: params.expand,
|
|
227
|
+
}),
|
|
228
|
+
),
|
|
175
229
|
);
|
|
176
230
|
return {
|
|
177
231
|
...result,
|
|
@@ -179,25 +233,25 @@ export abstract class AbstractResourceRepository<
|
|
|
179
233
|
};
|
|
180
234
|
}
|
|
181
235
|
|
|
182
|
-
saveNew(
|
|
236
|
+
async saveNew(
|
|
183
237
|
context: RepositoryContext,
|
|
184
238
|
resource: ShallowWritable<ResourceMap[T]>,
|
|
185
|
-
): ResourceMap[T] {
|
|
239
|
+
): Promise<ResourceMap[T]> {
|
|
186
240
|
resource.version = 1;
|
|
187
|
-
return this._storage.add(
|
|
241
|
+
return await this._storage.add(
|
|
188
242
|
context.projectKey,
|
|
189
243
|
this.getTypeId(),
|
|
190
244
|
resource as any,
|
|
191
245
|
);
|
|
192
246
|
}
|
|
193
247
|
|
|
194
|
-
saveUpdate(
|
|
248
|
+
async saveUpdate(
|
|
195
249
|
context: RepositoryContext,
|
|
196
250
|
version: number,
|
|
197
251
|
resource: ShallowWritable<ResourceMap[T]>,
|
|
198
|
-
) {
|
|
252
|
+
): Promise<ResourceMap[T]> {
|
|
199
253
|
// Check if the resource still exists.
|
|
200
|
-
const current = this._storage.get(
|
|
254
|
+
const current = await this._storage.get(
|
|
201
255
|
context.projectKey,
|
|
202
256
|
this.getTypeId(),
|
|
203
257
|
resource.id,
|
|
@@ -218,10 +272,18 @@ export abstract class AbstractResourceRepository<
|
|
|
218
272
|
throw new Error("Internal error: no changes to save");
|
|
219
273
|
}
|
|
220
274
|
resource.lastModifiedAt = new Date().toISOString();
|
|
275
|
+
(resource as any).lastModifiedBy = {
|
|
276
|
+
clientId: context.clientId ?? "",
|
|
277
|
+
isPlatformClient: false,
|
|
278
|
+
};
|
|
221
279
|
|
|
222
|
-
this._storage.add(
|
|
280
|
+
await this._storage.add(
|
|
281
|
+
context.projectKey,
|
|
282
|
+
this.getTypeId(),
|
|
283
|
+
resource as any,
|
|
284
|
+
);
|
|
223
285
|
|
|
224
|
-
return resource;
|
|
286
|
+
return resource as ResourceMap[T];
|
|
225
287
|
}
|
|
226
288
|
}
|
|
227
289
|
|
|
@@ -229,7 +291,7 @@ type UpdateActionHandlerMethod<A, T> = (
|
|
|
229
291
|
context: RepositoryContext,
|
|
230
292
|
resource: Writable<A>,
|
|
231
293
|
action: T,
|
|
232
|
-
) => void
|
|
294
|
+
) => void | Promise<void>;
|
|
233
295
|
|
|
234
296
|
export type UpdateHandlerInterface<
|
|
235
297
|
A extends BaseResource | Project,
|
|
@@ -239,19 +301,85 @@ export type UpdateHandlerInterface<
|
|
|
239
301
|
};
|
|
240
302
|
|
|
241
303
|
export class AbstractUpdateHandler {
|
|
242
|
-
|
|
304
|
+
_storage: AbstractStorage;
|
|
305
|
+
constructor(_storage: AbstractStorage) {
|
|
243
306
|
if (!_storage) {
|
|
244
307
|
throw new Error("No storage provided");
|
|
245
308
|
}
|
|
246
309
|
this._storage = _storage;
|
|
247
310
|
}
|
|
248
311
|
|
|
249
|
-
|
|
312
|
+
/**
|
|
313
|
+
* Shared implementation for setCustomField update actions.
|
|
314
|
+
*
|
|
315
|
+
* Throws InvalidOperation if the resource has no custom type set.
|
|
316
|
+
* When `value` is `null`, the field is removed; otherwise it is set.
|
|
317
|
+
*/
|
|
318
|
+
protected _setCustomFieldValues(
|
|
319
|
+
resource: { custom?: CustomFields },
|
|
320
|
+
{ name, value }: { name: string; value?: unknown },
|
|
321
|
+
): void {
|
|
322
|
+
if (!resource.custom) {
|
|
323
|
+
throw new CommercetoolsError<InvalidOperationError>(
|
|
324
|
+
{
|
|
325
|
+
code: "InvalidOperation",
|
|
326
|
+
message: "Resource has no custom type",
|
|
327
|
+
},
|
|
328
|
+
400,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
if (value === null) {
|
|
332
|
+
if (!(name in resource.custom.fields)) {
|
|
333
|
+
throw new CommercetoolsError<InvalidOperationError>(
|
|
334
|
+
{
|
|
335
|
+
code: "InvalidOperation",
|
|
336
|
+
message: `Cannot remove custom field ${name} because it does not exist.`,
|
|
337
|
+
},
|
|
338
|
+
400,
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
delete resource.custom.fields[name];
|
|
342
|
+
} else {
|
|
343
|
+
resource.custom.fields[name] = value;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Shared implementation for setCustomType update actions.
|
|
349
|
+
*
|
|
350
|
+
* When `type` is provided, resolves the type reference and sets the
|
|
351
|
+
* custom fields on the resource. When `type` is not provided, removes
|
|
352
|
+
* the custom fields entirely.
|
|
353
|
+
*/
|
|
354
|
+
protected async _setCustomType(
|
|
355
|
+
context: RepositoryContext,
|
|
356
|
+
resource: { custom?: CustomFields },
|
|
357
|
+
{
|
|
358
|
+
type,
|
|
359
|
+
fields,
|
|
360
|
+
}: { type?: TypeResourceIdentifier; fields?: FieldContainer },
|
|
361
|
+
): Promise<void> {
|
|
362
|
+
if (type) {
|
|
363
|
+
resource.custom = await createCustomFields(
|
|
364
|
+
{ type, fields },
|
|
365
|
+
context.projectKey,
|
|
366
|
+
this._storage,
|
|
367
|
+
);
|
|
368
|
+
} else {
|
|
369
|
+
resource.custom = undefined;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
async apply<R extends BaseResource | Project>(
|
|
250
374
|
context: RepositoryContext,
|
|
251
375
|
resource: R,
|
|
252
376
|
version: number,
|
|
253
377
|
actions: UpdateAction[],
|
|
254
|
-
): R {
|
|
378
|
+
): Promise<R> {
|
|
379
|
+
// We need a separate working copy because the caller (processUpdateActions)
|
|
380
|
+
// compares resource.version with updatedResource.version to detect changes.
|
|
381
|
+
// The resource parameter is already a clone from storage, but we still need
|
|
382
|
+
// two distinct references.
|
|
255
383
|
const updatedResource = cloneObject(resource) as ShallowWritable<R>;
|
|
256
384
|
const identifier = (resource as BaseResource).id
|
|
257
385
|
? (resource as BaseResource).id
|
|
@@ -277,13 +405,19 @@ export class AbstractUpdateHandler {
|
|
|
277
405
|
const updateFunc = this[action.action].bind(this);
|
|
278
406
|
|
|
279
407
|
if (!updateFunc) {
|
|
280
|
-
throw new
|
|
281
|
-
|
|
408
|
+
throw new CommercetoolsError<InvalidInputError>(
|
|
409
|
+
{
|
|
410
|
+
code: "InvalidInput",
|
|
411
|
+
message: `No mock implemented for update action ${action.action}`,
|
|
412
|
+
},
|
|
413
|
+
400,
|
|
282
414
|
);
|
|
283
415
|
}
|
|
284
416
|
|
|
285
|
-
|
|
286
|
-
|
|
417
|
+
// Snapshot the current state before applying the action so we can
|
|
418
|
+
// detect whether it actually changed anything.
|
|
419
|
+
const beforeUpdate = cloneObject(updatedResource);
|
|
420
|
+
await updateFunc(context, updatedResource, action);
|
|
287
421
|
|
|
288
422
|
// Check if the object is updated. We need to increase the version of
|
|
289
423
|
// an object per action which does an actual modification.
|
|
@@ -14,7 +14,7 @@ describe("As Associate Repositories", () => {
|
|
|
14
14
|
const storage = new InMemoryStorage();
|
|
15
15
|
const config: Config = { storage, strict: false };
|
|
16
16
|
|
|
17
|
-
test("AsAssociateCartRepository can create and retrieve carts", () => {
|
|
17
|
+
test("AsAssociateCartRepository can create and retrieve carts", async () => {
|
|
18
18
|
const repository = new AsAssociateCartRepository(config);
|
|
19
19
|
const ctx = { projectKey: "test-project" };
|
|
20
20
|
|
|
@@ -26,23 +26,23 @@ describe("As Associate Repositories", () => {
|
|
|
26
26
|
taxCalculationMode: "UnitPriceLevel" as const,
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
const cart = repository.create(ctx, cartDraft);
|
|
29
|
+
const cart = await repository.create(ctx, cartDraft);
|
|
30
30
|
expect(cart.id).toBeDefined();
|
|
31
31
|
expect(cart.version).toBe(1);
|
|
32
32
|
expect(cart.totalPrice.currencyCode).toBe("EUR");
|
|
33
33
|
|
|
34
34
|
// Test query
|
|
35
|
-
const result = repository.query(ctx);
|
|
35
|
+
const result = await repository.query(ctx);
|
|
36
36
|
expect(result.count).toBe(1);
|
|
37
37
|
expect(result.results[0].id).toBe(cart.id);
|
|
38
38
|
|
|
39
39
|
// Test get
|
|
40
|
-
const retrieved = repository.get(ctx, cart.id);
|
|
40
|
+
const retrieved = await repository.get(ctx, cart.id);
|
|
41
41
|
expect(retrieved).toBeDefined();
|
|
42
42
|
expect(retrieved?.id).toBe(cart.id);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
test("AsAssociateOrderRepository can create and retrieve orders", () => {
|
|
45
|
+
test("AsAssociateOrderRepository can create and retrieve orders", async () => {
|
|
46
46
|
const repository = new AsAssociateOrderRepository(config);
|
|
47
47
|
const ctx = { projectKey: "test-project" };
|
|
48
48
|
|
|
@@ -55,7 +55,7 @@ describe("As Associate Repositories", () => {
|
|
|
55
55
|
taxRoundingMode: "HalfEven" as const,
|
|
56
56
|
taxCalculationMode: "UnitPriceLevel" as const,
|
|
57
57
|
};
|
|
58
|
-
const cart = cartRepository.create(ctx, cartDraft);
|
|
58
|
+
const cart = await cartRepository.create(ctx, cartDraft);
|
|
59
59
|
|
|
60
60
|
const orderDraft = {
|
|
61
61
|
cart: {
|
|
@@ -65,29 +65,29 @@ describe("As Associate Repositories", () => {
|
|
|
65
65
|
version: cart.version,
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
-
const order = repository.create(ctx, orderDraft);
|
|
68
|
+
const order = await repository.create(ctx, orderDraft);
|
|
69
69
|
expect(order.id).toBeDefined();
|
|
70
70
|
expect(order.version).toBe(1);
|
|
71
71
|
expect(order.cart?.id).toBe(cart.id);
|
|
72
72
|
|
|
73
73
|
// Test query
|
|
74
|
-
const result = repository.query(ctx);
|
|
74
|
+
const result = await repository.query(ctx);
|
|
75
75
|
expect(result.count).toBe(1);
|
|
76
76
|
expect(result.results[0].id).toBe(order.id);
|
|
77
77
|
|
|
78
78
|
// Test get
|
|
79
|
-
const retrieved = repository.get(ctx, order.id);
|
|
79
|
+
const retrieved = await repository.get(ctx, order.id);
|
|
80
80
|
expect(retrieved).toBeDefined();
|
|
81
81
|
expect(retrieved?.id).toBe(order.id);
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
test("AsAssociateQuoteRequestRepository can create and retrieve quote requests", () => {
|
|
84
|
+
test("AsAssociateQuoteRequestRepository can create and retrieve quote requests", async () => {
|
|
85
85
|
const repository = new AsAssociateQuoteRequestRepository(config);
|
|
86
86
|
const ctx = { projectKey: "test-project" };
|
|
87
87
|
|
|
88
88
|
// Create a customer using the customer repository
|
|
89
89
|
const customerRepository = new CustomerRepository(config);
|
|
90
|
-
const customer = customerRepository.create(ctx, {
|
|
90
|
+
const customer = await customerRepository.create(ctx, {
|
|
91
91
|
email: "test@example.com",
|
|
92
92
|
password: "password123",
|
|
93
93
|
firstName: "John",
|
|
@@ -100,7 +100,7 @@ describe("As Associate Repositories", () => {
|
|
|
100
100
|
currency: "EUR",
|
|
101
101
|
customerId: customer.id,
|
|
102
102
|
};
|
|
103
|
-
const cart = cartRepository.create(ctx, cartDraft);
|
|
103
|
+
const cart = await cartRepository.create(ctx, cartDraft);
|
|
104
104
|
|
|
105
105
|
const quoteRequestDraft = {
|
|
106
106
|
cart: {
|
|
@@ -110,23 +110,23 @@ describe("As Associate Repositories", () => {
|
|
|
110
110
|
cartVersion: cart.version,
|
|
111
111
|
};
|
|
112
112
|
|
|
113
|
-
const quoteRequest = repository.create(ctx, quoteRequestDraft);
|
|
113
|
+
const quoteRequest = await repository.create(ctx, quoteRequestDraft);
|
|
114
114
|
expect(quoteRequest.id).toBeDefined();
|
|
115
115
|
expect(quoteRequest.version).toBe(1);
|
|
116
116
|
expect(quoteRequest.cart?.id).toBe(cart.id);
|
|
117
117
|
|
|
118
118
|
// Test query
|
|
119
|
-
const result = repository.query(ctx);
|
|
119
|
+
const result = await repository.query(ctx);
|
|
120
120
|
expect(result.count).toBe(1);
|
|
121
121
|
expect(result.results[0].id).toBe(quoteRequest.id);
|
|
122
122
|
|
|
123
123
|
// Test get
|
|
124
|
-
const retrieved = repository.get(ctx, quoteRequest.id);
|
|
124
|
+
const retrieved = await repository.get(ctx, quoteRequest.id);
|
|
125
125
|
expect(retrieved).toBeDefined();
|
|
126
126
|
expect(retrieved?.id).toBe(quoteRequest.id);
|
|
127
127
|
});
|
|
128
128
|
|
|
129
|
-
test("AsAssociateShoppingListRepository can create and retrieve shopping lists", () => {
|
|
129
|
+
test("AsAssociateShoppingListRepository can create and retrieve shopping lists", async () => {
|
|
130
130
|
const repository = new AsAssociateShoppingListRepository(config);
|
|
131
131
|
const ctx = { projectKey: "test-project" };
|
|
132
132
|
|
|
@@ -134,17 +134,17 @@ describe("As Associate Repositories", () => {
|
|
|
134
134
|
name: { "en-US": "My Shopping List" },
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
-
const shoppingList = repository.create(ctx, shoppingListDraft);
|
|
137
|
+
const shoppingList = await repository.create(ctx, shoppingListDraft);
|
|
138
138
|
expect(shoppingList.id).toBeDefined();
|
|
139
139
|
expect(shoppingList.version).toBe(1);
|
|
140
140
|
|
|
141
141
|
// Test query
|
|
142
|
-
const result = repository.query(ctx);
|
|
142
|
+
const result = await repository.query(ctx);
|
|
143
143
|
expect(result.count).toBe(1);
|
|
144
144
|
expect(result.results[0].id).toBe(shoppingList.id);
|
|
145
145
|
|
|
146
146
|
// Test get
|
|
147
|
-
const retrieved = repository.get(ctx, shoppingList.id);
|
|
147
|
+
const retrieved = await repository.get(ctx, shoppingList.id);
|
|
148
148
|
expect(retrieved).toBeDefined();
|
|
149
149
|
expect(retrieved?.id).toBe(shoppingList.id);
|
|
150
150
|
});
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
AssociateRoleUpdateAction,
|
|
12
12
|
} from "@commercetools/platform-sdk";
|
|
13
13
|
import type { Config } from "#src/config.ts";
|
|
14
|
+
import { AssociateRoleDraftSchema } from "#src/schemas/generated/associate-role.ts";
|
|
14
15
|
import { getBaseResourceProperties } from "../helpers.ts";
|
|
15
16
|
import type { Writable } from "../types.ts";
|
|
16
17
|
import type { UpdateHandlerInterface } from "./abstract.ts";
|
|
@@ -25,23 +26,27 @@ export class AssociateRoleRepository extends AbstractResourceRepository<"associa
|
|
|
25
26
|
constructor(config: Config) {
|
|
26
27
|
super("associate-role", config);
|
|
27
28
|
this.actions = new AssociateRoleUpdateHandler(this._storage);
|
|
29
|
+
this.draftSchema = AssociateRoleDraftSchema;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
create(
|
|
32
|
+
async create(
|
|
33
|
+
context: RepositoryContext,
|
|
34
|
+
draft: AssociateRoleDraft,
|
|
35
|
+
): Promise<AssociateRole> {
|
|
31
36
|
const resource: AssociateRole = {
|
|
32
|
-
...getBaseResourceProperties(),
|
|
37
|
+
...getBaseResourceProperties(context.clientId),
|
|
33
38
|
key: draft.key,
|
|
34
39
|
name: draft.name,
|
|
35
40
|
buyerAssignable: draft.buyerAssignable || false,
|
|
36
41
|
permissions: draft.permissions || [],
|
|
37
|
-
custom: createCustomFields(
|
|
42
|
+
custom: await createCustomFields(
|
|
38
43
|
draft.custom,
|
|
39
44
|
context.projectKey,
|
|
40
45
|
this._storage,
|
|
41
46
|
),
|
|
42
47
|
};
|
|
43
48
|
|
|
44
|
-
return this.saveNew(context, resource);
|
|
49
|
+
return await this.saveNew(context, resource);
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
|
|
@@ -95,31 +100,15 @@ class AssociateRoleUpdateHandler
|
|
|
95
100
|
resource: Writable<AssociateRole>,
|
|
96
101
|
{ name, value }: AssociateRoleSetCustomFieldAction,
|
|
97
102
|
) {
|
|
98
|
-
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (value === null) {
|
|
103
|
-
delete resource.custom.fields[name];
|
|
104
|
-
} else {
|
|
105
|
-
resource.custom.fields[name] = value;
|
|
106
|
-
}
|
|
103
|
+
this._setCustomFieldValues(resource, { name, value });
|
|
107
104
|
}
|
|
108
105
|
|
|
109
|
-
setCustomType(
|
|
106
|
+
async setCustomType(
|
|
110
107
|
context: RepositoryContext,
|
|
111
108
|
resource: Writable<AssociateRole>,
|
|
112
109
|
{ type, fields }: AssociateRoleSetCustomTypeAction,
|
|
113
110
|
) {
|
|
114
|
-
|
|
115
|
-
resource.custom = createCustomFields(
|
|
116
|
-
{ type, fields },
|
|
117
|
-
context.projectKey,
|
|
118
|
-
this._storage,
|
|
119
|
-
);
|
|
120
|
-
} else {
|
|
121
|
-
resource.custom = undefined;
|
|
122
|
-
}
|
|
111
|
+
await this._setCustomType(context, resource, { type, fields });
|
|
123
112
|
}
|
|
124
113
|
|
|
125
114
|
setName(
|