@reactionary/commercetools 0.6.3
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 +11 -0
- package/capabilities/cart.capability.js +324 -0
- package/capabilities/category.capability.js +198 -0
- package/capabilities/checkout.capability.js +374 -0
- package/capabilities/identity.capability.js +95 -0
- package/capabilities/index.js +15 -0
- package/capabilities/inventory.capability.js +63 -0
- package/capabilities/order-search.capability.js +106 -0
- package/capabilities/order.capability.js +48 -0
- package/capabilities/price.capability.js +114 -0
- package/capabilities/product-associations.capability.js +120 -0
- package/capabilities/product-list.capability.js +393 -0
- package/capabilities/product-reviews.capability.js +193 -0
- package/capabilities/product-search.capability.js +297 -0
- package/capabilities/product.capability.js +103 -0
- package/capabilities/profile.capability.js +337 -0
- package/capabilities/store.capability.js +51 -0
- package/core/capability-descriptors.js +274 -0
- package/core/client.js +318 -0
- package/core/initialize.js +47 -0
- package/core/initialize.types.js +8 -0
- package/core/token-cache.js +36 -0
- package/factories/cart/cart.factory.js +110 -0
- package/factories/category/category.factory.js +40 -0
- package/factories/checkout/checkout-initializer-overrides.example.js +67 -0
- package/factories/checkout/checkout.factory.js +235 -0
- package/factories/identity/identity.factory.js +14 -0
- package/factories/inventory/inventory.factory.js +30 -0
- package/factories/order/order.factory.js +114 -0
- package/factories/order-search/order-search.factory.js +68 -0
- package/factories/price/price.factory.js +52 -0
- package/factories/product/product-capability-custom-method-only.example.js +38 -0
- package/factories/product/product-capability-schema-signature-extension.example.js +46 -0
- package/factories/product/product-factory-baseline.example.js +10 -0
- package/factories/product/product-factory-schema-and-parse-extension.example.js +25 -0
- package/factories/product/product-factory-schema-extension.example.js +18 -0
- package/factories/product/product-initializer-factory-extension.example.js +33 -0
- package/factories/product/product.factory.js +151 -0
- package/factories/product/utils.example.js +8 -0
- package/factories/product-associations/product-associations.factory.js +63 -0
- package/factories/product-list/product-list.factory.js +65 -0
- package/factories/product-reviews/product-reviews.factory.js +42 -0
- package/factories/product-search/product-search.factory.js +114 -0
- package/factories/profile/profile.factory.js +62 -0
- package/factories/store/store.factory.js +29 -0
- package/index.js +28 -0
- package/package.json +17 -0
- package/schema/capabilities.schema.js +46 -0
- package/schema/commercetools.schema.js +30 -0
- package/schema/configuration.schema.js +19 -0
- package/schema/session.schema.js +9 -0
- package/src/capabilities/cart.capability.d.ts +34 -0
- package/src/capabilities/category.capability.d.ts +47 -0
- package/src/capabilities/checkout.capability.d.ts +39 -0
- package/src/capabilities/identity.capability.d.ts +14 -0
- package/src/capabilities/index.d.ts +15 -0
- package/src/capabilities/inventory.capability.d.ts +13 -0
- package/src/capabilities/order-search.capability.d.ts +13 -0
- package/src/capabilities/order.capability.d.ts +13 -0
- package/src/capabilities/price.capability.d.ts +18 -0
- package/src/capabilities/product-associations.capability.d.ts +17 -0
- package/src/capabilities/product-list.capability.d.ts +29 -0
- package/src/capabilities/product-reviews.capability.d.ts +18 -0
- package/src/capabilities/product-search.capability.d.ts +82 -0
- package/src/capabilities/product.capability.d.ts +17 -0
- package/src/capabilities/profile.capability.d.ts +30 -0
- package/src/capabilities/store.capability.d.ts +13 -0
- package/src/core/capability-descriptors.d.ts +16 -0
- package/src/core/client.d.ts +55 -0
- package/src/core/initialize.d.ts +5 -0
- package/src/core/initialize.types.d.ts +118 -0
- package/src/core/token-cache.d.ts +9 -0
- package/src/factories/cart/cart.factory.d.ts +14 -0
- package/src/factories/category/category.factory.d.ts +11 -0
- package/src/factories/checkout/checkout-initializer-overrides.example.d.ts +1 -0
- package/src/factories/checkout/checkout.factory.d.ts +18 -0
- package/src/factories/identity/identity.factory.d.ts +8 -0
- package/src/factories/inventory/inventory.factory.d.ts +9 -0
- package/src/factories/order/order.factory.d.ts +9 -0
- package/src/factories/order-search/order-search.factory.d.ts +11 -0
- package/src/factories/price/price.factory.d.ts +11 -0
- package/src/factories/product/product-capability-custom-method-only.example.d.ts +1 -0
- package/src/factories/product/product-capability-schema-signature-extension.example.d.ts +1 -0
- package/src/factories/product/product-factory-baseline.example.d.ts +1 -0
- package/src/factories/product/product-factory-schema-and-parse-extension.example.d.ts +1 -0
- package/src/factories/product/product-factory-schema-extension.example.d.ts +1 -0
- package/src/factories/product/product-initializer-factory-extension.example.d.ts +1 -0
- package/src/factories/product/product.factory.d.ts +18 -0
- package/src/factories/product/utils.example.d.ts +4 -0
- package/src/factories/product-associations/product-associations.factory.d.ts +15 -0
- package/src/factories/product-list/product-list.factory.d.ts +17 -0
- package/src/factories/product-reviews/product-reviews.factory.d.ts +14 -0
- package/src/factories/product-search/product-search.factory.d.ts +13 -0
- package/src/factories/profile/profile.factory.d.ts +11 -0
- package/src/factories/store/store.factory.d.ts +9 -0
- package/src/index.d.ts +28 -0
- package/src/schema/capabilities.schema.d.ts +104 -0
- package/src/schema/commercetools.schema.d.ts +30 -0
- package/src/schema/configuration.schema.d.ts +30 -0
- package/src/schema/session.schema.d.ts +7 -0
- package/src/test/client-builder-merge-extensions.example.d.ts +1 -0
- package/src/test/test-utils.d.ts +27 -0
- package/test/client-builder-merge-extensions.example.js +94 -0
- package/test/test-utils.js +27 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result)
|
|
9
|
+
__defProp(target, key, result);
|
|
10
|
+
return result;
|
|
11
|
+
};
|
|
12
|
+
import {
|
|
13
|
+
ProductReviewsCapability,
|
|
14
|
+
Reactionary,
|
|
15
|
+
success,
|
|
16
|
+
error,
|
|
17
|
+
ProductReviewSchema,
|
|
18
|
+
ProductRatingSummarySchema,
|
|
19
|
+
ProductReviewPaginatedResultSchema
|
|
20
|
+
} from "@reactionary/core";
|
|
21
|
+
class CommercetoolsProductReviewsCapability extends ProductReviewsCapability {
|
|
22
|
+
config;
|
|
23
|
+
commercetools;
|
|
24
|
+
factory;
|
|
25
|
+
constructor(config, cache, context, commercetools, factory) {
|
|
26
|
+
super(cache, context);
|
|
27
|
+
this.config = config;
|
|
28
|
+
this.commercetools = commercetools;
|
|
29
|
+
this.factory = factory;
|
|
30
|
+
}
|
|
31
|
+
async getClient() {
|
|
32
|
+
const client = await this.commercetools.getClient();
|
|
33
|
+
return client.withProjectKey({ projectKey: this.config.projectKey });
|
|
34
|
+
}
|
|
35
|
+
async getAdminClient() {
|
|
36
|
+
const client = await this.commercetools.getAdminClient();
|
|
37
|
+
return client.withProjectKey({ projectKey: this.config.projectKey });
|
|
38
|
+
}
|
|
39
|
+
async getRatingSummary(query) {
|
|
40
|
+
const client = await this.getClient();
|
|
41
|
+
const response = await client.productProjections().withKey({ key: query.product.key }).get().execute().catch((e) => {
|
|
42
|
+
if (e.statusCode === 404) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
throw e;
|
|
46
|
+
});
|
|
47
|
+
if (response && response.body) {
|
|
48
|
+
const summary = {
|
|
49
|
+
identifier: {
|
|
50
|
+
product: query.product
|
|
51
|
+
},
|
|
52
|
+
averageRating: 0,
|
|
53
|
+
totalRatings: 0,
|
|
54
|
+
ratingDistribution: void 0
|
|
55
|
+
};
|
|
56
|
+
if (response.body.reviewRatingStatistics) {
|
|
57
|
+
summary.averageRating = response.body.reviewRatingStatistics.averageRating;
|
|
58
|
+
summary.totalRatings = response.body.reviewRatingStatistics.count;
|
|
59
|
+
summary.ratingDistribution = {
|
|
60
|
+
"1": response.body.reviewRatingStatistics.ratingsDistribution["1"] ?? 0,
|
|
61
|
+
"2": response.body.reviewRatingStatistics.ratingsDistribution["2"] ?? 0,
|
|
62
|
+
"3": response.body.reviewRatingStatistics.ratingsDistribution["3"] ?? 0,
|
|
63
|
+
"4": response.body.reviewRatingStatistics.ratingsDistribution["4"] ?? 0,
|
|
64
|
+
"5": response.body.reviewRatingStatistics.ratingsDistribution["5"] ?? 0
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return success(this.factory.parseRatingSummary(this.context, summary));
|
|
68
|
+
} else {
|
|
69
|
+
return success(
|
|
70
|
+
this.factory.parseRatingSummary(
|
|
71
|
+
this.context,
|
|
72
|
+
this.createEmptyProductRatingSummary({ product: query.product })
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async findReviews(query) {
|
|
78
|
+
const client = await this.getClient();
|
|
79
|
+
const pageNumber = query.paginationOptions?.pageNumber ?? 1;
|
|
80
|
+
const pageSize = query.paginationOptions?.pageSize ?? 20;
|
|
81
|
+
const offset = (pageNumber - 1) * pageSize;
|
|
82
|
+
const product = await client.productProjections().withKey({ key: query.product.key }).get().execute().catch((e) => {
|
|
83
|
+
if (e.statusCode === 404) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
throw e;
|
|
87
|
+
});
|
|
88
|
+
if (!product || !product.body) {
|
|
89
|
+
return success(this.factory.parseReviewPaginatedResult(this.context, {
|
|
90
|
+
items: [],
|
|
91
|
+
totalCount: 0,
|
|
92
|
+
pageSize,
|
|
93
|
+
pageNumber,
|
|
94
|
+
totalPages: 0
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
const whereClause = `target(typeId="product" and id="${product.body.id}")`;
|
|
98
|
+
const sort = ["createdAt desc"];
|
|
99
|
+
const response = await client.reviews().get({
|
|
100
|
+
queryArgs: {
|
|
101
|
+
where: whereClause,
|
|
102
|
+
limit: pageSize,
|
|
103
|
+
offset,
|
|
104
|
+
sort
|
|
105
|
+
}
|
|
106
|
+
}).execute();
|
|
107
|
+
const reviews = response.body.results.map(
|
|
108
|
+
(review) => this.parseSingle(review, query.product.key)
|
|
109
|
+
);
|
|
110
|
+
const returnedResult = {
|
|
111
|
+
items: reviews,
|
|
112
|
+
totalCount: response.body.total || reviews.length,
|
|
113
|
+
pageSize,
|
|
114
|
+
pageNumber,
|
|
115
|
+
totalPages: Math.ceil((response.body.total || reviews.length) / Math.max(pageSize, 1))
|
|
116
|
+
};
|
|
117
|
+
return success(this.factory.parseReviewPaginatedResult(this.context, returnedResult));
|
|
118
|
+
}
|
|
119
|
+
async submitReview(mutation) {
|
|
120
|
+
if (!(this.context.session.identityContext.identity.type === "Registered")) {
|
|
121
|
+
return error({ type: "InvalidInput", error: "Only registered users can submit reviews." });
|
|
122
|
+
}
|
|
123
|
+
const client = await this.getAdminClient();
|
|
124
|
+
const response = await client.reviews().post({
|
|
125
|
+
body: {
|
|
126
|
+
authorName: mutation.authorName,
|
|
127
|
+
title: mutation.title,
|
|
128
|
+
text: mutation.content,
|
|
129
|
+
rating: mutation.rating,
|
|
130
|
+
customer: {
|
|
131
|
+
typeId: "customer",
|
|
132
|
+
id: this.context.session.identityContext.identity.id.userId
|
|
133
|
+
},
|
|
134
|
+
target: {
|
|
135
|
+
typeId: "product",
|
|
136
|
+
id: mutation.product.key
|
|
137
|
+
},
|
|
138
|
+
locale: this.context.languageContext.locale
|
|
139
|
+
}
|
|
140
|
+
}).execute();
|
|
141
|
+
const review = this.parseSingle(response.body, mutation.product.key);
|
|
142
|
+
return success(this.factory.parseReview(this.context, review));
|
|
143
|
+
}
|
|
144
|
+
parseSingle(review, productKey) {
|
|
145
|
+
return {
|
|
146
|
+
identifier: {
|
|
147
|
+
key: review.key || ""
|
|
148
|
+
},
|
|
149
|
+
product: {
|
|
150
|
+
key: productKey
|
|
151
|
+
},
|
|
152
|
+
authorName: review.authorName ?? "Anonymous",
|
|
153
|
+
authorId: review.customer?.id,
|
|
154
|
+
rating: review.rating ?? 0,
|
|
155
|
+
title: review.title ?? "",
|
|
156
|
+
content: review.text ?? "",
|
|
157
|
+
createdAt: review.createdAt,
|
|
158
|
+
updatedAt: review.lastModifiedAt,
|
|
159
|
+
verified: !!review.customer
|
|
160
|
+
// Verified if linked to a customer
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
__decorateClass([
|
|
165
|
+
Reactionary({
|
|
166
|
+
outputSchema: ProductRatingSummarySchema,
|
|
167
|
+
cache: true,
|
|
168
|
+
cacheTimeToLiveInSeconds: 300,
|
|
169
|
+
currencyDependentCaching: false,
|
|
170
|
+
localeDependentCaching: false
|
|
171
|
+
})
|
|
172
|
+
], CommercetoolsProductReviewsCapability.prototype, "getRatingSummary", 1);
|
|
173
|
+
__decorateClass([
|
|
174
|
+
Reactionary({
|
|
175
|
+
outputSchema: ProductReviewPaginatedResultSchema,
|
|
176
|
+
cache: true,
|
|
177
|
+
cacheTimeToLiveInSeconds: 60,
|
|
178
|
+
currencyDependentCaching: false,
|
|
179
|
+
localeDependentCaching: true
|
|
180
|
+
})
|
|
181
|
+
], CommercetoolsProductReviewsCapability.prototype, "findReviews", 1);
|
|
182
|
+
__decorateClass([
|
|
183
|
+
Reactionary({
|
|
184
|
+
outputSchema: ProductReviewSchema,
|
|
185
|
+
cache: false,
|
|
186
|
+
cacheTimeToLiveInSeconds: 0,
|
|
187
|
+
currencyDependentCaching: false,
|
|
188
|
+
localeDependentCaching: false
|
|
189
|
+
})
|
|
190
|
+
], CommercetoolsProductReviewsCapability.prototype, "submitReview", 1);
|
|
191
|
+
export {
|
|
192
|
+
CommercetoolsProductReviewsCapability
|
|
193
|
+
};
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result)
|
|
9
|
+
__defProp(target, key, result);
|
|
10
|
+
return result;
|
|
11
|
+
};
|
|
12
|
+
import {
|
|
13
|
+
FacetValueIdentifierSchema,
|
|
14
|
+
ProductSearchCapability,
|
|
15
|
+
ProductSearchQueryByTermSchema,
|
|
16
|
+
ProductSearchQueryCreateNavigationFilterSchema,
|
|
17
|
+
ProductSearchResultSchema,
|
|
18
|
+
Reactionary,
|
|
19
|
+
success
|
|
20
|
+
} from "@reactionary/core";
|
|
21
|
+
import createDebug from "debug";
|
|
22
|
+
import { CommercetoolsCategoryLookupSchema, CommercetoolsResolveCategoryQueryByKeySchema } from "../schema/commercetools.schema.js";
|
|
23
|
+
const debug = createDebug("reactionary:commercetools:search");
|
|
24
|
+
class CommercetoolsProductSearchCapability extends ProductSearchCapability {
|
|
25
|
+
config;
|
|
26
|
+
commercetools;
|
|
27
|
+
factory;
|
|
28
|
+
constructor(config, cache, context, commercetools, factory) {
|
|
29
|
+
super(cache, context);
|
|
30
|
+
this.config = config;
|
|
31
|
+
this.commercetools = commercetools;
|
|
32
|
+
this.factory = factory;
|
|
33
|
+
}
|
|
34
|
+
async getClient() {
|
|
35
|
+
const client = await this.commercetools.getClient();
|
|
36
|
+
return client.withProjectKey({ projectKey: this.config.projectKey }).products();
|
|
37
|
+
}
|
|
38
|
+
async getFacetQuery(payload, selectedFacetValue) {
|
|
39
|
+
if (selectedFacetValue.facet.key === "categories") {
|
|
40
|
+
return {
|
|
41
|
+
exact: {
|
|
42
|
+
field: "categoriesSubTree",
|
|
43
|
+
values: [selectedFacetValue.key],
|
|
44
|
+
fieldType: "text"
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
exact: {
|
|
50
|
+
field: selectedFacetValue.facet.key,
|
|
51
|
+
fieldType: "text",
|
|
52
|
+
value: selectedFacetValue.key
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async resolveCategoryFromId(payload) {
|
|
57
|
+
const client = (await this.commercetools.getClient()).withProjectKey({ projectKey: this.config.projectKey });
|
|
58
|
+
const response = await client.categories().withId({ ID: payload.id }).get().execute();
|
|
59
|
+
if (!response.body || !response.body.name) {
|
|
60
|
+
throw new Error(`Category with ID ${payload.id} not found`);
|
|
61
|
+
}
|
|
62
|
+
const result = {
|
|
63
|
+
id: response.body.id,
|
|
64
|
+
key: response.body.key,
|
|
65
|
+
name: response.body.name,
|
|
66
|
+
meta: {
|
|
67
|
+
cache: {
|
|
68
|
+
hit: false,
|
|
69
|
+
key: "commercetools-internal-category-from-id-" + payload.id
|
|
70
|
+
},
|
|
71
|
+
placeholder: false
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
async resolveCategoryFromKey(payload) {
|
|
77
|
+
const client = (await this.commercetools.getClient()).withProjectKey({ projectKey: this.config.projectKey });
|
|
78
|
+
const response = await client.categories().withKey({ key: payload.key }).get().execute();
|
|
79
|
+
if (!response.body || !response.body.name) {
|
|
80
|
+
throw new Error(`Category with key ${payload.key} not found`);
|
|
81
|
+
}
|
|
82
|
+
const result = {
|
|
83
|
+
id: response.body.id,
|
|
84
|
+
key: response.body.key,
|
|
85
|
+
name: response.body.name,
|
|
86
|
+
meta: {
|
|
87
|
+
cache: {
|
|
88
|
+
hit: false,
|
|
89
|
+
key: "commercetools-internal-category-from-key-" + payload.key
|
|
90
|
+
},
|
|
91
|
+
placeholder: false
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
async getCategoryFilterExpression(payload) {
|
|
97
|
+
if (!payload.search.categoryFilter) {
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
100
|
+
if (payload.search.categoryFilter.key) {
|
|
101
|
+
return {
|
|
102
|
+
exact: {
|
|
103
|
+
field: "categoriesSubTree",
|
|
104
|
+
values: [payload.search.categoryFilter.key],
|
|
105
|
+
fieldType: "text"
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return void 0;
|
|
110
|
+
}
|
|
111
|
+
async getSearchTermExpression(payload) {
|
|
112
|
+
if (payload.search.term.trim().length === 0 || payload.search.term === "*") {
|
|
113
|
+
return void 0;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
or: [
|
|
117
|
+
{
|
|
118
|
+
fullText: {
|
|
119
|
+
field: "name",
|
|
120
|
+
language: `${this.context.languageContext.locale}`,
|
|
121
|
+
value: payload.search.term
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
fullText: {
|
|
126
|
+
field: "description",
|
|
127
|
+
language: `${this.context.languageContext.locale}`,
|
|
128
|
+
value: payload.search.term
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
fullText: {
|
|
133
|
+
field: "searchKeywords",
|
|
134
|
+
language: `${this.context.languageContext.locale}`,
|
|
135
|
+
value: payload.search.term
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async getFacetsQuery(payload) {
|
|
142
|
+
if (payload.search.facets.length === 0) {
|
|
143
|
+
return void 0;
|
|
144
|
+
}
|
|
145
|
+
const facetsToApply = await Promise.all(
|
|
146
|
+
payload.search.facets.map((facet) => this.getFacetQuery(payload, facet))
|
|
147
|
+
);
|
|
148
|
+
if (facetsToApply.length === 0) {
|
|
149
|
+
return void 0;
|
|
150
|
+
}
|
|
151
|
+
if (facetsToApply.length === 1) {
|
|
152
|
+
return facetsToApply[0];
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
and: facetsToApply
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async getFacetsToReturn(payload) {
|
|
159
|
+
const facetsToReturn = [];
|
|
160
|
+
const configFacets = ["categories", ...this.config.facetFieldsForSearch];
|
|
161
|
+
for (const facet of configFacets) {
|
|
162
|
+
facetsToReturn.push({
|
|
163
|
+
distinct: {
|
|
164
|
+
name: facet,
|
|
165
|
+
field: facet,
|
|
166
|
+
fieldType: "text",
|
|
167
|
+
limit: 50
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return facetsToReturn;
|
|
172
|
+
}
|
|
173
|
+
async createCategoryNavigationFilter(payload) {
|
|
174
|
+
const categoryPath = payload.categoryPath;
|
|
175
|
+
const deepestCategory = categoryPath[categoryPath.length - 1];
|
|
176
|
+
const resolvedCategory = await this.resolveCategoryFromKey({ key: deepestCategory.identifier.key });
|
|
177
|
+
const resolvedId = resolvedCategory?.id;
|
|
178
|
+
const facetIdentifier = {
|
|
179
|
+
key: "categories"
|
|
180
|
+
};
|
|
181
|
+
const facetValueIdentifier = {
|
|
182
|
+
facet: facetIdentifier,
|
|
183
|
+
key: resolvedId || "unknown"
|
|
184
|
+
};
|
|
185
|
+
return success(facetValueIdentifier);
|
|
186
|
+
}
|
|
187
|
+
async queryByTerm(payload) {
|
|
188
|
+
const client = await this.getClient();
|
|
189
|
+
const facetsToReturn = await this.getFacetsToReturn(payload);
|
|
190
|
+
const facetsToApply = await this.getFacetsQuery(payload);
|
|
191
|
+
const searchTermExpression = await this.getSearchTermExpression(payload);
|
|
192
|
+
const categoryFilterExpression = await this.getCategoryFilterExpression(payload);
|
|
193
|
+
let finalFilterExpression = void 0;
|
|
194
|
+
if (searchTermExpression) {
|
|
195
|
+
finalFilterExpression = searchTermExpression;
|
|
196
|
+
}
|
|
197
|
+
if (facetsToApply) {
|
|
198
|
+
if (finalFilterExpression) {
|
|
199
|
+
finalFilterExpression = {
|
|
200
|
+
and: [finalFilterExpression, facetsToApply]
|
|
201
|
+
};
|
|
202
|
+
} else {
|
|
203
|
+
finalFilterExpression = facetsToApply;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (categoryFilterExpression) {
|
|
207
|
+
if (finalFilterExpression) {
|
|
208
|
+
finalFilterExpression = {
|
|
209
|
+
and: [finalFilterExpression, categoryFilterExpression]
|
|
210
|
+
};
|
|
211
|
+
} else {
|
|
212
|
+
finalFilterExpression = categoryFilterExpression;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const response = await client.search().post({
|
|
216
|
+
body: {
|
|
217
|
+
query: finalFilterExpression,
|
|
218
|
+
productProjectionParameters: {
|
|
219
|
+
storeProjection: this.context.storeIdentifier.key
|
|
220
|
+
},
|
|
221
|
+
limit: payload.search.paginationOptions.pageSize,
|
|
222
|
+
offset: (payload.search.paginationOptions.pageNumber - 1) * payload.search.paginationOptions.pageSize,
|
|
223
|
+
facets: [...facetsToReturn]
|
|
224
|
+
}
|
|
225
|
+
}).execute();
|
|
226
|
+
const responseBody = response.body;
|
|
227
|
+
const result = this.factory.parseSearchResult(
|
|
228
|
+
this.context,
|
|
229
|
+
responseBody,
|
|
230
|
+
payload
|
|
231
|
+
);
|
|
232
|
+
await this.patchCategoryFacetValues(result);
|
|
233
|
+
for (const selectedFacet of payload.search.facets) {
|
|
234
|
+
const facet = result.facets.find((f) => f.identifier.key === selectedFacet.facet.key);
|
|
235
|
+
if (facet) {
|
|
236
|
+
const value = facet.values.find((v) => v.identifier.key === selectedFacet.key);
|
|
237
|
+
if (value) {
|
|
238
|
+
value.active = true;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (debug.enabled) {
|
|
243
|
+
debug(
|
|
244
|
+
`Search for term "${payload.search.term}" returned ${responseBody.results.length} products (page ${payload.search.paginationOptions.pageNumber} of ${result.totalPages})`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
return success(result);
|
|
248
|
+
}
|
|
249
|
+
async patchCategoryFacetValues(result) {
|
|
250
|
+
const categoryFacet = result.facets.find(
|
|
251
|
+
(f) => f.identifier.key === "categories"
|
|
252
|
+
);
|
|
253
|
+
if (!categoryFacet) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const resolvedCategories = categoryFacet.values.map((facetValue) => this.resolveCategoryFromId({ id: facetValue.identifier.key }));
|
|
257
|
+
const categories = await Promise.all(resolvedCategories);
|
|
258
|
+
for (const facetValue of categoryFacet.values) {
|
|
259
|
+
try {
|
|
260
|
+
const category = categories.find((c) => c.id === facetValue.identifier.key);
|
|
261
|
+
if (!category) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
facetValue.name = category.name[this.context.languageContext.locale] || category.id;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
if (debug.enabled) {
|
|
267
|
+
debug(`Error resolving category key for id ${facetValue.identifier.key}:`, error);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
__decorateClass([
|
|
274
|
+
Reactionary({
|
|
275
|
+
inputSchema: CommercetoolsResolveCategoryQueryByKeySchema,
|
|
276
|
+
outputSchema: CommercetoolsCategoryLookupSchema
|
|
277
|
+
})
|
|
278
|
+
], CommercetoolsProductSearchCapability.prototype, "resolveCategoryFromKey", 1);
|
|
279
|
+
__decorateClass([
|
|
280
|
+
Reactionary({
|
|
281
|
+
inputSchema: ProductSearchQueryCreateNavigationFilterSchema,
|
|
282
|
+
outputSchema: FacetValueIdentifierSchema
|
|
283
|
+
})
|
|
284
|
+
], CommercetoolsProductSearchCapability.prototype, "createCategoryNavigationFilter", 1);
|
|
285
|
+
__decorateClass([
|
|
286
|
+
Reactionary({
|
|
287
|
+
inputSchema: ProductSearchQueryByTermSchema,
|
|
288
|
+
outputSchema: ProductSearchResultSchema,
|
|
289
|
+
cache: true,
|
|
290
|
+
cacheTimeToLiveInSeconds: 300,
|
|
291
|
+
currencyDependentCaching: false,
|
|
292
|
+
localeDependentCaching: true
|
|
293
|
+
})
|
|
294
|
+
], CommercetoolsProductSearchCapability.prototype, "queryByTerm", 1);
|
|
295
|
+
export {
|
|
296
|
+
CommercetoolsProductSearchCapability
|
|
297
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result)
|
|
9
|
+
__defProp(target, key, result);
|
|
10
|
+
return result;
|
|
11
|
+
};
|
|
12
|
+
import {
|
|
13
|
+
ProductCapability,
|
|
14
|
+
ProductQueryByIdSchema,
|
|
15
|
+
ProductQueryBySKUSchema,
|
|
16
|
+
ProductQueryBySlugSchema,
|
|
17
|
+
ProductSchema,
|
|
18
|
+
Reactionary,
|
|
19
|
+
success,
|
|
20
|
+
error
|
|
21
|
+
} from "@reactionary/core";
|
|
22
|
+
class CommercetoolsProductCapability extends ProductCapability {
|
|
23
|
+
constructor(cache, context, config, commercetools, factory) {
|
|
24
|
+
super(cache, context);
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.commercetools = commercetools;
|
|
27
|
+
this.factory = factory;
|
|
28
|
+
}
|
|
29
|
+
async getClient() {
|
|
30
|
+
const client = await this.commercetools.getClient();
|
|
31
|
+
return client.withProjectKey({ projectKey: this.config.projectKey }).productProjections();
|
|
32
|
+
}
|
|
33
|
+
async getById(payload) {
|
|
34
|
+
const client = await this.getClient();
|
|
35
|
+
const remote = await client.withKey({ key: payload.identifier.key }).get().execute();
|
|
36
|
+
const value = this.factory.parseProduct(this.context, remote.body);
|
|
37
|
+
return success(value);
|
|
38
|
+
}
|
|
39
|
+
async getBySlug(payload) {
|
|
40
|
+
const client = await this.getClient();
|
|
41
|
+
const remote = await client.get({
|
|
42
|
+
queryArgs: {
|
|
43
|
+
// FIXME: Hardcoded locale
|
|
44
|
+
where: "slug(en = :slug)",
|
|
45
|
+
"var.slug": payload.slug
|
|
46
|
+
}
|
|
47
|
+
}).execute();
|
|
48
|
+
if (remote.body.count === 0) {
|
|
49
|
+
return error({
|
|
50
|
+
type: "NotFound",
|
|
51
|
+
identifier: payload.slug
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const result = this.factory.parseProduct(this.context, remote.body.results[0]);
|
|
55
|
+
return success(result);
|
|
56
|
+
}
|
|
57
|
+
async getBySKU(payload) {
|
|
58
|
+
const client = await this.getClient();
|
|
59
|
+
const remote = await client.get({
|
|
60
|
+
queryArgs: {
|
|
61
|
+
staged: false,
|
|
62
|
+
limit: 1,
|
|
63
|
+
where: "variants(sku in (:skus)) OR (masterVariant(sku in (:skus))) ",
|
|
64
|
+
"var.skus": [payload].map((p) => p.variant.sku)
|
|
65
|
+
}
|
|
66
|
+
}).execute();
|
|
67
|
+
const result = this.factory.parseProduct(this.context, remote.body.results[0]);
|
|
68
|
+
return success(result);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
__decorateClass([
|
|
72
|
+
Reactionary({
|
|
73
|
+
inputSchema: ProductQueryByIdSchema,
|
|
74
|
+
outputSchema: ProductSchema,
|
|
75
|
+
cache: true,
|
|
76
|
+
cacheTimeToLiveInSeconds: 300,
|
|
77
|
+
currencyDependentCaching: false,
|
|
78
|
+
localeDependentCaching: true
|
|
79
|
+
})
|
|
80
|
+
], CommercetoolsProductCapability.prototype, "getById", 1);
|
|
81
|
+
__decorateClass([
|
|
82
|
+
Reactionary({
|
|
83
|
+
inputSchema: ProductQueryBySlugSchema,
|
|
84
|
+
outputSchema: ProductSchema,
|
|
85
|
+
cache: true,
|
|
86
|
+
cacheTimeToLiveInSeconds: 300,
|
|
87
|
+
currencyDependentCaching: false,
|
|
88
|
+
localeDependentCaching: true
|
|
89
|
+
})
|
|
90
|
+
], CommercetoolsProductCapability.prototype, "getBySlug", 1);
|
|
91
|
+
__decorateClass([
|
|
92
|
+
Reactionary({
|
|
93
|
+
inputSchema: ProductQueryBySKUSchema,
|
|
94
|
+
outputSchema: ProductSchema,
|
|
95
|
+
cache: true,
|
|
96
|
+
cacheTimeToLiveInSeconds: 300,
|
|
97
|
+
currencyDependentCaching: false,
|
|
98
|
+
localeDependentCaching: true
|
|
99
|
+
})
|
|
100
|
+
], CommercetoolsProductCapability.prototype, "getBySKU", 1);
|
|
101
|
+
export {
|
|
102
|
+
CommercetoolsProductCapability
|
|
103
|
+
};
|