Skip to content

Commit ec1cc5e

Browse files
feat(elasticsearch-plugin): Extend ElasticSearch to also support groupBySKU for multi-vendor store scenarios (#3528)
1 parent 5aa01cc commit ec1cc5e

File tree

9 files changed

+116
-38
lines changed

9 files changed

+116
-38
lines changed

packages/elasticsearch-plugin/e2e/e2e-helpers.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,20 @@ export async function testGroupByProduct(client: SimpleGraphQLClient) {
3737
},
3838
},
3939
);
40-
expect(result.search.totalItems).toBe(20);
40+
expect(result.search.totalItems).toBe(21);
41+
}
42+
43+
export async function testGroupBySKU(client: SimpleGraphQLClient) {
44+
const result = await client.query<SearchProductsShopQuery, SearchProductsShopQueryVariables>(
45+
SEARCH_PRODUCTS_SHOP,
46+
{
47+
input: {
48+
term: 'bonsai',
49+
groupBySKU: true,
50+
},
51+
},
52+
);
53+
expect(result.search.totalItems).toBe(1);
4154
}
4255

4356
export async function testNoGrouping(client: SimpleGraphQLClient) {
@@ -46,10 +59,11 @@ export async function testNoGrouping(client: SimpleGraphQLClient) {
4659
{
4760
input: {
4861
groupByProduct: false,
62+
groupBySKU: false,
4963
},
5064
},
5165
);
52-
expect(result.search.totalItems).toBe(34);
66+
expect(result.search.totalItems).toBe(35);
5367
}
5468

