Parcourir la source

fix(core): Fix validation of relation custom fields

Fixes #1000
Michael Bromley il y a 4 ans
Parent
commit
fc3a9c5a08

+ 2 - 1
packages/common/src/shared-utils.ts

@@ -84,7 +84,8 @@ export function generateAllCombinations<T>(
 
 /**
  * @description
- * Returns the input field name of a relation custom field.
+ * Returns the input field name of a custom field, taking into account that "relation" type custom
+ * field inputs are suffixed with "Id" or "Ids".
  */
 export function getGraphQlInputName(config: { name: string; type: string; list?: boolean }): string {
     if (config.type === 'relation') {

+ 28 - 1
packages/core/e2e/custom-fields.e2e-spec.ts

@@ -1,5 +1,5 @@
 import { LanguageCode } from '@vendure/common/lib/generated-types';
-import { CustomFields, mergeConfig, TransactionalConnection } from '@vendure/core';
+import { Asset, CustomFields, mergeConfig, TransactionalConnection } from '@vendure/core';
 import { createTestEnvironment } from '@vendure/testing';
 import gql from 'graphql-tag';
 import path from 'path';
@@ -83,6 +83,15 @@ const customConfig = mergeConfig(testConfig, {
                     return `async error`;
                 },
             },
+            {
+                name: 'validateRelation',
+                type: 'relation',
+                entity: Asset,
+                validate: async value => {
+                    await new Promise(resolve => setTimeout(resolve, 1));
+                    return `relation error`;
+                },
+            },
             {
                 name: 'stringWithOptions',
                 type: 'string',
@@ -217,6 +226,7 @@ describe('Custom fields', () => {
                 { name: 'validateFn2', type: 'string', list: false },
                 { name: 'validateFn3', type: 'string', list: false },
                 { name: 'validateFn4', type: 'string', list: false },
+                { name: 'validateRelation', type: 'relation', list: false },
                 { name: 'stringWithOptions', type: 'string', list: false },
                 { name: 'nonPublic', type: 'string', list: false },
                 { name: 'public', type: 'string', list: false },
@@ -614,6 +624,23 @@ describe('Custom fields', () => {
                 `);
             }, `async error`),
         );
+
+        // https://github.com/vendure-ecommerce/vendure/issues/1000
+        it(
+            'supports validation of relation types',
+            assertThrowsWithMessage(async () => {
+                await adminClient.query(gql`
+                    mutation {
+                        updateProduct(input: { id: "T_1", customFields: { validateRelationId: "T_1" } }) {
+                            id
+                            customFields {
+                                validateFn4
+                            }
+                        }
+                    }
+                `);
+            }, `relation error`),
+        );
     });
 
     describe('public access', () => {

+ 2 - 1
packages/core/src/api/middleware/validate-custom-fields-interceptor.ts

@@ -2,6 +2,7 @@ import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nes
 import { ModuleRef } from '@nestjs/core';
 import { GqlExecutionContext } from '@nestjs/graphql';
 import { LanguageCode } from '@vendure/common/lib/generated-types';
+import { getGraphQlInputName } from '@vendure/common/lib/shared-utils';
 import {
     GraphQLInputType,
     GraphQLList,
@@ -105,7 +106,7 @@ export class ValidateCustomFieldsInterceptor implements NestInterceptor {
         injector: Injector,
     ) {
         for (const [key, value] of Object.entries(customFieldsObject)) {
-            const config = customFieldConfig.find(c => c.name === key);
+            const config = customFieldConfig.find(c => getGraphQlInputName(c) === key);
             if (config) {
                 await validateCustomFieldValue(config, value, injector, languageCode);
             }

+ 2 - 1
packages/core/src/config/custom-field/custom-field-types.ts

@@ -20,7 +20,8 @@ export type DefaultValueType<T extends CustomFieldType> =
     T extends 'string' | 'localeString' ? string :
         T extends 'int' | 'float' ? number :
             T extends 'boolean' ? boolean :
-                T extends 'datetime' ? Date : never;
+                T extends 'datetime' ? Date :
+                    T extends 'relation' ? any : never;
 
 export type BaseTypedCustomFieldConfig<T extends CustomFieldType, C extends CustomField> = Omit<
     C,