Browse Source

refactor(core): Use ConfigArgService for common operations

Michael Bromley 5 years ago
parent
commit
a8bde2a1f3

+ 24 - 15
packages/core/src/service/helpers/config-arg/config-arg.service.ts

@@ -10,24 +10,28 @@ import { ConfigService } from '../../../config/config.service';
 import { FulfillmentHandler } from '../../../config/fulfillment/fulfillment-handler';
 import { PaymentMethodHandler } from '../../../config/payment-method/payment-method-handler';
 import { PromotionAction } from '../../../config/promotion/promotion-action';
+import { PromotionCondition } from '../../../config/promotion/promotion-condition';
 import { ShippingCalculator } from '../../../config/shipping-method/shipping-calculator';
 import { ShippingEligibilityChecker } from '../../../config/shipping-method/shipping-eligibility-checker';
 
-export type ConfigDefType =
-    | 'CollectionFilter'
-    | 'FulfillmentHandler'
-    | 'PaymentMethodHandler'
-    | 'PromotionAction'
-    | 'PromotionCondition'
-    | 'ShippingCalculator'
-    | 'ShippingEligibilityChecker';
+export type ConfigDefTypeMap = {
+    CollectionFilter: CollectionFilter;
+    FulfillmentHandler: FulfillmentHandler;
+    PaymentMethodHandler: PaymentMethodHandler;
+    PromotionAction: PromotionAction;
+    PromotionCondition: PromotionCondition;
+    ShippingCalculator: ShippingCalculator;
+    ShippingEligibilityChecker: ShippingEligibilityChecker;
+};
+
+export type ConfigDefType = keyof ConfigDefTypeMap;
 
 /**
  * This helper class provides methods relating to ConfigurableOperationDef instances.
  */
 @Injectable()
 export class ConfigArgService {
-    private readonly definitionsByType: { [K in ConfigDefType]: ConfigurableOperationDef[] };
+    private readonly definitionsByType: { [K in ConfigDefType]: Array<ConfigDefTypeMap[K]> };
 
     constructor(private configService: ConfigService) {
         this.definitionsByType = {
@@ -41,19 +45,24 @@ export class ConfigArgService {
         };
     }
 
-    getDefinitions(defType: ConfigDefType): ConfigurableOperationDef[] {
-        return this.definitionsByType[defType];
+    getDefinitions<T extends ConfigDefType>(defType: T): Array<ConfigDefTypeMap[T]> {
+        return this.definitionsByType[defType] as Array<ConfigDefTypeMap[T]>;
     }
 
-    parseInput(defType: ConfigDefType, input: ConfigurableOperationInput): ConfigurableOperation {
-        const defsOfType = this.definitionsByType[defType];
-        const match = defsOfType.find(def => def.code === input.code);
+    getByCode<T extends ConfigDefType>(defType: T, code: string): ConfigDefTypeMap[T] {
+        const defsOfType = this.getDefinitions(defType);
+        const match = defsOfType.find(def => def.code === code);
         if (!match) {
             throw new UserInputError(`error.no-configurable-operation-def-with-code-found`, {
-                code: input.code,
+                code,
                 type: defType,
             });
         }
+        return match as ConfigDefTypeMap[T];
+    }
+
+    parseInput(defType: ConfigDefType, input: ConfigurableOperationInput): ConfigurableOperation {
+        const match = this.getByCode(defType, input.code);
         return {
             code: input.code,
             args: input.arguments,

+ 4 - 22
packages/core/src/service/services/collection.service.ts

@@ -15,11 +15,10 @@ import { merge } from 'rxjs';
 import { debounceTime } from 'rxjs/operators';
 
 import { RequestContext, SerializedRequestContext } from '../../api/common/request-context';
-import { IllegalOperationError, UserInputError } from '../../common/error/errors';
+import { IllegalOperationError } from '../../common/error/errors';
 import { ListQueryOptions } from '../../common/types/common-types';
 import { Translated } from '../../common/types/locale-types';
 import { assertFound, idsAreEqual } from '../../common/utils';
-import { CollectionFilter } from '../../config/catalog/collection-filter';
 import { ConfigService } from '../../config/config.service';
 import { Logger } from '../../config/logger/vendure-logger';
 import { CollectionTranslation } from '../../entity/collection/collection-translation.entity';
@@ -33,6 +32,7 @@ import { Job } from '../../job-queue/job';
 import { JobQueue } from '../../job-queue/job-queue';
 import { JobQueueService } from '../../job-queue/job-queue.service';
 import { WorkerService } from '../../worker/worker.service';
+import { ConfigArgService } from '../helpers/config-arg/config-arg.service';
 import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder';
 import { SlugValidator } from '../helpers/slug-validator/slug-validator';
 import { TranslatableSaver } from '../helpers/translatable-saver/translatable-saver';
@@ -62,6 +62,7 @@ export class CollectionService implements OnModuleInit {
         private jobQueueService: JobQueueService,
         private configService: ConfigService,
         private slugValidator: SlugValidator,
+        private configArgService: ConfigArgService,
     ) {}
 
     onModuleInit() {
@@ -381,18 +382,7 @@ export class CollectionService implements OnModuleInit {
         const filters: ConfigurableOperation[] = [];
         if (input.filters) {
             for (const filter of input.filters) {
-                const match = this.getFilterByCode(filter.code);
-                const output = {
-                    code: filter.code,
-                    description: match.description,
-                    args: filter.arguments.map((inputArg, i) => {
-                        return {
-                            name: inputArg.name,
-                            value: inputArg.value,
-                        };
-                    }),
-                };
-                filters.push(output);
+                filters.push(this.configArgService.parseInput('CollectionFilter', filter));
             }
         }
         return filters;
@@ -520,12 +510,4 @@ export class CollectionService implements OnModuleInit {
         this.rootCollection = newRoot;
         return newRoot;
     }
-
-    private getFilterByCode(code: string): CollectionFilter<any> {
-        const match = this.configService.catalogOptions.collectionFilters.find(a => a.code === code);
-        if (!match) {
-            throw new UserInputError(`error.adjustment-operation-with-code-not-found`, { code });
-        }
-        return match;
-    }
 }

+ 3 - 5
packages/core/src/service/services/payment-method.service.ts

@@ -24,6 +24,7 @@ import { Refund } from '../../entity/refund/refund.entity';
 import { EventBus } from '../../event-bus/event-bus';
 import { PaymentStateTransitionEvent } from '../../event-bus/events/payment-state-transition-event';
 import { RefundStateTransitionEvent } from '../../event-bus/events/refund-state-transition-event';
+import { ConfigArgService } from '../helpers/config-arg/config-arg.service';
 import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder';
 import { PaymentStateMachine } from '../helpers/payment-state-machine/payment-state-machine';
 import { RefundStateMachine } from '../helpers/refund-state-machine/refund-state-machine';
@@ -39,6 +40,7 @@ export class PaymentMethodService {
         private paymentStateMachine: PaymentStateMachine,
         private refundStateMachine: RefundStateMachine,
         private eventBus: EventBus,
+        private configArgService: ConfigArgService,
     ) {}
 
     async initPaymentMethods() {
@@ -184,11 +186,7 @@ export class PaymentMethodService {
     }
 
     getPaymentMethodHandler(code: string): PaymentMethodHandler {
-        const handler = this.configService.paymentOptions.paymentMethodHandlers.find(h => h.code === code);
-        if (!handler) {
-            throw new UserInputError(`error.no-payment-handler-with-code`, { code });
-        }
-        return handler;
+        return this.configArgService.getByCode('PaymentMethodHandler', code);
     }
 
     private async getMethodAndHandler(

+ 12 - 38
packages/core/src/service/services/promotion.service.ts

@@ -1,11 +1,7 @@
 import { Injectable } from '@nestjs/common';
 import { ApplyCouponCodeResult } from '@vendure/common/lib/generated-shop-types';
 import {
-    Adjustment,
-    AdjustmentType,
-    ConfigurableOperation,
     ConfigurableOperationDefinition,
-    ConfigurableOperationInput,
     CreatePromotionInput,
     CreatePromotionResult,
     DeletionResponse,
@@ -19,7 +15,6 @@ import { unique } from '@vendure/common/lib/unique';
 
 import { RequestContext } from '../../api/common/request-context';
 import { ErrorResultUnion, JustErrorResults } from '../../common/error/error-result';
-import { UserInputError } from '../../common/error/errors';
 import { MissingConditionsError } from '../../common/error/generated-graphql-admin-errors';
 import {
     CouponCodeExpiredError,
@@ -34,6 +29,7 @@ import { PromotionAction } from '../../config/promotion/promotion-action';
 import { PromotionCondition } from '../../config/promotion/promotion-condition';
 import { Order } from '../../entity/order/order.entity';
 import { Promotion } from '../../entity/promotion/promotion.entity';
+import { ConfigArgService } from '../helpers/config-arg/config-arg.service';
 import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder';
 import { patchEntity } from '../helpers/utils/patch-entity';
 import { TransactionalConnection } from '../transaction/transactional-connection';
@@ -56,6 +52,7 @@ export class PromotionService {
         private configService: ConfigService,
         private channelService: ChannelService,
         private listQueryBuilder: ListQueryBuilder,
+        private configArgService: ConfigArgService,
     ) {
         this.availableConditions = this.configService.promotionOptions.promotionConditions || [];
         this.availableActions = this.configService.promotionOptions.promotionActions || [];
@@ -111,8 +108,8 @@ export class PromotionService {
             perCustomerUsageLimit: input.perCustomerUsageLimit,
             startsAt: input.startsAt,
             endsAt: input.endsAt,
-            conditions: input.conditions.map(c => this.parseOperationArgs('condition', c)),
-            actions: input.actions.map(a => this.parseOperationArgs('action', a)),
+            conditions: input.conditions.map(c => this.configArgService.parseInput('PromotionCondition', c)),
+            actions: input.actions.map(a => this.configArgService.parseInput('PromotionAction', a)),
             priorityScore: this.calculatePriorityScore(input),
         });
         if (promotion.conditions.length === 0 && !promotion.couponCode) {
@@ -133,10 +130,14 @@ export class PromotionService {
         });
         const updatedPromotion = patchEntity(promotion, omit(input, ['conditions', 'actions']));
         if (input.conditions) {
-            updatedPromotion.conditions = input.conditions.map(c => this.parseOperationArgs('condition', c));
+            updatedPromotion.conditions = input.conditions.map(c =>
+                this.configArgService.parseInput('PromotionCondition', c),
+            );
         }
         if (input.actions) {
-            updatedPromotion.actions = input.actions.map(a => this.parseOperationArgs('action', a));
+            updatedPromotion.actions = input.actions.map(a =>
+                this.configArgService.parseInput('PromotionAction', a),
+            );
         }
         if (promotion.conditions.length === 0 && !promotion.couponCode) {
             return new MissingConditionsError();
@@ -208,44 +209,17 @@ export class PromotionService {
 
         return qb.getCount();
     }
-    /**
-     * Converts the input values of the "create" and "update" mutations into the format expected by the AdjustmentSource entity.
-     */
-    private parseOperationArgs(
-        type: 'condition' | 'action',
-        input: ConfigurableOperationInput,
-    ): ConfigurableOperation {
-        const match = this.getAdjustmentOperationByCode(type, input.code);
-        const output: ConfigurableOperation = {
-            code: input.code,
-            args: input.arguments,
-        };
-        return output;
-    }
 
     private calculatePriorityScore(input: CreatePromotionInput | UpdatePromotionInput): number {
         const conditions = input.conditions
-            ? input.conditions.map(c => this.getAdjustmentOperationByCode('condition', c.code))
+            ? input.conditions.map(c => this.configArgService.getByCode('PromotionCondition', c.code))
             : [];
         const actions = input.actions
-            ? input.actions.map(c => this.getAdjustmentOperationByCode('action', c.code))
+            ? input.actions.map(c => this.configArgService.getByCode('PromotionAction', c.code))
             : [];
         return [...conditions, ...actions].reduce((score, op) => score + op.priorityValue, 0);
     }
 
-    private getAdjustmentOperationByCode(
-        type: 'condition' | 'action',
-        code: string,
-    ): PromotionCondition | PromotionAction {
-        const available: Array<PromotionAction | PromotionCondition> =
-            type === 'condition' ? this.availableConditions : this.availableActions;
-        const match = available.find(a => a.code === code);
-        if (!match) {
-            throw new UserInputError(`error.adjustment-operation-with-code-not-found`, { code });
-        }
-        return match;
-    }
-
     /**
      * Update the activeSources cache.
      */