5569
export async function testMatchSearchTerm(client: SimpleGraphQLClient) {
@@ -110,6 +124,7 @@ export async function testMatchFacetIdsOr(client: SimpleGraphQLClient) {
110124
);
111125
expect(result.search.items.map(i => i.productName)).toEqual([
112126
'Bonsai Tree',
127+
'Bonsai Tree (Ch2)',
113128
'Camera Lens',
114129
'Clacky Keyboard',
115130
'Curvy Monitor',
@@ -157,6 +172,7 @@ export async function testMatchFacetValueFiltersOr(client: SimpleGraphQLClient)
157172
expect(result.search.items.map(i => i.productName).sort()).toEqual(
158173
[
159174
'Bonsai Tree',
175+
'Bonsai Tree (Ch2)',
160176
'Camera Lens',
161177
'Clacky Keyboard',
162178
'Curvy Monitor',
@@ -256,6 +272,7 @@ export async function testMatchCollectionId(client: SimpleGraphQLClient) {
256272
);
257273
expect(result.search.items.map(i => i.productName).sort()).toEqual([
258274
'Bonsai Tree',
275+
'Bonsai Tree (Ch2)',
259276
'Orchid',
260277
'Spiky Cactus',
261278
]);
@@ -273,6 +290,7 @@ export async function testMatchCollectionSlug(client: SimpleGraphQLClient) {
273290
);
274291
expect(result.search.items.map(i => i.productName).sort()).toEqual([
275292
'Bonsai Tree',
293+
'Bonsai Tree (Ch2)',
276294
'Orchid',
277295
'Spiky Cactus',
278296
]);

packages/elasticsearch-plugin/e2e/elasticsearch-plugin-uuid.e2e-spec.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,19 @@ describe('Elasticsearch plugin with UuidIdStrategy', () => {
6363
},
6464
},
6565
);
66-
expect(search.totalItems).toBe(20);
66+
expect(search.totalItems).toBe(21);
67+
});
68+
69+
it('no term or filters grouped by SKU', async () => {
70+
const { search } = await shopClient.query<SearchProductsShopQuery, SearchProductsShopQueryVariables>(
71+
SEARCH_PRODUCTS_SHOP,
72+
{
73+
input: {
74+
groupBySKU: true,
75+
},
76+
},
77+
);
78+
expect(search.totalItems).toBe(34);
6779
});
6880

6981
it('with search term', async () => {
@@ -79,6 +91,19 @@ describe('Elasticsearch plugin with UuidIdStrategy', () => {
7991
expect(search.totalItems).toBe(1);
8092
});
8193

94+
it('with search term grouped by SKU', async () => {
95+
const { search } = await shopClient.query<SearchProductsShopQuery, SearchProductsShopQueryVariables>(
96+
SEARCH_PRODUCTS_SHOP,
97+
{
98+
input: {
99+
groupBySKU: true,
100+
term: 'bonsai',
101+
},
102+
},
103+
);
104+
expect(search.totalItems).toBe(1);
105+
});
106+
82107
it('with collectionId filter term', async () => {
83108
const { collections } = await shopClient.query<GetCollectionListQuery>(GET_COLLECTION_LIST);
84109
const { search } = await shopClient.query<SearchProductsShopQuery, SearchProductsShopQueryVariables>(

packages/elasticsearch-plugin/e2e/elasticsearch-plugin.e2e-spec.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
doAdminSearchQuery,
5151
dropElasticIndices,
5252
testGroupByProduct,
53+
testGroupBySKU,
5354
testMatchCollectionId,
5455
testMatchCollectionSlug,
5556
testMatchFacetIdsAnd,
@@ -203,6 +204,8 @@ describe('Elasticsearch plugin', () => {
203204
describe('shop api', () => {
204205
it('group by product', () => testGroupByProduct(shopClient));
205206

207+
it('group by SKU', () => testGroupBySKU(shopClient));
208+
206209
it('no grouping', () => testNoGrouping(shopClient));
207210

208211
it('matches search term', () => testMatchSearchTerm(shopClient));
@@ -245,8 +248,8 @@ describe('Elasticsearch plugin', () => {
245248
{ count: 17, facetValue: { id: 'T_2', name: 'computers' } },
246249
{ count: 4, facetValue: { id: 'T_3', name: 'photo' } },
247250
{ count: 10, facetValue: { id: 'T_4', name: 'sports equipment' } },
248-
{ count: 3, facetValue: { id: 'T_5', name: 'home & garden' } },
249-
{ count: 3, facetValue: { id: 'T_6', name: 'plants' } },
251+
{ count: 4, facetValue: { id: 'T_5', name: 'home & garden' } },
252+
{ count: 4, facetValue: { id: 'T_6', name: 'plants' } },
250253
]);
251254
});
252255

@@ -264,8 +267,8 @@ describe('Elasticsearch plugin', () => {
264267
{ count: 6, facetValue: { id: 'T_2', name: 'computers' } },
265268
{ count: 4, facetValue: { id: 'T_3', name: 'photo' } },
266269
{ count: 7, facetValue: { id: 'T_4', name: 'sports equipment' } },
267-
{ count: 3, facetValue: { id: 'T_5', name: 'home & garden' } },
268-
{ count: 3, facetValue: { id: 'T_6', name: 'plants' } },
270+
{ count: 4, facetValue: { id: 'T_5', name: 'home & garden' } },
271+
{ count: 4, facetValue: { id: 'T_6', name: 'plants' } },
269272
]);
270273
});
271274

@@ -312,8 +315,8 @@ describe('Elasticsearch plugin', () => {
312315
{ count: 6, facetValue: { id: 'T_2', name: 'computers' } },
313316
{ count: 4, facetValue: { id: 'T_3', name: 'photo' } },
314317
{ count: 7, facetValue: { id: 'T_4', name: 'sports equipment' } },
315-
{ count: 3, facetValue: { id: 'T_5', name: 'home & garden' } },
316-
{ count: 3, facetValue: { id: 'T_6', name: 'plants' } },
318+
{ count: 4, facetValue: { id: 'T_5', name: 'home & garden' } },
319+
{ count: 4, facetValue: { id: 'T_6', name: 'plants' } },
317320
]);
318321
});
319322

@@ -327,7 +330,7 @@ describe('Elasticsearch plugin', () => {
327330
},
328331
});
329332
expect(result.search.collections).toEqual([
330-
{ collection: { id: 'T_2', name: 'Plants' }, count: 3 },
333+
{ collection: { id: 'T_2', name: 'Plants' }, count: 4 },
331334
]);
332335
});
333336

@@ -341,7 +344,7 @@ describe('Elasticsearch plugin', () => {
341344
},
342345
});
343346
expect(result.search.collections).toEqual([
344-
{ collection: { id: 'T_2', name: 'Plants' }, count: 3 },
347+
{ collection: { id: 'T_2', name: 'Plants' }, count: 4 },
345348
]);
346349
});
347350

