Răsfoiți Sursa

perf(core): Cache certain field resolvers to avoid duplicated DB calls

Fixes #1119
Michael Bromley 4 ani în urmă
părinte
comite
13697c3589

+ 3 - 1
packages/core/src/api/api-internal-modules.ts

@@ -1,5 +1,6 @@
 import { Module } from '@nestjs/common';
 
+import { CacheModule } from '../cache/cache.module';
 import { ConfigModule } from '../config/config.module';
 import { DataImportModule } from '../data-import/data-import.module';
 import { JobQueueModule } from '../job-queue/job-queue.module';
@@ -152,10 +153,11 @@ export const adminEntityResolvers = [
  * one API module.
  */
 @Module({
-    imports: [ConfigModule, ServiceModule.forRoot()],
+    imports: [ConfigModule, ServiceModule.forRoot(), CacheModule],
     providers: [IdCodecService, ConfigurableOperationCodec, CustomFieldRelationResolverService],
     exports: [
         IdCodecService,
+        CacheModule,
         ConfigModule,
         ConfigurableOperationCodec,
         CustomFieldRelationResolverService,

+ 5 - 1
packages/core/src/api/resolvers/entity/facet-entity.resolver.ts

@@ -1,5 +1,6 @@
 import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
 
+import { RequestContextCacheService } from '../../../cache/request-context-cache.service';
 import { FacetValue } from '../../../entity/facet-value/facet-value.entity';
 import { Facet } from '../../../entity/facet/facet.entity';
 import { LocaleStringHydrator } from '../../../service/helpers/locale-string-hydrator/locale-string-hydrator';
@@ -12,6 +13,7 @@ export class FacetEntityResolver {
     constructor(
         private facetValueService: FacetValueService,
         private localeStringHydrator: LocaleStringHydrator,
+        private requestContextCache: RequestContextCacheService,
     ) {}
 
     @ResolveField()
@@ -24,6 +26,8 @@ export class FacetEntityResolver {
         if (facet.values) {
             return facet.values;
         }
-        return this.facetValueService.findByFacetId(ctx, facet.id);
+        return this.requestContextCache.get(ctx, `FacetEntityResolver.values(${facet.id})`, () =>
+            this.facetValueService.findByFacetId(ctx, facet.id),
+        );
     }
 }

+ 9 - 2
packages/core/src/api/resolvers/entity/facet-value-entity.resolver.ts

@@ -1,5 +1,6 @@
 import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
 
+import { RequestContextCacheService } from '../../../cache/request-context-cache.service';
 import { FacetValue } from '../../../entity/facet-value/facet-value.entity';
 import { Facet } from '../../../entity/facet/facet.entity';
 import { LocaleStringHydrator } from '../../../service/helpers/locale-string-hydrator/locale-string-hydrator';
@@ -9,7 +10,11 @@ import { Ctx } from '../../decorators/request-context.decorator';
 
 @Resolver('FacetValue')
 export class FacetValueEntityResolver {
-    constructor(private facetService: FacetService, private localeStringHydrator: LocaleStringHydrator) {}
+    constructor(
+        private facetService: FacetService,
+        private localeStringHydrator: LocaleStringHydrator,
+        private requestContextCache: RequestContextCacheService,
+    ) {}
 
     @ResolveField()
     name(@Ctx() ctx: RequestContext, @Parent() facetValue: FacetValue): Promise<string> {
@@ -21,6 +26,8 @@ export class FacetValueEntityResolver {
         if (facetValue.facet) {
             return facetValue.facet;
         }
-        return this.facetService.findByFacetValueId(ctx, facetValue.id);
+        return this.requestContextCache.get(ctx, `FacetValueEntityResolver.facet(${facetValue.id})`, () =>
+            this.facetService.findByFacetValueId(ctx, facetValue.id),
+        );
     }
 }

+ 0 - 1
packages/core/src/api/resolvers/entity/product-entity.resolver.ts

@@ -72,7 +72,6 @@ export class ProductEntityResolver {
         @Ctx() ctx: RequestContext,
         @Parent() product: Product,
     ): Promise<Array<Translated<ProductOptionGroup>>> {
-        const a = info;
         return this.productOptionGroupService.getOptionGroupsByProductId(ctx, product.id);
     }
 

+ 5 - 1
packages/core/src/api/resolvers/entity/product-option-entity.resolver.ts

@@ -1,6 +1,7 @@
 import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
 import { Permission } from '@vendure/common/lib/generated-types';
 
+import { RequestContextCacheService } from '../../../cache/request-context-cache.service';
 import { Translated } from '../../../common/types/locale-types';
 import { assertFound } from '../../../common/utils';
 import { ProductOptionGroup } from '../../../entity/product-option-group/product-option-group.entity';
@@ -16,6 +17,7 @@ export class ProductOptionEntityResolver {
     constructor(
         private productOptionGroupService: ProductOptionGroupService,
         private localeStringHydrator: LocaleStringHydrator,
+        private requestContextCache: RequestContextCacheService,
     ) {}
 
     @ResolveField()
@@ -32,6 +34,8 @@ export class ProductOptionEntityResolver {
         if (option.group) {
             return option.group;
         }
-        return assertFound(this.productOptionGroupService.findOne(ctx, option.groupId));
+        return this.requestContextCache.get(ctx, `ProductOptionEntityResolver.group(${option.groupId})`, () =>
+            assertFound(this.productOptionGroupService.findOne(ctx, option.groupId)),
+        );
     }
 }

+ 7 - 1
packages/core/src/api/resolvers/entity/product-variant-entity.resolver.ts

@@ -3,6 +3,7 @@ import { CurrencyCode, StockMovementListOptions } from '@vendure/common/lib/gene
 import { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';
 import { PaginatedList } from '@vendure/common/lib/shared-types';
 
+import { RequestContextCacheService } from '../../../cache/request-context-cache.service';
 import { Translated } from '../../../common/types/locale-types';
 import { idsAreEqual } from '../../../common/utils';
 import { Asset, Channel, FacetValue, Product, ProductOption, TaxRate } from '../../../entity';
@@ -23,6 +24,7 @@ export class ProductVariantEntityResolver {
         private productVariantService: ProductVariantService,
         private assetService: AssetService,
         private localeStringHydrator: LocaleStringHydrator,
+        private requestContextCache: RequestContextCacheService,
     ) {}
 
     @ResolveField()
@@ -67,7 +69,11 @@ export class ProductVariantEntityResolver {
         if (productVariant.product) {
             return productVariant.product;
         }
-        return this.productVariantService.getProductForVariant(ctx, productVariant);
+        return this.requestContextCache.get(
+            ctx,
+            `ProductVariantEntityResolver.product(${productVariant.productId})`,
+            () => this.productVariantService.getProductForVariant(ctx, productVariant),
+        );
     }
 
     @ResolveField()