Просмотр исходного кода

fix(core): Fix DefaultSearchPlugin pagination/sort with non-default lang

Fixes #1752, fixes #1746
Michael Bromley 3 лет назад
Родитель
Сommit
5f7bea4d21

+ 193 - 148
packages/core/e2e/default-search-plugin.e2e-spec.ts

@@ -42,14 +42,13 @@ import {
     SearchGetPrices,
     SearchInput,
     SearchResultSortParameter,
-    SortOrder,
     UpdateAsset,
     UpdateCollection,
     UpdateProduct,
     UpdateProductVariants,
     UpdateTaxRate,
 } from './graphql/generated-e2e-admin-types';
-import { LogicalOperator, SearchProductsShop } from './graphql/generated-e2e-shop-types';
+import { LogicalOperator, SearchProductsShop, SortOrder } from './graphql/generated-e2e-shop-types';
 import {
     ASSIGN_PRODUCTVARIANT_TO_CHANNEL,
     ASSIGN_PRODUCT_TO_CHANNEL,
@@ -88,9 +87,9 @@ interface SearchProductShopVariables extends SearchProductsShop.Variables {
 }
 
 describe('Default search plugin', () => {
-    const {server, adminClient, shopClient} = createTestEnvironment(
+    const { server, adminClient, shopClient } = createTestEnvironment(
         mergeConfig(testConfig(), {
-            plugins: [DefaultSearchPlugin.init({indexStockStatus: true}), DefaultJobQueuePlugin],
+            plugins: [DefaultSearchPlugin.init({ indexStockStatus: true }), DefaultJobQueuePlugin],
         }),
     );
 
@@ -279,7 +278,7 @@ describe('Default search plugin', () => {
             {
                 input: {
                     groupByProduct: true,
-                    facetValueFilters: [{and: 'T_1'}, {and: 'T_2'}],
+                    facetValueFilters: [{ and: 'T_1' }, { and: 'T_2' }],
                 },
             },
         );
@@ -299,7 +298,7 @@ describe('Default search plugin', () => {
             {
                 input: {
                     groupByProduct: true,
-                    facetValueFilters: [{or: ['T_1', 'T_5']}],
+                    facetValueFilters: [{ or: ['T_1', 'T_5'] }],
                 },
             },
         );
@@ -326,7 +325,7 @@ describe('Default search plugin', () => {
             {
                 input: {
                     groupByProduct: true,
-                    facetValueFilters: [{and: 'T_1'}, {or: ['T_2', 'T_3']}],
+                    facetValueFilters: [{ and: 'T_1' }, { or: ['T_2', 'T_3'] }],
                 },
             },
         );
@@ -351,7 +350,7 @@ describe('Default search plugin', () => {
                 input: {
                     facetValueIds: ['T_2', 'T_3'],
                     facetValueOperator: LogicalOperator.OR,
-                    facetValueFilters: [{and: 'T_1'}],
+                    facetValueFilters: [{ and: 'T_1' }],
                     groupByProduct: true,
                 },
             },
@@ -376,7 +375,7 @@ describe('Default search plugin', () => {
             {
                 input: {
                     facetValueIds: ['T_1'],
-                    facetValueFilters: [{and: 'T_3'}],
+                    facetValueFilters: [{ and: 'T_3' }],
                     facetValueOperator: LogicalOperator.AND,
                     groupByProduct: true,
                 },
@@ -436,16 +435,16 @@ describe('Default search plugin', () => {
         );
         expect(result.search.items).toEqual([
             {
-                price: {value: 129900},
-                priceWithTax: {value: 155880},
+                price: { value: 129900 },
+                priceWithTax: { value: 155880 },
             },
             {
-                price: {value: 139900},
-                priceWithTax: {value: 167880},
+                price: { value: 139900 },
+                priceWithTax: { value: 167880 },
             },
             {
-                price: {value: 219900},
-                priceWithTax: {value: 263880},
+                price: { value: 219900 },
+                priceWithTax: { value: 263880 },
             },
         ]);
     }
@@ -462,16 +461,16 @@ describe('Default search plugin', () => {
         );
         expect(result.search.items).toEqual([
             {
-                price: {min: 129900, max: 229900},
-                priceWithTax: {min: 155880, max: 275880},
+                price: { min: 129900, max: 229900 },
+                priceWithTax: { min: 155880, max: 275880 },
             },
             {
-                price: {min: 14374, max: 16994},
-                priceWithTax: {min: 17249, max: 20393},
+                price: { min: 14374, max: 16994 },
+                priceWithTax: { min: 17249, max: 20393 },
             },
             {
-                price: {min: 93120, max: 109995},
-                priceWithTax: {min: 111744, max: 131994},
+                price: { min: 93120, max: 109995 },
+                priceWithTax: { min: 111744, max: 131994 },
             },
         ]);
     }
@@ -519,12 +518,12 @@ describe('Default search plugin', () => {
                 },
             );
             expect(result.search.facetValues).toEqual([
-                {count: 21, facetValue: {id: 'T_1', name: 'electronics'}},
-                {count: 17, facetValue: {id: 'T_2', name: 'computers'}},
-                {count: 4, facetValue: {id: 'T_3', name: 'photo'}},
-                {count: 10, facetValue: {id: 'T_4', name: 'sports equipment'}},
-                {count: 3, facetValue: {id: 'T_5', name: 'home & garden'}},
-                {count: 3, facetValue: {id: 'T_6', name: 'plants'}},
+                { count: 21, facetValue: { id: 'T_1', name: 'electronics' } },
+                { count: 17, facetValue: { id: 'T_2', name: 'computers' } },
+                { count: 4, facetValue: { id: 'T_3', name: 'photo' } },
+                { count: 10, facetValue: { id: 'T_4', name: 'sports equipment' } },
+                { count: 3, facetValue: { id: 'T_5', name: 'home & garden' } },
+                { count: 3, facetValue: { id: 'T_6', name: 'plants' } },
             ]);
         });
 
@@ -538,12 +537,12 @@ describe('Default search plugin', () => {
                 },
             );
             expect(result.search.facetValues).toEqual([
-                {count: 10, facetValue: {id: 'T_1', name: 'electronics'}},
-                {count: 6, facetValue: {id: 'T_2', name: 'computers'}},
-                {count: 4, facetValue: {id: 'T_3', name: 'photo'}},
-                {count: 7, facetValue: {id: 'T_4', name: 'sports equipment'}},
-                {count: 3, facetValue: {id: 'T_5', name: 'home & garden'}},
-                {count: 3, facetValue: {id: 'T_6', name: 'plants'}},
+                { count: 10, facetValue: { id: 'T_1', name: 'electronics' } },
+                { count: 6, facetValue: { id: 'T_2', name: 'computers' } },
+                { count: 4, facetValue: { id: 'T_3', name: 'photo' } },
+                { count: 7, facetValue: { id: 'T_4', name: 'sports equipment' } },
+                { count: 3, facetValue: { id: 'T_5', name: 'home & garden' } },
+                { count: 3, facetValue: { id: 'T_6', name: 'plants' } },
             ]);
         });
 
@@ -559,23 +558,23 @@ describe('Default search plugin', () => {
                 },
             );
             expect(result.search.facetValues).toEqual([
-                {count: 4, facetValue: {id: 'T_1', name: 'electronics'}},
-                {count: 4, facetValue: {id: 'T_2', name: 'computers'}},
+                { count: 4, facetValue: { id: 'T_1', name: 'electronics' } },
+                { count: 4, facetValue: { id: 'T_2', name: 'computers' } },
             ]);
         });
 
         it('omits facetValues of private facets', async () => {
-            const {createFacet} = await adminClient.query<CreateFacet.Mutation, CreateFacet.Variables>(
+            const { createFacet } = await adminClient.query<CreateFacet.Mutation, CreateFacet.Variables>(
                 CREATE_FACET,
                 {
                     input: {
                         code: 'profit-margin',
                         isPrivate: true,
-                        translations: [{languageCode: LanguageCode.en, name: 'Profit Margin'}],
+                        translations: [{ languageCode: LanguageCode.en, name: 'Profit Margin' }],
                         values: [
                             {
                                 code: 'massive',
-                                translations: [{languageCode: LanguageCode.en, name: 'massive'}],
+                                translations: [{ languageCode: LanguageCode.en, name: 'massive' }],
                             },
                         ],
                     },
@@ -600,12 +599,12 @@ describe('Default search plugin', () => {
                 },
             );
             expect(result.search.facetValues).toEqual([
-                {count: 10, facetValue: {id: 'T_1', name: 'electronics'}},
-                {count: 6, facetValue: {id: 'T_2', name: 'computers'}},
-                {count: 4, facetValue: {id: 'T_3', name: 'photo'}},
-                {count: 7, facetValue: {id: 'T_4', name: 'sports equipment'}},
-                {count: 3, facetValue: {id: 'T_5', name: 'home & garden'}},
-                {count: 3, facetValue: {id: 'T_6', name: 'plants'}},
+                { count: 10, facetValue: { id: 'T_1', name: 'electronics' } },
+                { count: 6, facetValue: { id: 'T_2', name: 'computers' } },
+                { count: 4, facetValue: { id: 'T_3', name: 'photo' } },
+                { count: 7, facetValue: { id: 'T_4', name: 'sports equipment' } },
+                { count: 3, facetValue: { id: 'T_5', name: 'home & garden' } },
+                { count: 3, facetValue: { id: 'T_6', name: 'plants' } },
             ]);
         });
 
@@ -619,7 +618,7 @@ describe('Default search plugin', () => {
                 },
             );
             expect(result.search.collections).toEqual([
-                {collection: {id: 'T_2', name: 'Plants'}, count: 3},
+                { collection: { id: 'T_2', name: 'Plants' }, count: 3 },
             ]);
         });
 
@@ -633,7 +632,7 @@ describe('Default search plugin', () => {
                 },
             );
             expect(result.search.collections).toEqual([
-                {collection: {id: 'T_2', name: 'Plants'}, count: 3},
+                { collection: { id: 'T_2', name: 'Plants' }, count: 3 },
             ]);
         });
 
@@ -665,7 +664,7 @@ describe('Default search plugin', () => {
             await adminClient.query<UpdateProductVariants.Mutation, UpdateProductVariants.Variables>(
                 UPDATE_PRODUCT_VARIANTS,
                 {
-                    input: [{id: 'T_3', enabled: false}],
+                    input: [{ id: 'T_3', enabled: false }],
                 },
             );
             await awaitRunningJobs(adminClient);
@@ -819,7 +818,7 @@ describe('Default search plugin', () => {
         describe('updating the index', () => {
             it('updates index when ProductVariants are changed', async () => {
                 await awaitRunningJobs(adminClient);
-                const {search} = await doAdminSearchQuery({term: 'drive', groupByProduct: false});
+                const { search } = await doAdminSearchQuery({ term: 'drive', groupByProduct: false });
                 expect(search.items.map(i => i.sku)).toEqual([
                     'IHD455T1',
                     'IHD455T2',
@@ -839,7 +838,7 @@ describe('Default search plugin', () => {
                 );
 
                 await awaitRunningJobs(adminClient);
-                const {search: search2} = await doAdminSearchQuery({
+                const { search: search2 } = await doAdminSearchQuery({
                     term: 'drive',
                     groupByProduct: false,
                 });
@@ -855,7 +854,7 @@ describe('Default search plugin', () => {
 
             it('updates index when ProductVariants are deleted', async () => {
                 await awaitRunningJobs(adminClient);
-                const {search} = await doAdminSearchQuery({term: 'drive', groupByProduct: false});
+                const { search } = await doAdminSearchQuery({ term: 'drive', groupByProduct: false });
 
                 await adminClient.query<DeleteProductVariant.Mutation, DeleteProductVariant.Variables>(
                     DELETE_PRODUCT_VARIANT,
@@ -865,7 +864,7 @@ describe('Default search plugin', () => {
                 );
 
                 await awaitRunningJobs(adminClient);
-                const {search: search2} = await doAdminSearchQuery({
+                const { search: search2 } = await doAdminSearchQuery({
                     term: 'drive',
                     groupByProduct: false,
                 });
@@ -886,7 +885,7 @@ describe('Default search plugin', () => {
                     },
                 });
                 await awaitRunningJobs(adminClient);
-                const result = await doAdminSearchQuery({facetValueIds: ['T_2'], groupByProduct: true});
+                const result = await doAdminSearchQuery({ facetValueIds: ['T_2'], groupByProduct: true });
                 expect(result.search.items.map(i => i.productName)).toEqual([
                     'Curvy Monitor',
                     'Gaming PC',
@@ -897,13 +896,13 @@ describe('Default search plugin', () => {
             });
 
             it('updates index when a Product is deleted', async () => {
-                const {search} = await doAdminSearchQuery({facetValueIds: ['T_2'], groupByProduct: true});
+                const { search } = await doAdminSearchQuery({ facetValueIds: ['T_2'], groupByProduct: true });
                 expect(search.items.map(i => i.productId)).toEqual(['T_2', 'T_3', 'T_4', 'T_5', 'T_6']);
                 await adminClient.query<DeleteProduct.Mutation, DeleteProduct.Variables>(DELETE_PRODUCT, {
                     id: 'T_5',
                 });
                 await awaitRunningJobs(adminClient);
-                const {search: search2} = await doAdminSearchQuery({
+                const { search: search2 } = await doAdminSearchQuery({
                     facetValueIds: ['T_2'],
                     groupByProduct: true,
                 });
@@ -937,7 +936,7 @@ describe('Default search plugin', () => {
                 await awaitRunningJobs(adminClient);
                 // add an additional check for the collection filters to update
                 await awaitRunningJobs(adminClient);
-                const result1 = await doAdminSearchQuery({collectionId: 'T_2', groupByProduct: true});
+                const result1 = await doAdminSearchQuery({ collectionId: 'T_2', groupByProduct: true });
 
                 expect(result1.search.items.map(i => i.productName)).toEqual([
                     'Road Bike',
@@ -949,7 +948,7 @@ describe('Default search plugin', () => {
                     'Running Shoe',
                 ]);
 
-                const result2 = await doAdminSearchQuery({collectionSlug: 'plants', groupByProduct: true});
+                const result2 = await doAdminSearchQuery({ collectionSlug: 'plants', groupByProduct: true });
 
                 expect(result2.search.items.map(i => i.productName)).toEqual([
                     'Road Bike',
@@ -963,8 +962,10 @@ describe('Default search plugin', () => {
             }, 10000);
 
             it('updates index when a Collection created', async () => {
-                const {createCollection} = await adminClient.query<CreateCollection.Mutation,
-                    CreateCollection.Variables>(CREATE_COLLECTION, {
+                const { createCollection } = await adminClient.query<
+                    CreateCollection.Mutation,
+                    CreateCollection.Variables
+                >(CREATE_COLLECTION, {
                     input: {
                         translations: [
                             {
@@ -1027,8 +1028,8 @@ describe('Default search plugin', () => {
                 );
                 expect(result.search.items).toEqual([
                     {
-                        price: {min: 129900, max: 229900},
-                        priceWithTax: {min: 194850, max: 344850},
+                        price: { min: 129900, max: 229900 },
+                        priceWithTax: { min: 194850, max: 344850 },
                     },
                 ]);
             });
@@ -1047,7 +1048,7 @@ describe('Default search plugin', () => {
                 }
 
                 it('updates index when asset focalPoint is changed', async () => {
-                    const {search: search1} = await searchForLaptop();
+                    const { search: search1 } = await searchForLaptop();
 
                     expect(search1.items[0].productAsset!.id).toBe('T_1');
                     expect(search1.items[0].productAsset!.focalPoint).toBeNull();
@@ -1064,14 +1065,14 @@ describe('Default search plugin', () => {
 
                     await awaitRunningJobs(adminClient);
 
-                    const {search: search2} = await searchForLaptop();
+                    const { search: search2 } = await searchForLaptop();
 
                     expect(search2.items[0].productAsset!.id).toBe('T_1');
-                    expect(search2.items[0].productAsset!.focalPoint).toEqual({x: 0.42, y: 0.42});
+                    expect(search2.items[0].productAsset!.focalPoint).toEqual({ x: 0.42, y: 0.42 });
                 });
 
                 it('updates index when asset deleted', async () => {
-                    const {search: search1} = await searchForLaptop();
+                    const { search: search1 } = await searchForLaptop();
 
                     const assetId = search1.items[0].productAsset?.id;
                     expect(assetId).toBeTruthy();
@@ -1085,26 +1086,28 @@ describe('Default search plugin', () => {
 
                     await awaitRunningJobs(adminClient);
 
-                    const {search: search2} = await searchForLaptop();
+                    const { search: search2 } = await searchForLaptop();
 
                     expect(search2.items[0].productAsset).toBeNull();
                 });
             });
 
             it('does not include deleted ProductVariants in index', async () => {
-                const {search: s1} = await doAdminSearchQuery({
+                const { search: s1 } = await doAdminSearchQuery({
                     term: 'hard drive',
                     groupByProduct: false,
                 });
 
-                const {deleteProductVariant} = await adminClient.query<DeleteProductVariant.Mutation,
-                    DeleteProductVariant.Variables>(DELETE_PRODUCT_VARIANT, {id: s1.items[0].productVariantId});
+                const { deleteProductVariant } = await adminClient.query<
+                    DeleteProductVariant.Mutation,
+                    DeleteProductVariant.Variables
+                >(DELETE_PRODUCT_VARIANT, { id: s1.items[0].productVariantId });
 
                 await awaitRunningJobs(adminClient);
 
-                const {search} = await adminClient.query<SearchGetPrices.Query, SearchGetPrices.Variables>(
+                const { search } = await adminClient.query<SearchGetPrices.Query, SearchGetPrices.Variables>(
                     SEARCH_GET_PRICES,
-                    {input: {term: 'hard drive', groupByProduct: true}},
+                    { input: { term: 'hard drive', groupByProduct: true } },
                 );
                 expect(search.items[0].price).toEqual({
                     min: 7896,
@@ -1113,11 +1116,11 @@ describe('Default search plugin', () => {
             });
 
             it('returns enabled field when not grouped', async () => {
-                const result = await doAdminSearchQuery({groupByProduct: false, take: 3});
+                const result = await doAdminSearchQuery({ groupByProduct: false, take: 3 });
                 expect(result.search.items.map(pick(['productVariantId', 'enabled']))).toEqual([
-                    {productVariantId: 'T_1', enabled: true},
-                    {productVariantId: 'T_2', enabled: true},
-                    {productVariantId: 'T_3', enabled: false},
+                    { productVariantId: 'T_1', enabled: true },
+                    { productVariantId: 'T_2', enabled: true },
+                    { productVariantId: 'T_3', enabled: false },
                 ]);
             });
 
@@ -1126,17 +1129,17 @@ describe('Default search plugin', () => {
                     UPDATE_PRODUCT_VARIANTS,
                     {
                         input: [
-                            {id: 'T_1', enabled: false},
-                            {id: 'T_2', enabled: false},
+                            { id: 'T_1', enabled: false },
+                            { id: 'T_2', enabled: false },
                         ],
                     },
                 );
                 await awaitRunningJobs(adminClient);
-                const result = await doAdminSearchQuery({groupByProduct: true, take: 3});
+                const result = await doAdminSearchQuery({ groupByProduct: true, take: 3 });
                 expect(result.search.items.map(pick(['productId', 'enabled']))).toEqual([
-                    {productId: 'T_1', enabled: true},
-                    {productId: 'T_2', enabled: true},
-                    {productId: 'T_3', enabled: true},
+                    { productId: 'T_1', enabled: true },
+                    { productId: 'T_2', enabled: true },
+                    { productId: 'T_3', enabled: true },
                 ]);
             });
 
@@ -1144,15 +1147,15 @@ describe('Default search plugin', () => {
                 await adminClient.query<UpdateProductVariants.Mutation, UpdateProductVariants.Variables>(
                     UPDATE_PRODUCT_VARIANTS,
                     {
-                        input: [{id: 'T_4', enabled: false}],
+                        input: [{ id: 'T_4', enabled: false }],
                     },
                 );
                 await awaitRunningJobs(adminClient);
-                const result = await doAdminSearchQuery({groupByProduct: true, take: 3});
+                const result = await doAdminSearchQuery({ groupByProduct: true, take: 3 });
                 expect(result.search.items.map(pick(['productId', 'enabled']))).toEqual([
-                    {productId: 'T_1', enabled: false},
-                    {productId: 'T_2', enabled: true},
-                    {productId: 'T_3', enabled: true},
+                    { productId: 'T_1', enabled: false },
+                    { productId: 'T_2', enabled: true },
+                    { productId: 'T_3', enabled: true },
                 ]);
             });
 
@@ -1164,11 +1167,11 @@ describe('Default search plugin', () => {
                     },
                 });
                 await awaitRunningJobs(adminClient);
-                const result = await doAdminSearchQuery({groupByProduct: true, take: 3});
+                const result = await doAdminSearchQuery({ groupByProduct: true, take: 3 });
                 expect(result.search.items.map(pick(['productId', 'enabled']))).toEqual([
-                    {productId: 'T_1', enabled: false},
-                    {productId: 'T_2', enabled: true},
-                    {productId: 'T_3', enabled: false},
+                    { productId: 'T_1', enabled: false },
+                    { productId: 'T_2', enabled: true },
+                    { productId: 'T_3', enabled: false },
                 ]);
             });
 
@@ -1177,11 +1180,11 @@ describe('Default search plugin', () => {
                 await adminClient.query<Reindex.Mutation>(REINDEX);
 
                 await awaitRunningJobs(adminClient);
-                const result = await doAdminSearchQuery({groupByProduct: true, take: 3});
+                const result = await doAdminSearchQuery({ groupByProduct: true, take: 3 });
                 expect(result.search.items.map(pick(['productId', 'enabled']))).toEqual([
-                    {productId: 'T_1', enabled: false},
-                    {productId: 'T_2', enabled: true},
-                    {productId: 'T_3', enabled: false},
+                    { productId: 'T_1', enabled: false },
+                    { productId: 'T_2', enabled: true },
+                    { productId: 'T_3', enabled: false },
                 ]);
             });
 
@@ -1199,14 +1202,14 @@ describe('Default search plugin', () => {
                 );
                 expect(result1.search.items).toEqual([
                     {
-                        price: {min: 14374, max: 16994},
-                        priceWithTax: {min: 21561, max: 25491},
+                        price: { min: 14374, max: 16994 },
+                        priceWithTax: { min: 21561, max: 25491 },
                     },
                 ]);
                 await adminClient.query<UpdateProductVariants.Mutation, UpdateProductVariants.Variables>(
                     UPDATE_PRODUCT_VARIANTS,
                     {
-                        input: [{id: 'T_5', enabled: false}],
+                        input: [{ id: 'T_5', enabled: false }],
                     },
                 );
                 await awaitRunningJobs(adminClient);
@@ -1223,8 +1226,8 @@ describe('Default search plugin', () => {
                 );
                 expect(result2.search.items).toEqual([
                     {
-                        price: {min: 16994, max: 16994},
-                        priceWithTax: {min: 25491, max: 25491},
+                        price: { min: 16994, max: 16994 },
+                        priceWithTax: { min: 25491, max: 25491 },
                     },
                 ]);
             });
@@ -1234,12 +1237,14 @@ describe('Default search plugin', () => {
                 // We generate this long string out of random chars because Postgres uses compression
                 // when storing the string value, so e.g. a long series of a single character will not
                 // reproduce the error.
-                const description = Array.from({length: 220})
+                const description = Array.from({ length: 220 })
                     .map(() => Math.random().toString(36))
                     .join(' ');
 
-                const {createProduct} = await adminClient.query<CreateProduct.Mutation,
-                    CreateProduct.Variables>(CREATE_PRODUCT, {
+                const { createProduct } = await adminClient.query<
+                    CreateProduct.Mutation,
+                    CreateProduct.Variables
+                >(CREATE_PRODUCT, {
                     input: {
                         translations: [
                             {
@@ -1260,14 +1265,14 @@ describe('Default search plugin', () => {
                                 sku: 'VLD01',
                                 price: 100,
                                 translations: [
-                                    {languageCode: LanguageCode.en, name: 'Very long description variant'},
+                                    { languageCode: LanguageCode.en, name: 'Very long description variant' },
                                 ],
                             },
                         ],
                     },
                 );
                 await awaitRunningJobs(adminClient);
-                const result = await doAdminSearchQuery({term: 'aabbccdd'});
+                const result = await doAdminSearchQuery({ term: 'aabbccdd' });
                 expect(result.search.items.map(i => i.productName)).toEqual([
                     'Very long description aabbccdd',
                 ]);
@@ -1282,8 +1287,10 @@ describe('Default search plugin', () => {
             let createdProductId: string;
 
             it('creates synthetic index item for Product with no variants', async () => {
-                const {createProduct} = await adminClient.query<CreateProduct.Mutation,
-                    CreateProduct.Variables>(CREATE_PRODUCT, {
+                const { createProduct } = await adminClient.query<
+                    CreateProduct.Mutation,
+                    CreateProduct.Variables
+                >(CREATE_PRODUCT, {
                     input: {
                         facetValueIds: ['T_1'],
                         translations: [
@@ -1298,7 +1305,7 @@ describe('Default search plugin', () => {
                 });
 
                 await awaitRunningJobs(adminClient);
-                const result = await doAdminSearchQuery({groupByProduct: true, term: 'strawberry'});
+                const result = await doAdminSearchQuery({ groupByProduct: true, term: 'strawberry' });
                 expect(
                     result.search.items.map(
                         pick([
@@ -1324,24 +1331,26 @@ describe('Default search plugin', () => {
             });
 
             it('removes synthetic index item once a variant is created', async () => {
-                const {createProductVariants} = await adminClient.query<CreateProductVariants.Mutation,
-                    CreateProductVariants.Variables>(CREATE_PRODUCT_VARIANTS, {
+                const { createProductVariants } = await adminClient.query<
+                    CreateProductVariants.Mutation,
+                    CreateProductVariants.Variables
+                >(CREATE_PRODUCT_VARIANTS, {
                     input: [
                         {
                             productId: createdProductId,
                             sku: 'SC01',
                             price: 1399,
                             translations: [
-                                {languageCode: LanguageCode.en, name: 'Strawberry Cheesecake Pie'},
+                                { languageCode: LanguageCode.en, name: 'Strawberry Cheesecake Pie' },
                             ],
                         },
                     ],
                 });
                 await awaitRunningJobs(adminClient);
 
-                const result = await doAdminSearchQuery({groupByProduct: false, term: 'strawberry'});
+                const result = await doAdminSearchQuery({ groupByProduct: false, term: 'strawberry' });
                 expect(result.search.items.map(pick(['productVariantName']))).toEqual([
-                    {productVariantName: 'Strawberry Cheesecake Pie'},
+                    { productVariantName: 'Strawberry Cheesecake Pie' },
                 ]);
             });
         });
@@ -1351,8 +1360,10 @@ describe('Default search plugin', () => {
             let secondChannel: ChannelFragment;
 
             beforeAll(async () => {
-                const {createChannel} = await adminClient.query<CreateChannel.Mutation,
-                    CreateChannel.Variables>(CREATE_CHANNEL, {
+                const { createChannel } = await adminClient.query<
+                    CreateChannel.Mutation,
+                    CreateChannel.Variables
+                >(CREATE_CHANNEL, {
                     input: {
                         code: 'second-channel',
                         token: SECOND_CHANNEL_TOKEN,
@@ -1371,20 +1382,22 @@ describe('Default search plugin', () => {
                 await adminClient.query<AssignProductsToChannel.Mutation, AssignProductsToChannel.Variables>(
                     ASSIGN_PRODUCT_TO_CHANNEL,
                     {
-                        input: {channelId: secondChannel.id, productIds: ['T_1', 'T_2']},
+                        input: { channelId: secondChannel.id, productIds: ['T_1', 'T_2'] },
                     },
                 );
                 await awaitRunningJobs(adminClient);
 
                 adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
-                const {search} = await doAdminSearchQuery({groupByProduct: true});
+                const { search } = await doAdminSearchQuery({ groupByProduct: true });
                 expect(search.items.map(i => i.productId)).toEqual(['T_1', 'T_2']);
             }, 10000);
 
             it('removing product from channel', async () => {
                 adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
-                const {removeProductsFromChannel} = await adminClient.query<RemoveProductsFromChannel.Mutation,
-                    RemoveProductsFromChannel.Variables>(REMOVE_PRODUCT_FROM_CHANNEL, {
+                const { removeProductsFromChannel } = await adminClient.query<
+                    RemoveProductsFromChannel.Mutation,
+                    RemoveProductsFromChannel.Variables
+                >(REMOVE_PRODUCT_FROM_CHANNEL, {
                     input: {
                         productIds: ['T_2'],
                         channelId: secondChannel.id,
@@ -1393,24 +1406,26 @@ describe('Default search plugin', () => {
                 await awaitRunningJobs(adminClient);
 
                 adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
-                const {search} = await doAdminSearchQuery({groupByProduct: true});
+                const { search } = await doAdminSearchQuery({ groupByProduct: true });
                 expect(search.items.map(i => i.productId)).toEqual(['T_1']);
             }, 10000);
 
             it('adding product variant to channel', async () => {
                 adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
-                await adminClient.query<AssignProductVariantsToChannel.Mutation,
-                    AssignProductVariantsToChannel.Variables>(ASSIGN_PRODUCTVARIANT_TO_CHANNEL, {
-                    input: {channelId: secondChannel.id, productVariantIds: ['T_10', 'T_15']},
+                await adminClient.query<
+                    AssignProductVariantsToChannel.Mutation,
+                    AssignProductVariantsToChannel.Variables
+                >(ASSIGN_PRODUCTVARIANT_TO_CHANNEL, {
+                    input: { channelId: secondChannel.id, productVariantIds: ['T_10', 'T_15'] },
                 });
                 await awaitRunningJobs(adminClient);
 
                 adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
 
-                const {search: searchGrouped} = await doAdminSearchQuery({groupByProduct: true});
+                const { search: searchGrouped } = await doAdminSearchQuery({ groupByProduct: true });
                 expect(searchGrouped.items.map(i => i.productId)).toEqual(['T_1', 'T_3', 'T_4']);
 
-                const {search: searchUngrouped} = await doAdminSearchQuery({groupByProduct: false});
+                const { search: searchUngrouped } = await doAdminSearchQuery({ groupByProduct: false });
                 expect(searchUngrouped.items.map(i => i.productVariantId)).toEqual([
                     'T_1',
                     'T_2',
@@ -1423,18 +1438,20 @@ describe('Default search plugin', () => {
 
             it('removing product variant from channel', async () => {
                 adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
-                await adminClient.query<RemoveProductVariantsFromChannel.Mutation,
-                    RemoveProductVariantsFromChannel.Variables>(REMOVE_PRODUCTVARIANT_FROM_CHANNEL, {
-                    input: {channelId: secondChannel.id, productVariantIds: ['T_1', 'T_15']},
+                await adminClient.query<
+                    RemoveProductVariantsFromChannel.Mutation,
+                    RemoveProductVariantsFromChannel.Variables
+                >(REMOVE_PRODUCTVARIANT_FROM_CHANNEL, {
+                    input: { channelId: secondChannel.id, productVariantIds: ['T_1', 'T_15'] },
                 });
                 await awaitRunningJobs(adminClient);
 
                 adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
 
-                const {search: searchGrouped} = await doAdminSearchQuery({groupByProduct: true});
+                const { search: searchGrouped } = await doAdminSearchQuery({ groupByProduct: true });
                 expect(searchGrouped.items.map(i => i.productId)).toEqual(['T_1', 'T_3']);
 
-                const {search: searchUngrouped} = await doAdminSearchQuery({groupByProduct: false});
+                const { search: searchUngrouped } = await doAdminSearchQuery({ groupByProduct: false });
                 expect(searchUngrouped.items.map(i => i.productVariantId)).toEqual([
                     'T_2',
                     'T_3',
@@ -1445,18 +1462,20 @@ describe('Default search plugin', () => {
 
             it('updating product affects current channel', async () => {
                 adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
-                const {updateProduct} = await adminClient.query<UpdateProduct.Mutation,
-                    UpdateProduct.Variables>(UPDATE_PRODUCT, {
+                const { updateProduct } = await adminClient.query<
+                    UpdateProduct.Mutation,
+                    UpdateProduct.Variables
+                >(UPDATE_PRODUCT, {
                     input: {
                         id: 'T_3',
                         enabled: true,
-                        translations: [{languageCode: LanguageCode.en, name: 'xyz'}],
+                        translations: [{ languageCode: LanguageCode.en, name: 'xyz' }],
                     },
                 });
 
                 await awaitRunningJobs(adminClient);
 
-                const {search: searchGrouped} = await doAdminSearchQuery({
+                const { search: searchGrouped } = await doAdminSearchQuery({
                     groupByProduct: true,
                     term: 'xyz',
                 });
@@ -1465,7 +1484,7 @@ describe('Default search plugin', () => {
 
             it('updating product affects other channels', async () => {
                 adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
-                const {search: searchGrouped} = await doAdminSearchQuery({
+                const { search: searchGrouped } = await doAdminSearchQuery({
                     groupByProduct: true,
                     term: 'xyz',
                 });
@@ -1499,20 +1518,22 @@ describe('Default search plugin', () => {
                 await adminClient.query<AssignProductsToChannel.Mutation, AssignProductsToChannel.Variables>(
                     ASSIGN_PRODUCT_TO_CHANNEL,
                     {
-                        input: {channelId: secondChannel.id, productIds: ['T_4']},
+                        input: { channelId: secondChannel.id, productIds: ['T_4'] },
                     },
                 );
                 await awaitRunningJobs(adminClient);
 
                 async function searchSecondChannelForDEProduct() {
                     adminClient.setChannelToken(SECOND_CHANNEL_TOKEN);
-                    const {search} = await adminClient.query<SearchProductsShop.Query,
-                        SearchProductShopVariables>(
+                    const { search } = await adminClient.query<
+                        SearchProductsShop.Query,
+                        SearchProductShopVariables
+                    >(
                         SEARCH_PRODUCTS,
                         {
-                            input: {term: 'product', groupByProduct: true},
+                            input: { term: 'product', groupByProduct: true },
                         },
-                        {languageCode: LanguageCode.de},
+                        { languageCode: LanguageCode.de },
                     );
                     return search;
                 }
@@ -1521,8 +1542,10 @@ describe('Default search plugin', () => {
                 expect(search1.items.map(i => i.productName)).toEqual(['product de']);
 
                 adminClient.setChannelToken(E2E_DEFAULT_CHANNEL_TOKEN);
-                const {removeProductsFromChannel} = await adminClient.query<RemoveProductsFromChannel.Mutation,
-                    RemoveProductsFromChannel.Variables>(REMOVE_PRODUCT_FROM_CHANNEL, {
+                const { removeProductsFromChannel } = await adminClient.query<
+                    RemoveProductsFromChannel.Mutation,
+                    RemoveProductsFromChannel.Variables
+                >(REMOVE_PRODUCT_FROM_CHANNEL, {
                     input: {
                         productIds: ['T_4'],
                         channelId: secondChannel.id,
@@ -1551,8 +1574,10 @@ describe('Default search plugin', () => {
             }
 
             beforeAll(async () => {
-                const {updateProduct} = await adminClient.query<UpdateProduct.Mutation,
-                    UpdateProduct.Variables>(UPDATE_PRODUCT, {
+                const { updateProduct } = await adminClient.query<
+                    UpdateProduct.Mutation,
+                    UpdateProduct.Variables
+                >(UPDATE_PRODUCT, {
                     input: {
                         id: 'T_1',
                         translations: [
@@ -1593,21 +1618,21 @@ describe('Default search plugin', () => {
             });
 
             it('fallbacks to default language', async () => {
-                const { search } = await searchInLanguage(LanguageCode.af)
+                const { search } = await searchInLanguage(LanguageCode.af);
                 // No records for AF language, but we expect > 0
                 // because of fallback to default language (EN)
                 expect(search.totalItems).toBeGreaterThan(0);
-            })
+            });
 
             it('indexes product-level languages', async () => {
-                const {search: search1} = await searchInLanguage(LanguageCode.de);
+                const { search: search1 } = await searchInLanguage(LanguageCode.de);
 
                 expect(search1.items.map(i => i.productName)).toContain('laptop name de');
-                expect(search1.items.map(i => i.productName)).not.toContain('laptop name zh')
+                expect(search1.items.map(i => i.productName)).not.toContain('laptop name zh');
                 expect(search1.items.map(i => i.slug)).toContain('laptop-slug-de');
                 expect(search1.items.map(i => i.description)).toContain('laptop description de');
 
-                const {search: search2} = await searchInLanguage(LanguageCode.zh);
+                const { search: search2 } = await searchInLanguage(LanguageCode.zh);
 
                 expect(search2.items.map(i => i.productName)).toContain('laptop name zh');
                 expect(search2.items.map(i => i.productName)).not.toContain('laptop name de');
@@ -1616,11 +1641,31 @@ describe('Default search plugin', () => {
             });
 
             it('indexes product variant-level languages', async () => {
-                const {search: search1} = await searchInLanguage(LanguageCode.fr);
+                const { search: search1 } = await searchInLanguage(LanguageCode.fr);
 
                 expect(search1.items.map(i => i.productName)).toContain('Laptop');
                 expect(search1.items.map(i => i.productVariantName)).toContain('laptop variant fr');
             });
+
+            // https://github.com/vendure-ecommerce/vendure/issues/1752
+            // https://github.com/vendure-ecommerce/vendure/issues/1746
+            it('sort by name with non-default languageCode', async () => {
+                const result = await adminClient.query<SearchProductsShop.Query, SearchProductShopVariables>(
+                    SEARCH_PRODUCTS,
+                    {
+                        input: {
+                            take: 2,
+                            sort: {
+                                name: SortOrder.ASC,
+                            },
+                        },
+                    },
+                    {
+                        languageCode: LanguageCode.de,
+                    },
+                );
+                expect(result.search.items.length).toEqual(2);
+            });
         });
     });
 });

+ 4 - 4
packages/core/src/plugin/default-search-plugin/search-strategy/mysql-search-strategy.ts

@@ -98,10 +98,10 @@ export class MysqlSearchStrategy implements SearchStrategy {
         this.applyTermAndFilters(ctx, qb, input);
         if (sort) {
             if (sort.name) {
-                qb.addOrderBy(input.groupByProduct ? 'MIN(si.productName)' : 'productName', sort.name);
+                qb.addOrderBy(input.groupByProduct ? 'MIN(si.productName)' : 'si.productName', sort.name);
             }
             if (sort.price) {
-                qb.addOrderBy(input.groupByProduct ? 'MIN(si.price)' : 'price', sort.price);
+                qb.addOrderBy(input.groupByProduct ? 'MIN(si.price)' : 'si.price', sort.price);
             }
         } else {
             if (input.term && input.term.length > this.minTermLength) {
@@ -113,8 +113,8 @@ export class MysqlSearchStrategy implements SearchStrategy {
         }
 
         return qb
-            .take(take)
-            .skip(skip)
+            .limit(take)
+            .offset(skip)
             .getRawMany()
             .then(res => res.map(r => mapToSearchResult(r, ctx.channel.currencyCode)));
     }

+ 3 - 3
packages/core/src/plugin/default-search-plugin/search-strategy/postgres-search-strategy.ts

@@ -116,8 +116,8 @@ export class PostgresSearchStrategy implements SearchStrategy {
         }
 
         return qb
-            .take(take)
-            .skip(skip)
+            .limit(take)
+            .offset(skip)
             .getRawMany()
             .then(res => res.map(r => mapToSearchResult(r, ctx.channel.currencyCode)));
     }
@@ -244,7 +244,7 @@ export class PostgresSearchStrategy implements SearchStrategy {
                 collectionSlug,
             });
         }
-        
+
         applyLanguageConstraints(qb, ctx.languageCode, ctx.channel.defaultLanguageCode);
         qb.andWhere('si.channelId = :channelId', { channelId: ctx.channelId });
         if (input.groupByProduct === true) {

+ 15 - 10
packages/core/src/plugin/default-search-plugin/search-strategy/search-strategy-utils.ts

@@ -10,7 +10,9 @@ import {
 import { ID } from '@vendure/common/lib/shared-types';
 import { unique } from '@vendure/common/lib/unique';
 import { QueryBuilder, SelectQueryBuilder } from 'typeorm';
+
 import { SearchIndexItem } from '../entities/search-index-item.entity';
+
 import { identifierFields } from './search-strategy-common';
 
 /**
@@ -117,7 +119,7 @@ export function createPlaceholderFromId(id: ID): string {
 
 /**
  * Applies language constraints for {@link SearchIndexItem} query.
- * 
+ *
  * @param qb QueryBuilder instance
  * @param languageCode Preferred language code
  * @param defaultLanguageCode Default language code that is used if {@link SearchIndexItem} is not available in preferred language
@@ -127,24 +129,27 @@ export function applyLanguageConstraints(
     languageCode: LanguageCode,
     defaultLanguageCode: LanguageCode,
 ) {
-    if (languageCode == defaultLanguageCode) {
-        qb.andWhere('si.languageCode = :languageCode', { languageCode: languageCode });
+    if (languageCode === defaultLanguageCode) {
+        qb.andWhere('si.languageCode = :languageCode', { languageCode });
     } else {
         qb.andWhere('si.languageCode IN (:...languageCodes)', {
             languageCodes: [languageCode, defaultLanguageCode],
         });
 
-        const joinFieldConditions = identifierFields
-            .map(field => `si.${field} = sil.${field}`)
-            .join(' AND ');
+        const joinFieldConditions = identifierFields.map(field => `si.${field} = sil.${field}`).join(' AND ');
 
-        qb.leftJoin(SearchIndexItem, 'sil', `
+        qb.leftJoin(
+            SearchIndexItem,
+            'sil',
+            `
             ${joinFieldConditions}
             AND si.languageCode != sil.languageCode
             AND sil.languageCode = :languageCode
-        `, {
-            languageCode: languageCode,
-        });
+        `,
+            {
+                languageCode,
+            },
+        );
 
         qb.andWhere('sil.languageCode IS NULL');
     }

+ 3 - 6
packages/core/src/plugin/default-search-plugin/search-strategy/sqlite-search-strategy.ts

@@ -112,13 +112,10 @@ export class SqliteSearchStrategy implements SearchStrategy {
         }
 
         return await qb
-            .take(take)
-            .skip(skip)
+            .limit(take)
+            .offset(skip)
             .getRawMany()
-            .then(res => {
-                // console.warn(qb.getQueryAndParameters(), "take", take, "skip", skip, "length", res.length)
-                return res.map(r => mapToSearchResult(r, ctx.channel.currencyCode))
-            });
+            .then(res => res.map(r => mapToSearchResult(r, ctx.channel.currencyCode)));
     }
 
     async getTotalCount(ctx: RequestContext, input: SearchInput, enabledOnly: boolean): Promise<number> {