Browse Source

fix(elasticsearch-plugin): Correctly update index on variant deletion

Fixes #266
Michael Bromley 6 years ago
parent
commit
8b91a592eb

+ 34 - 3
packages/elasticsearch-plugin/e2e/elasticsearch-plugin.e2e-spec.ts

@@ -441,7 +441,7 @@ describe('Elasticsearch plugin', () => {
                     groupByProduct: false,
                 });
 
-                expect(search2.items.map(i => i.sku)).toEqual([
+                expect(search2.items.map(i => i.sku).sort()).toEqual([
                     'IHD455T2_updated',
                     'IHD455T3_updated',
                     'IHD455T4_updated',
@@ -469,7 +469,13 @@ describe('Elasticsearch plugin', () => {
 
             it('updates index when a Product is deleted', async () => {
                 const { search } = await doAdminSearchQuery({ facetValueIds: ['T_2'], groupByProduct: true });
-                expect(search.items.map(i => i.productId)).toEqual(['T_3', 'T_5', 'T_6', 'T_2', 'T_4']);
+                expect(search.items.map(i => i.productId).sort()).toEqual([
+                    'T_2',
+                    'T_3',
+                    'T_4',
+                    'T_5',
+                    'T_6',
+                ]);
                 await adminClient.query<DeleteProduct.Mutation, DeleteProduct.Variables>(DELETE_PRODUCT, {
                     id: 'T_5',
                 });
@@ -478,7 +484,7 @@ describe('Elasticsearch plugin', () => {
                     facetValueIds: ['T_2'],
                     groupByProduct: true,
                 });
-                expect(search2.items.map(i => i.productId)).toEqual(['T_3', 'T_6', 'T_2', 'T_4']);
+                expect(search2.items.map(i => i.productId).sort()).toEqual(['T_2', 'T_3', 'T_4', 'T_6']);
             });
 
             it('updates index when a Collection is changed', async () => {
@@ -631,6 +637,31 @@ describe('Elasticsearch plugin', () => {
                 expect(search2.items[0].productAsset!.focalPoint).toEqual({ x: 0.42, y: 0.42 });
             });
 
+            it('does not include deleted ProductVariants in index', async () => {
+                const { search: s1 } = await doAdminSearchQuery({
+                    term: 'hard drive',
+                    groupByProduct: false,
+                });
+
+                const variantToDelete = s1.items.find(i => i.sku === 'IHD455T2_updated')!;
+
+                const { deleteProductVariant } = await adminClient.query<
+                    DeleteProductVariant.Mutation,
+                    DeleteProductVariant.Variables
+                >(DELETE_PRODUCT_VARIANT, { id: variantToDelete.productVariantId });
+
+                await awaitRunningJobs(adminClient);
+
+                const { search } = await adminClient.query<SearchGetPrices.Query, SearchGetPrices.Variables>(
+                    SEARCH_GET_PRICES,
+                    { input: { term: 'hard drive', groupByProduct: true } },
+                );
+                expect(search.items[0].price).toEqual({
+                    min: 7896,
+                    max: 13435,
+                });
+            });
+
             it('returns disabled field when not grouped', async () => {
                 const result = await doAdminSearchQuery({ groupByProduct: false, term: 'laptop' });
                 expect(result.search.items.map(pick(['productVariantId', 'enabled']))).toEqual([

+ 20 - 3
packages/elasticsearch-plugin/src/indexer.controller.ts

@@ -182,6 +182,13 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
     }: DeleteVariantMessage['data']): Observable<DeleteVariantMessage['response']> {
         const ctx = RequestContext.fromObject(rawContext);
         return asyncObservable(async () => {
+            const variants = await this.connection
+                .getRepository(ProductVariant)
+                .findByIds(variantIds, { relations: ['product'] });
+            const productIds = unique(variants.map(v => v.product.id));
+            for (const productId of productIds) {
+                await this.updateProductInternal(ctx, productId, ctx.channelId);
+            }
             await this.deleteVariantsInternal(variantIds, ctx.channelId);
             return true;
         });
@@ -262,7 +269,7 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
                 }
 
                 const qb = this.getSearchIndexQueryBuilder(ctx.channelId);
-                const count = await qb.andWhere('variants__product.deletedAt IS NULL').getCount();
+                const count = await qb.getCount();
                 Logger.verbose(`Reindexing ${count} ProductVariants`, loggerCtx);
 
                 const batches = Math.ceil(count / batchSize);
@@ -403,6 +410,9 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
 
         const productVariants = await this.connection.getRepository(ProductVariant).findByIds(variantIds, {
             relations: variantRelations,
+            where: {
+                deletedAt: null,
+            },
             order: {
                 id: 'ASC',
             },
@@ -441,6 +451,9 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
                 .getRepository(ProductVariant)
                 .findByIds(product.variants.map(v => v.id), {
                     relations: variantRelations,
+                    where: {
+                        deletedAt: null,
+                    },
                 });
             if (product.enabled === false) {
                 updatedProductVariants.forEach(v => (v.enabled = false));
@@ -526,7 +539,9 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
         FindOptionsUtils.joinEagerRelations(qb, qb.alias, this.connection.getMetadata(ProductVariant));
         qb.leftJoin('variants.product', '__product')
             .leftJoin('__product.channels', '__channel')
-            .where('__channel.id = :channelId', { channelId });
+            .where('__channel.id = :channelId', { channelId })
+            .andWhere('variants__product.deletedAt IS NULL')
+            .andWhere('variants.deletedAt IS NULL');
         return qb;
     }
 
@@ -538,7 +553,6 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
         const { batchSize } = this.options;
         const i = Number.parseInt(batchNumber.toString(), 10);
         const variants = await qb
-            .andWhere('variants__product.deletedAt IS NULL')
             .take(batchSize)
             .skip(i * batchSize)
             .addOrderBy('variants.id', 'ASC')
@@ -550,6 +564,9 @@ export class ElasticsearchIndexerController implements OnModuleInit, OnModuleDes
     private async getVariantsByIds(ctx: RequestContext, ids: ID[]) {
         const variants = await this.connection.getRepository(ProductVariant).findByIds(ids, {
             relations: variantRelations,
+            where: {
+                deletedAt: null,
+            },
             order: {
                 id: 'ASC',
             },