diff --git a/packages/core/e2e/default-search-plugin.e2e-spec.ts b/packages/core/e2e/default-search-plugin.e2e-spec.ts index 8915bb26db..67d76170c9 100644 --- a/packages/core/e2e/default-search-plugin.e2e-spec.ts +++ b/packages/core/e2e/default-search-plugin.e2e-spec.ts @@ -48,7 +48,7 @@ describe('Default search plugin', () => { }); async function testGroupByProduct(client: SimpleGraphQLClient) { - const result = await client.query(SEARCH_PRODUCTS, { + const result = await client.query(SEARCH_PRODUCTS_SHOP, { input: { groupByProduct: true, }, @@ -57,7 +57,7 @@ describe('Default search plugin', () => { } async function testNoGrouping(client: SimpleGraphQLClient) { - const result = await client.query(SEARCH_PRODUCTS, { + const result = await client.query(SEARCH_PRODUCTS_SHOP, { input: { groupByProduct: false, }, @@ -66,7 +66,7 @@ describe('Default search plugin', () => { } async function testMatchSearchTerm(client: SimpleGraphQLClient) { - const result = await client.query(SEARCH_PRODUCTS, { + const result = await client.query(SEARCH_PRODUCTS_SHOP, { input: { term: 'camera', groupByProduct: true, @@ -80,7 +80,7 @@ describe('Default search plugin', () => { } async function testMatchFacetIds(client: SimpleGraphQLClient) { - const result = await client.query(SEARCH_PRODUCTS, { + const result = await client.query(SEARCH_PRODUCTS_SHOP, { input: { facetIds: ['T_1', 'T_2'], groupByProduct: true, @@ -97,7 +97,7 @@ describe('Default search plugin', () => { } async function testMatchCollectionId(client: SimpleGraphQLClient) { - const result = await client.query(SEARCH_PRODUCTS, { + const result = await client.query(SEARCH_PRODUCTS_SHOP, { input: { collectionId: 'T_2', groupByProduct: true, @@ -204,7 +204,7 @@ describe('Default search plugin', () => { }); it('encodes the productId and productVariantId', async () => { - const result = await shopClient.query(SEARCH_PRODUCTS, { + const result = await shopClient.query(SEARCH_PRODUCTS_SHOP, { input: { groupByProduct: false, take: 1, @@ -224,7 +224,7 @@ describe('Default search plugin', () => { { id: 'T_3', enabled: false }, ], }); - const result = await shopClient.query(SEARCH_PRODUCTS, { + const result = await shopClient.query(SEARCH_PRODUCTS_SHOP, { input: { groupByProduct: false, take: 3, @@ -384,9 +384,99 @@ describe('Default search plugin', () => { }, ]); }); + + it('returns disabled field when not grouped', async () => { + const result = await adminClient.query(SEARCH_PRODUCTS, { + input: { + 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 }, + ]); + }); + + it('when grouped, disabled is false if at least one variant is enabled', async () => { + await adminClient.query(UPDATE_PRODUCT_VARIANTS, { + input: [ + { id: 'T_1', enabled: false }, + { id: 'T_2', enabled: false }, + ], + }); + const result = await adminClient.query(SEARCH_PRODUCTS, { + input: { + 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 }, + ]); + }); + + it('when grouped, disabled is true if all variants are disabled', async () => { + await adminClient.query(UPDATE_PRODUCT_VARIANTS, { + input: [ + { id: 'T_4', enabled: false }, + ], + }); + const result = await adminClient.query(SEARCH_PRODUCTS, { + input: { + 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 }, + ]); + }); + + it('when grouped, disabled is true product is disabled', async () => { + await adminClient.query(UPDATE_PRODUCT, { + input: { + id: 'T_3', + enabled: false, + }, + }); + const result = await adminClient.query(SEARCH_PRODUCTS, { + input: { + 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 }, + ]); + }); }); }); +export const SEARCH_PRODUCTS_SHOP = gql` + query SearchProducts($input: SearchInput!) { + search(input: $input) { + totalItems + items { + productId + productName + productPreview + productVariantId + productVariantName + productVariantPreview + sku + } + } + } +`; + export const SEARCH_GET_FACET_VALUES = gql` query SearchProducts($input: SearchInput!) { search(input: $input) { diff --git a/packages/core/src/plugin/default-search-plugin/fulltext-search.service.ts b/packages/core/src/plugin/default-search-plugin/fulltext-search.service.ts index 8a9b1c199c..4050ac2031 100644 --- a/packages/core/src/plugin/default-search-plugin/fulltext-search.service.ts +++ b/packages/core/src/plugin/default-search-plugin/fulltext-search.service.ts @@ -124,6 +124,9 @@ export class FulltextSearchService implements SearchService { .findByIds(product.variants.map(v => v.id), { relations: this.variantRelations, }); + if (product.enabled === false) { + updatedVariants.forEach(v => v.enabled = false); + } } } } else { diff --git a/packages/core/src/plugin/default-search-plugin/search-strategy/postgres-search-strategy.ts b/packages/core/src/plugin/default-search-plugin/search-strategy/postgres-search-strategy.ts index d4a6f4cee4..8d53ea4b53 100644 --- a/packages/core/src/plugin/default-search-plugin/search-strategy/postgres-search-strategy.ts +++ b/packages/core/src/plugin/default-search-plugin/search-strategy/postgres-search-strategy.ts @@ -63,7 +63,7 @@ export class PostgresSearchStrategy implements SearchStrategy { } } if (enabledOnly) { - qb.andWhere('"si"."enabled" = :enabled', { enabled: true }); + qb.andWhere('"si_enabled" = :enabled', { enabled: true }); } return qb @@ -82,7 +82,7 @@ export class PostgresSearchStrategy implements SearchStrategy { input, ); if (enabledOnly) { - innerQb.andWhere('"si"."enabled" = :enabled', { enabled: true }); + innerQb.andWhere('"si_enabled" = :enabled', { enabled: true }); } const totalItemsQb = this.connection .createQueryBuilder() @@ -151,6 +151,7 @@ export class PostgresSearchStrategy implements SearchStrategy { private createPostgresSelect(groupByProduct: boolean): string { return [ 'sku', + 'enabled', 'slug', 'price', 'priceWithTax', @@ -172,6 +173,8 @@ export class PostgresSearchStrategy implements SearchStrategy { if (groupByProduct && col !== 'productId') { if (col === 'facetIds' || col === 'facetValueIds' || col === 'collectionIds') { return `string_agg(${qualifiedName}, ',') as "${alias}"`; + } else if (col === 'enabled') { + return `bool_or(${qualifiedName}) as "${alias}"`; } else { return `MIN(${qualifiedName}) as "${alias}"`; }