@labdigital/commercetools-mock 0.9.1 → 0.10.1
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 +8 -0
- package/dist/index.d.ts +354 -188
- package/dist/index.global.js +2346 -2209
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +1968 -1829
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2171 -2032
- package/dist/index.mjs.map +1 -1
- package/package.json +30 -21
- package/src/constants.ts +4 -2
- package/src/ctMock.ts +27 -86
- package/src/helpers.ts +10 -11
- package/src/index.test.ts +1 -1
- package/src/lib/haversine.ts +2 -2
- package/src/lib/masking.ts +3 -1
- package/src/lib/predicateParser.ts +93 -92
- package/src/lib/projectionSearchFilter.test.ts +28 -36
- package/src/lib/projectionSearchFilter.ts +88 -103
- package/src/oauth/store.ts +3 -3
- package/src/priceSelector.test.ts +16 -35
- package/src/priceSelector.ts +6 -9
- package/src/product-projection-search.ts +49 -57
- package/src/projectAPI.test.ts +7 -0
- package/src/projectAPI.ts +17 -22
- package/src/repositories/abstract.ts +102 -51
- package/src/repositories/cart-discount.ts +4 -5
- package/src/repositories/cart.ts +56 -46
- package/src/repositories/category.ts +23 -26
- package/src/repositories/channel.ts +5 -6
- package/src/repositories/custom-object.ts +41 -32
- package/src/repositories/customer-group.ts +4 -5
- package/src/repositories/customer.ts +42 -5
- package/src/repositories/discount-code.ts +5 -6
- package/src/repositories/errors.ts +10 -14
- package/src/repositories/extension.ts +16 -15
- package/src/repositories/helpers.ts +10 -15
- package/src/repositories/index.ts +75 -0
- package/src/repositories/inventory-entry.ts +5 -6
- package/src/repositories/my-order.ts +2 -2
- package/src/repositories/order-edit.ts +39 -0
- package/src/repositories/order.test.ts +16 -11
- package/src/repositories/order.ts +21 -14
- package/src/repositories/payment.ts +9 -10
- package/src/repositories/product-discount.ts +5 -25
- package/src/repositories/product-projection.ts +12 -5
- package/src/repositories/product-selection.ts +40 -0
- package/src/repositories/product-type.ts +38 -60
- package/src/repositories/product.ts +128 -85
- package/src/repositories/project.ts +16 -33
- package/src/repositories/quote-request.ts +28 -0
- package/src/repositories/quote.ts +28 -0
- package/src/repositories/review.ts +34 -0
- package/src/repositories/shipping-method.ts +25 -28
- package/src/repositories/shopping-list.ts +6 -6
- package/src/repositories/staged-quote.ts +29 -0
- package/src/repositories/standalone-price.ts +36 -0
- package/src/repositories/state.ts +16 -17
- package/src/repositories/store.ts +13 -29
- package/src/repositories/subscription.ts +4 -5
- package/src/repositories/tax-category.ts +9 -26
- package/src/repositories/type.ts +24 -27
- package/src/repositories/zone.ts +9 -11
- package/src/server.ts +5 -0
- package/src/services/abstract.ts +43 -12
- package/src/services/cart-discount.ts +3 -4
- package/src/services/cart.test.ts +9 -11
- package/src/services/cart.ts +42 -38
- package/src/services/category.test.ts +1 -2
- package/src/services/category.ts +3 -4
- package/src/services/channel.ts +3 -4
- package/src/services/custom-object.test.ts +6 -6
- package/src/services/custom-object.ts +4 -5
- package/src/services/customer-group.ts +3 -4
- package/src/services/customer.test.ts +136 -0
- package/src/services/customer.ts +5 -6
- package/src/services/discount-code.ts +3 -4
- package/src/services/extension.ts +3 -4
- package/src/services/index.ts +74 -0
- package/src/services/inventory-entry.test.ts +9 -13
- package/src/services/inventory-entry.ts +3 -4
- package/src/services/my-cart.test.ts +2 -0
- package/src/services/my-cart.ts +4 -5
- package/src/services/my-customer.ts +3 -4
- package/src/services/my-order.ts +4 -5
- package/src/services/my-payment.ts +3 -4
- package/src/services/order.test.ts +28 -26
- package/src/services/order.ts +4 -5
- package/src/services/payment.ts +3 -4
- package/src/services/product-discount.ts +3 -20
- package/src/services/product-projection.test.ts +76 -8
- package/src/services/product-projection.ts +4 -5
- package/src/services/product-type.ts +3 -20
- package/src/services/product.test.ts +200 -90
- package/src/services/product.ts +3 -4
- package/src/services/project.ts +5 -6
- package/src/services/shipping-method.ts +3 -4
- package/src/services/shopping-list.ts +3 -4
- package/src/services/state.ts +3 -4
- package/src/services/store.test.ts +11 -2
- package/src/services/store.ts +4 -21
- package/src/services/subscription.ts +3 -4
- package/src/services/tax-category.ts +3 -20
- package/src/services/type.ts +3 -4
- package/src/services/zone.ts +3 -4
- package/src/storage/abstract.ts +82 -0
- package/src/{storage.ts → storage/in-memory.ts} +79 -147
- package/src/storage/index.ts +2 -0
- package/src/types.ts +52 -83
|
@@ -5,14 +5,11 @@ import {
|
|
|
5
5
|
ProductProjection,
|
|
6
6
|
QueryParam,
|
|
7
7
|
FacetResults,
|
|
8
|
-
FacetTerm,
|
|
9
8
|
TermFacetResult,
|
|
10
9
|
RangeFacetResult,
|
|
11
10
|
FilteredFacetResult,
|
|
12
11
|
} from '@commercetools/platform-sdk'
|
|
13
|
-
import { ByProjectKeyProductProjectionsSearchRequestBuilder } from '@commercetools/platform-sdk/dist/declarations/src/generated/client/search/by-project-key-product-projections-search-request-builder'
|
|
14
12
|
import { nestedLookup } from './helpers'
|
|
15
|
-
import { ProductService } from './services/product'
|
|
16
13
|
import { Writable } from './types'
|
|
17
14
|
import { CommercetoolsError } from './exceptions'
|
|
18
15
|
import {
|
|
@@ -60,13 +57,17 @@ export class ProductProjectionSearch {
|
|
|
60
57
|
projectKey: string,
|
|
61
58
|
params: ProductProjectionSearchParams
|
|
62
59
|
): ProductProjectionPagedSearchResponse {
|
|
63
|
-
// Get a copy of all the products in the storage engine. We need a copy
|
|
64
|
-
// since we will be modifying the data.
|
|
65
60
|
let resources = this._storage
|
|
66
61
|
.all(projectKey, 'product')
|
|
67
|
-
.map(r =>
|
|
62
|
+
.map((r) => this.transform(r, params.staged ?? false))
|
|
63
|
+
.filter((p) => {
|
|
64
|
+
if (!params.staged ?? false) {
|
|
65
|
+
return p.published
|
|
66
|
+
}
|
|
67
|
+
return true
|
|
68
|
+
})
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
const markMatchingVariant = params.markMatchingVariants ?? false
|
|
70
71
|
|
|
71
72
|
// Apply the priceSelector
|
|
72
73
|
applyPriceSelector(resources, {
|
|
@@ -79,15 +80,14 @@ export class ProductProjectionSearch {
|
|
|
79
80
|
// Apply filters pre facetting
|
|
80
81
|
if (params.filter) {
|
|
81
82
|
try {
|
|
82
|
-
const filters = params.filter.map(
|
|
83
|
-
parseFilterExpression(f, params.staged ?? false)
|
|
84
|
-
)
|
|
83
|
+
const filters = params.filter.map(parseFilterExpression)
|
|
85
84
|
|
|
86
85
|
// Filters can modify the output. So clone the resources first.
|
|
87
|
-
resources = resources.filter(resource =>
|
|
88
|
-
filters.every(f => f(resource, markMatchingVariant))
|
|
86
|
+
resources = resources.filter((resource) =>
|
|
87
|
+
filters.every((f) => f(resource, markMatchingVariant))
|
|
89
88
|
)
|
|
90
89
|
} catch (err) {
|
|
90
|
+
console.error(err)
|
|
91
91
|
throw new CommercetoolsError<InvalidInputError>(
|
|
92
92
|
{
|
|
93
93
|
code: 'InvalidInput',
|
|
@@ -104,12 +104,9 @@ export class ProductProjectionSearch {
|
|
|
104
104
|
// Apply filters post facetting
|
|
105
105
|
if (params['filter.query']) {
|
|
106
106
|
try {
|
|
107
|
-
const filters = params['filter.query'].map(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
resources = resources.filter(resource =>
|
|
112
|
-
filters.every(f => f(resource, markMatchingVariant))
|
|
107
|
+
const filters = params['filter.query'].map(parseFilterExpression)
|
|
108
|
+
resources = resources.filter((resource) =>
|
|
109
|
+
filters.every((f) => f(resource, markMatchingVariant))
|
|
113
110
|
)
|
|
114
111
|
} catch (err) {
|
|
115
112
|
throw new CommercetoolsError<InvalidInputError>(
|
|
@@ -122,33 +119,34 @@ export class ProductProjectionSearch {
|
|
|
122
119
|
}
|
|
123
120
|
}
|
|
124
121
|
|
|
125
|
-
// Get the total before slicing the array
|
|
126
|
-
const totalResources = resources.length
|
|
127
|
-
|
|
128
|
-
// Apply offset, limit
|
|
129
|
-
const offset = params.offset || 0
|
|
130
|
-
const limit = params.limit || 20
|
|
131
|
-
resources = resources.slice(offset, offset + limit)
|
|
132
|
-
|
|
133
122
|
// Expand the resources
|
|
134
123
|
if (params.expand !== undefined) {
|
|
135
|
-
resources = resources.map(resource =>
|
|
136
|
-
|
|
137
|
-
|
|
124
|
+
resources = resources.map((resource) =>
|
|
125
|
+
this._storage.expand(projectKey, resource, params.expand)
|
|
126
|
+
)
|
|
138
127
|
}
|
|
139
128
|
|
|
129
|
+
// Create a slice for the pagination. If we were working with large datasets
|
|
130
|
+
// then we should have done this before transforming. But that isn't the
|
|
131
|
+
// goal of this library. So lets keep it simple.
|
|
132
|
+
const totalResults = resources.length
|
|
133
|
+
const offset = params.offset || 0
|
|
134
|
+
const limit = params.limit || 20
|
|
135
|
+
const results = resources.slice(offset, offset + limit)
|
|
136
|
+
|
|
140
137
|
return {
|
|
141
|
-
count:
|
|
142
|
-
total:
|
|
138
|
+
count: totalResults,
|
|
139
|
+
total: results.length,
|
|
143
140
|
offset: offset,
|
|
144
141
|
limit: limit,
|
|
145
|
-
results:
|
|
142
|
+
results: results,
|
|
146
143
|
facets: facets,
|
|
147
144
|
}
|
|
148
145
|
}
|
|
149
146
|
|
|
150
|
-
transform(product: Product): ProductProjection {
|
|
151
|
-
const obj = product.masterData.current
|
|
147
|
+
transform(product: Product, staged: boolean): ProductProjection {
|
|
148
|
+
const obj = !staged ? product.masterData.current : product.masterData.staged
|
|
149
|
+
|
|
152
150
|
return {
|
|
153
151
|
id: product.id,
|
|
154
152
|
createdAt: product.createdAt,
|
|
@@ -163,12 +161,14 @@ export class ProductProjectionSearch {
|
|
|
163
161
|
masterVariant: obj.masterVariant,
|
|
164
162
|
variants: obj.variants,
|
|
165
163
|
productType: product.productType,
|
|
164
|
+
hasStagedChanges: product.masterData.hasStagedChanges,
|
|
165
|
+
published: product.masterData.published,
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
getFacets(
|
|
170
170
|
params: ProductProjectionSearchParams,
|
|
171
|
-
products:
|
|
171
|
+
products: ProductProjection[]
|
|
172
172
|
): FacetResults {
|
|
173
173
|
if (!params.facet) return {}
|
|
174
174
|
const staged = false
|
|
@@ -179,7 +179,7 @@ export class ProductProjectionSearch {
|
|
|
179
179
|
|
|
180
180
|
// Term Facet
|
|
181
181
|
if (expression.type === 'TermExpression') {
|
|
182
|
-
result[facet] = this.termFacet(expression.source, products
|
|
182
|
+
result[facet] = this.termFacet(expression.source, products)
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
// Range Facet
|
|
@@ -187,8 +187,7 @@ export class ProductProjectionSearch {
|
|
|
187
187
|
result[expression.source] = this.rangeFacet(
|
|
188
188
|
expression.source,
|
|
189
189
|
expression.children,
|
|
190
|
-
products
|
|
191
|
-
staged
|
|
190
|
+
products
|
|
192
191
|
)
|
|
193
192
|
}
|
|
194
193
|
|
|
@@ -197,8 +196,7 @@ export class ProductProjectionSearch {
|
|
|
197
196
|
result[expression.source] = this.filterFacet(
|
|
198
197
|
expression.source,
|
|
199
198
|
expression.children,
|
|
200
|
-
products
|
|
201
|
-
staged
|
|
199
|
+
products
|
|
202
200
|
)
|
|
203
201
|
}
|
|
204
202
|
}
|
|
@@ -211,11 +209,7 @@ export class ProductProjectionSearch {
|
|
|
211
209
|
* - counting products
|
|
212
210
|
* - correct dataType
|
|
213
211
|
*/
|
|
214
|
-
termFacet(
|
|
215
|
-
facet: string,
|
|
216
|
-
products: Product[],
|
|
217
|
-
staged: boolean
|
|
218
|
-
): TermFacetResult {
|
|
212
|
+
termFacet(facet: string, products: ProductProjection[]): TermFacetResult {
|
|
219
213
|
const result: Writable<TermFacetResult> = {
|
|
220
214
|
type: 'terms',
|
|
221
215
|
dataType: 'text',
|
|
@@ -227,9 +221,9 @@ export class ProductProjectionSearch {
|
|
|
227
221
|
const terms: Record<any, number> = {}
|
|
228
222
|
|
|
229
223
|
if (facet.startsWith('variants.')) {
|
|
230
|
-
products.forEach(p => {
|
|
231
|
-
const variants = getVariants(p
|
|
232
|
-
variants.forEach(v => {
|
|
224
|
+
products.forEach((p) => {
|
|
225
|
+
const variants = getVariants(p)
|
|
226
|
+
variants.forEach((v) => {
|
|
233
227
|
result.total++
|
|
234
228
|
|
|
235
229
|
let value = resolveVariantValue(v, facet)
|
|
@@ -244,7 +238,7 @@ export class ProductProjectionSearch {
|
|
|
244
238
|
})
|
|
245
239
|
})
|
|
246
240
|
} else {
|
|
247
|
-
products.forEach(p => {
|
|
241
|
+
products.forEach((p) => {
|
|
248
242
|
const value = nestedLookup(p, facet)
|
|
249
243
|
result.total++
|
|
250
244
|
if (value === undefined) {
|
|
@@ -266,15 +260,14 @@ export class ProductProjectionSearch {
|
|
|
266
260
|
filterFacet(
|
|
267
261
|
source: string,
|
|
268
262
|
filters: FilterExpression[] | undefined,
|
|
269
|
-
products:
|
|
270
|
-
staged: boolean
|
|
263
|
+
products: ProductProjection[]
|
|
271
264
|
): FilteredFacetResult {
|
|
272
265
|
let count = 0
|
|
273
266
|
if (source.startsWith('variants.')) {
|
|
274
267
|
for (const p of products) {
|
|
275
|
-
for (const v of getVariants(p
|
|
268
|
+
for (const v of getVariants(p)) {
|
|
276
269
|
const val = resolveVariantValue(v, source)
|
|
277
|
-
if (filters?.some(f => f.match(val))) {
|
|
270
|
+
if (filters?.some((f) => f.match(val))) {
|
|
278
271
|
count++
|
|
279
272
|
}
|
|
280
273
|
}
|
|
@@ -292,15 +285,14 @@ export class ProductProjectionSearch {
|
|
|
292
285
|
rangeFacet(
|
|
293
286
|
source: string,
|
|
294
287
|
ranges: RangeExpression[] | undefined,
|
|
295
|
-
products:
|
|
296
|
-
staged: boolean
|
|
288
|
+
products: ProductProjection[]
|
|
297
289
|
): RangeFacetResult {
|
|
298
290
|
const counts =
|
|
299
|
-
ranges?.map(range => {
|
|
291
|
+
ranges?.map((range) => {
|
|
300
292
|
if (source.startsWith('variants.')) {
|
|
301
293
|
const values = []
|
|
302
294
|
for (const p of products) {
|
|
303
|
-
for (const v of getVariants(p
|
|
295
|
+
for (const v of getVariants(p)) {
|
|
304
296
|
const val = resolveVariantValue(v, source)
|
|
305
297
|
if (val === undefined) {
|
|
306
298
|
continue
|
package/src/projectAPI.ts
CHANGED
|
@@ -1,34 +1,31 @@
|
|
|
1
|
-
import { ReferenceTypeId } from '@commercetools/platform-sdk'
|
|
2
1
|
import { GetParams } from 'repositories/abstract'
|
|
3
2
|
import { getBaseResourceProperties } from './helpers'
|
|
4
3
|
import { AbstractStorage } from './storage'
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
RepositoryTypes,
|
|
8
|
-
ResourceMap,
|
|
9
|
-
Services,
|
|
10
|
-
ServiceTypes,
|
|
11
|
-
} from './types'
|
|
4
|
+
import { RepositoryMap } from './repositories'
|
|
5
|
+
import { ResourceMap, ResourceType } from './types'
|
|
12
6
|
|
|
13
7
|
export class ProjectAPI {
|
|
14
8
|
private projectKey: string
|
|
15
9
|
private _storage: AbstractStorage
|
|
16
|
-
private
|
|
10
|
+
private _repositories: RepositoryMap
|
|
17
11
|
|
|
18
12
|
constructor(
|
|
19
13
|
projectKey: string,
|
|
20
|
-
|
|
14
|
+
repositories: RepositoryMap,
|
|
21
15
|
storage: AbstractStorage
|
|
22
16
|
) {
|
|
23
17
|
this.projectKey = projectKey
|
|
24
18
|
this._storage = storage
|
|
25
|
-
this.
|
|
19
|
+
this._repositories = repositories
|
|
26
20
|
}
|
|
27
21
|
|
|
28
|
-
add
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
add<T extends keyof RepositoryMap & keyof ResourceMap>(
|
|
23
|
+
typeId: T,
|
|
24
|
+
resource: ResourceMap[T]
|
|
25
|
+
) {
|
|
26
|
+
const repository = this._repositories[typeId]
|
|
27
|
+
if (repository) {
|
|
28
|
+
this._storage.add(this.projectKey, typeId, {
|
|
32
29
|
...getBaseResourceProperties(),
|
|
33
30
|
...resource,
|
|
34
31
|
})
|
|
@@ -37,7 +34,7 @@ export class ProjectAPI {
|
|
|
37
34
|
}
|
|
38
35
|
}
|
|
39
36
|
|
|
40
|
-
get<RT extends
|
|
37
|
+
get<RT extends ResourceType>(
|
|
41
38
|
typeId: RT,
|
|
42
39
|
id: string,
|
|
43
40
|
params?: GetParams
|
|
@@ -51,12 +48,10 @@ export class ProjectAPI {
|
|
|
51
48
|
}
|
|
52
49
|
|
|
53
50
|
// TODO: Not sure if we want to expose this...
|
|
54
|
-
getRepository<RT extends keyof RepositoryMap>(
|
|
55
|
-
typeId
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (service !== undefined) {
|
|
59
|
-
return service.repository as RepositoryMap[RT]
|
|
51
|
+
getRepository<RT extends keyof RepositoryMap>(typeId: RT): RepositoryMap[RT] {
|
|
52
|
+
const repository = this._repositories[typeId]
|
|
53
|
+
if (repository !== undefined) {
|
|
54
|
+
return repository as RepositoryMap[RT]
|
|
60
55
|
}
|
|
61
56
|
throw new Error('No such repository')
|
|
62
57
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { RepositoryTypes } from './../types'
|
|
2
|
-
import deepEqual from 'deep-equal'
|
|
3
|
-
|
|
4
1
|
import {
|
|
5
2
|
BaseResource,
|
|
6
|
-
InvalidOperationError,
|
|
7
3
|
Project,
|
|
4
|
+
ResourceNotFoundError,
|
|
8
5
|
UpdateAction,
|
|
9
6
|
} from '@commercetools/platform-sdk'
|
|
7
|
+
import deepEqual from 'deep-equal'
|
|
8
|
+
import { CommercetoolsError } from '../exceptions'
|
|
9
|
+
import { cloneObject } from '../helpers'
|
|
10
10
|
import { AbstractStorage } from '../storage'
|
|
11
|
+
import { ResourceMap, ResourceType, ShallowWritable } from './../types'
|
|
11
12
|
import { checkConcurrentModification } from './errors'
|
|
12
|
-
import { CommercetoolsError } from '../exceptions'
|
|
13
13
|
|
|
14
14
|
export type QueryParams = {
|
|
15
15
|
expand?: string[]
|
|
@@ -26,7 +26,8 @@ export type RepositoryContext = {
|
|
|
26
26
|
projectKey: string
|
|
27
27
|
storeKey?: string
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
export abstract class AbstractRepository<R extends BaseResource | Project> {
|
|
30
31
|
protected _storage: AbstractStorage
|
|
31
32
|
protected actions: Partial<
|
|
32
33
|
Record<
|
|
@@ -39,53 +40,80 @@ export abstract class AbstractRepository {
|
|
|
39
40
|
this._storage = storage
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
abstract
|
|
43
|
+
abstract saveNew({ projectKey }: RepositoryContext, resource: R): void
|
|
44
|
+
|
|
45
|
+
abstract saveUpdate(
|
|
43
46
|
{ projectKey }: RepositoryContext,
|
|
44
|
-
|
|
47
|
+
version: number,
|
|
48
|
+
resource: R
|
|
45
49
|
): void
|
|
46
50
|
|
|
47
51
|
processUpdateActions(
|
|
48
52
|
context: RepositoryContext,
|
|
49
|
-
resource:
|
|
53
|
+
resource: R,
|
|
54
|
+
version: number,
|
|
50
55
|
actions: UpdateAction[]
|
|
51
|
-
):
|
|
56
|
+
): R {
|
|
52
57
|
// Deep-copy
|
|
53
|
-
const
|
|
58
|
+
const updatedResource = cloneObject(resource) as ShallowWritable<R>
|
|
59
|
+
const identifier = (resource as BaseResource).id
|
|
60
|
+
? (resource as BaseResource).id
|
|
61
|
+
: (resource as Project).key
|
|
54
62
|
|
|
55
|
-
actions.forEach(action => {
|
|
63
|
+
actions.forEach((action) => {
|
|
56
64
|
const updateFunc = this.actions[action.action]
|
|
57
65
|
|
|
58
66
|
if (!updateFunc) {
|
|
59
67
|
console.error(`No mock implemented for update action ${action.action}`)
|
|
60
|
-
|
|
68
|
+
throw new Error(
|
|
69
|
+
`No mock implemented for update action ${action.action}`
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const beforeUpdate = cloneObject(resource)
|
|
74
|
+
updateFunc(context, updatedResource, action)
|
|
75
|
+
|
|
76
|
+
// Check if the object is updated. We need to increase the version of
|
|
77
|
+
// an object per action which does an actual modification.
|
|
78
|
+
// This isn't the most performant method to do this (the update action
|
|
79
|
+
// should return a flag) but for now the easiest.
|
|
80
|
+
if (!deepEqual(beforeUpdate, updatedResource)) {
|
|
81
|
+
// We only check the version when there is an actual modification to
|
|
82
|
+
// be stored.
|
|
83
|
+
checkConcurrentModification(resource.version, version, identifier)
|
|
84
|
+
|
|
85
|
+
updatedResource.version += 1
|
|
61
86
|
}
|
|
62
|
-
updateFunc(context, modifiedResource, action)
|
|
63
87
|
})
|
|
64
88
|
|
|
65
|
-
|
|
66
|
-
|
|
89
|
+
// If all actions succeeded we write the new version
|
|
90
|
+
// to the storage.
|
|
91
|
+
if (resource.version != updatedResource.version) {
|
|
92
|
+
this.saveUpdate(context, version, updatedResource)
|
|
67
93
|
}
|
|
68
94
|
|
|
69
|
-
const result = this.postProcessResource(
|
|
95
|
+
const result = this.postProcessResource(updatedResource)
|
|
70
96
|
if (!result) {
|
|
71
|
-
throw new Error(
|
|
97
|
+
throw new Error('invalid post process action')
|
|
72
98
|
}
|
|
73
99
|
return result
|
|
74
100
|
}
|
|
75
101
|
|
|
76
|
-
postProcessResource(resource:
|
|
77
|
-
return resource
|
|
78
|
-
}
|
|
79
|
-
|
|
102
|
+
abstract postProcessResource(resource: any): any
|
|
80
103
|
}
|
|
81
104
|
|
|
82
|
-
export abstract class AbstractResourceRepository
|
|
83
|
-
|
|
84
|
-
|
|
105
|
+
export abstract class AbstractResourceRepository<
|
|
106
|
+
T extends ResourceType
|
|
107
|
+
> extends AbstractRepository<ResourceMap[T]> {
|
|
108
|
+
abstract create(context: RepositoryContext, draft: any): ResourceMap[T]
|
|
109
|
+
abstract getTypeId(): T
|
|
85
110
|
|
|
86
111
|
constructor(storage: AbstractStorage) {
|
|
87
112
|
super(storage)
|
|
88
|
-
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
postProcessResource(resource: ResourceMap[T]): ResourceMap[T] {
|
|
116
|
+
return resource
|
|
89
117
|
}
|
|
90
118
|
|
|
91
119
|
query(context: RepositoryContext, params: QueryParams = {}) {
|
|
@@ -98,7 +126,6 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
|
|
|
98
126
|
|
|
99
127
|
// @ts-ignore
|
|
100
128
|
result.results = result.results.map(this.postProcessResource)
|
|
101
|
-
|
|
102
129
|
return result
|
|
103
130
|
}
|
|
104
131
|
|
|
@@ -106,58 +133,82 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
|
|
|
106
133
|
context: RepositoryContext,
|
|
107
134
|
id: string,
|
|
108
135
|
params: GetParams = {}
|
|
109
|
-
):
|
|
110
|
-
const resource = this._storage.get(
|
|
111
|
-
|
|
136
|
+
): ResourceMap[T] | null {
|
|
137
|
+
const resource = this._storage.get(
|
|
138
|
+
context.projectKey,
|
|
139
|
+
this.getTypeId(),
|
|
140
|
+
id,
|
|
141
|
+
params
|
|
142
|
+
)
|
|
143
|
+
return resource ? this.postProcessResource(resource) : null
|
|
112
144
|
}
|
|
113
145
|
|
|
114
146
|
getByKey(
|
|
115
147
|
context: RepositoryContext,
|
|
116
148
|
key: string,
|
|
117
149
|
params: GetParams = {}
|
|
118
|
-
):
|
|
150
|
+
): ResourceMap[T] | null {
|
|
119
151
|
const resource = this._storage.getByKey(
|
|
120
152
|
context.projectKey,
|
|
121
153
|
this.getTypeId(),
|
|
122
154
|
key,
|
|
123
155
|
params
|
|
124
156
|
)
|
|
125
|
-
return this.postProcessResource(resource)
|
|
157
|
+
return resource ? this.postProcessResource(resource) : null
|
|
126
158
|
}
|
|
127
159
|
|
|
128
160
|
delete(
|
|
129
161
|
context: RepositoryContext,
|
|
130
162
|
id: string,
|
|
131
163
|
params: GetParams = {}
|
|
132
|
-
):
|
|
164
|
+
): ResourceMap[T] | null {
|
|
133
165
|
const resource = this._storage.delete(
|
|
134
166
|
context.projectKey,
|
|
135
167
|
this.getTypeId(),
|
|
136
168
|
id,
|
|
137
169
|
params
|
|
138
170
|
)
|
|
139
|
-
return this.postProcessResource(resource)
|
|
171
|
+
return resource ? this.postProcessResource(resource) : null
|
|
140
172
|
}
|
|
141
173
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
174
|
+
saveNew(
|
|
175
|
+
context: RepositoryContext,
|
|
176
|
+
resource: ShallowWritable<ResourceMap[T]>
|
|
177
|
+
) {
|
|
178
|
+
resource.version = 1
|
|
179
|
+
this._storage.add(context.projectKey, this.getTypeId(), resource as any)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
saveUpdate(
|
|
183
|
+
context: RepositoryContext,
|
|
184
|
+
version: number,
|
|
185
|
+
resource: ShallowWritable<ResourceMap[T]>
|
|
186
|
+
) {
|
|
187
|
+
// Check if the resource still exists.
|
|
188
|
+
const current = this._storage.get(
|
|
189
|
+
context.projectKey,
|
|
190
|
+
this.getTypeId(),
|
|
191
|
+
resource.id
|
|
192
|
+
)
|
|
193
|
+
if (!current) {
|
|
194
|
+
throw new CommercetoolsError<ResourceNotFoundError>(
|
|
195
|
+
{
|
|
196
|
+
code: 'ResourceNotFound',
|
|
197
|
+
message: 'Resource not found while updating',
|
|
198
|
+
},
|
|
199
|
+
400
|
|
200
|
+
)
|
|
157
201
|
}
|
|
158
202
|
|
|
159
|
-
|
|
160
|
-
|
|
203
|
+
checkConcurrentModification(current.version, version, resource.id)
|
|
204
|
+
|
|
205
|
+
if (current.version === resource.version) {
|
|
206
|
+
throw new Error('Internal error: no changes to save')
|
|
207
|
+
}
|
|
208
|
+
resource.lastModifiedAt = new Date().toISOString()
|
|
209
|
+
|
|
161
210
|
this._storage.add(context.projectKey, this.getTypeId(), resource as any)
|
|
211
|
+
|
|
212
|
+
return resource
|
|
162
213
|
}
|
|
163
214
|
}
|
|
@@ -14,16 +14,15 @@ import {
|
|
|
14
14
|
CartDiscountValueFixed,
|
|
15
15
|
CartDiscountValueGiftLineItem,
|
|
16
16
|
CartDiscountValueRelative,
|
|
17
|
-
ReferenceTypeId,
|
|
18
17
|
} from '@commercetools/platform-sdk'
|
|
19
18
|
import { Writable } from 'types'
|
|
20
19
|
import { getBaseResourceProperties } from '../helpers'
|
|
21
20
|
import { AbstractResourceRepository, RepositoryContext } from './abstract'
|
|
22
21
|
import { createTypedMoney } from './helpers'
|
|
23
22
|
|
|
24
|
-
export class CartDiscountRepository extends AbstractResourceRepository {
|
|
25
|
-
getTypeId()
|
|
26
|
-
return 'cart-discount'
|
|
23
|
+
export class CartDiscountRepository extends AbstractResourceRepository<'cart-discount'> {
|
|
24
|
+
getTypeId() {
|
|
25
|
+
return 'cart-discount' as const
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
create(context: RepositoryContext, draft: CartDiscountDraft): CartDiscount {
|
|
@@ -43,7 +42,7 @@ export class CartDiscountRepository extends AbstractResourceRepository {
|
|
|
43
42
|
validUntil: draft.validUntil,
|
|
44
43
|
value: this.transformValueDraft(draft.value),
|
|
45
44
|
}
|
|
46
|
-
this.
|
|
45
|
+
this.saveNew(context, resource)
|
|
47
46
|
return resource
|
|
48
47
|
}
|
|
49
48
|
|