@@ -407,7 +410,7 @@ describe('Elasticsearch plugin', () => {
407410
},
408411
},
409412
);
410-
expect(result.search.totalItems).toBe(2);
413+
expect(result.search.totalItems).toBe(3);
411414
});
412415

413416
it('inStock is false and grouped by product', async () => {
@@ -420,7 +423,7 @@ describe('Elasticsearch plugin', () => {
420423
},
421424
},
422425
);
423-
expect(result.search.totalItems).toBe(1);
426+
expect(result.search.totalItems).toBe(2);
424427
});
425428

426429
it('inStock is true and not grouped by product', async () => {
@@ -459,7 +462,7 @@ describe('Elasticsearch plugin', () => {
459462
},
460463
},
461464
);
462-
expect(result.search.totalItems).toBe(33);
465+
expect(result.search.totalItems).toBe(34);
463466
});
464467

465468
it('inStock is undefined and grouped by product', async () => {
@@ -472,13 +475,15 @@ describe('Elasticsearch plugin', () => {
472475
},
473476
},
474477
);
475-
expect(result.search.totalItems).toBe(20);
478+
expect(result.search.totalItems).toBe(21);
476479
});
477480
});
478481

479482
describe('admin api', () => {
480483
it('group by product', () => testGroupByProduct(adminClient));
481484

485+
it('group by SKU', () => testGroupBySKU(adminClient));
486+
482487
it('no grouping', () => testNoGrouping(adminClient));
483488

484489
it('matches search term', () => testMatchSearchTerm(adminClient));

packages/elasticsearch-plugin/e2e/fixtures/e2e-products-full.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ Running Shoe , running-shoe , "With its ultra-light, uber-responsive
3333
Spiky Cactus , spiky-cactus , "A spiky yet elegant house cactus - perfect for the home or office. Origin and habitat: Probably native only to the Andes of Peru" , , category:home & garden|category:plants , , , SC011001 , 15.50 , standard , 100 , true , ,
3434
Orchid , orchid , "Gloriously elegant. It can go along with any interior as it is a neutral color and the most popular Phalaenopsis overall. 2 to 3 foot stems host large white flowers that can last for over 2 months." , , category:home & garden|category:plants , , , ROR00221 , 65.00 , standard , 100 , true , ,
3535
Bonsai Tree , bonsai-tree , "Excellent semi-evergreen bonsai. Indoors or out but needs some winter protection. All trees sent will leave the nursery in excellent condition and will be of equal quality or better than the photograph shown." , , category:home & garden|category:plants , , , B01MXFLUSV , 19.99 , standard , 0 , true , ,
36+
Bonsai Tree (Ch2) , bonsai-tree-ch2 , "SAME PRODUCT IN A DIFFERENT CHANNEL WITH SAME SKU to test groupBySKU - Excellent semi-evergreen bonsai. Indoors or out but needs some winter protection. All trees sent will leave the nursery in excellent condition and will be of equal quality or better than the photograph shown." , , category:home & garden|category:plants , , , B01MXFLUSV , 19.99 , standard , 0 , true , ,

packages/elasticsearch-plugin/src/api/api-extensions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export function generateSchemaExtensions(options: ElasticsearchOptions): Documen
3838
priceRange: PriceRangeInput
3939
priceRangeWithTax: PriceRangeInput
4040
inStock: Boolean
41+
groupBySKU: Boolean
4142
${inputExtensions.map(([name, type]) => `${name}: ${type}`).join('\n ')}
4243
}
4344

packages/elasticsearch-plugin/src/build-elastic-body.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export function buildElasticBody(
2222
collectionId,
2323
collectionSlug,
2424
groupByProduct,
25+
groupBySKU,
2526
skip,
2627
take,
2728
sort,
@@ -147,6 +148,9 @@ export function buildElasticBody(
147148
if (groupByProduct) {
148149
body.collapse = { field: 'productId' };
149150
}
151+
if (groupBySKU) {
152+
body.collapse = { field: 'sku.keyword' };
153+
}
150154
return body;
151155
}
152156

0 commit comments

Comments
 (0)