diff --git a/lib/schema-builder/storages/type-metadata.storage.ts b/lib/schema-builder/storages/type-metadata.storage.ts
index b84b903f2..6b2f7a810 100644
--- a/lib/schema-builder/storages/type-metadata.storage.ts
+++ b/lib/schema-builder/storages/type-metadata.storage.ts
@@ -157,11 +157,28 @@ export class TypeMetadataStorageHost {
}
addDirectiveMetadata(metadata: ClassDirectiveMetadata) {
- this.classDirectives.push(metadata);
+ const exist = this.fieldDirectives.some((directiveMetadata) => {
+ return (
+ directiveMetadata.sdl === metadata.sdl &&
+ directiveMetadata.target === metadata.target
+ );
+ });
+ if (!exist) {
+ this.classDirectives.push(metadata);
+ }
}
addDirectivePropertyMetadata(metadata: PropertyDirectiveMetadata) {
- this.fieldDirectives.push(metadata);
+ const exist = this.fieldDirectives.some((directiveMetadata) => {
+ return (
+ directiveMetadata.fieldName === metadata.fieldName &&
+ directiveMetadata.sdl === metadata.sdl &&
+ directiveMetadata.target === metadata.target
+ );
+ });
+ if (!exist) {
+ this.fieldDirectives.push(metadata);
+ }
}
addExtensionsMetadata(metadata: ClassExtensionsMetadata) {
diff --git a/lib/type-helpers/intersection-type.helper.ts b/lib/type-helpers/intersection-type.helper.ts
index bee42662a..2457f19d5 100644
--- a/lib/type-helpers/intersection-type.helper.ts
+++ b/lib/type-helpers/intersection-type.helper.ts
@@ -7,6 +7,7 @@ import {
import { Field } from '../decorators';
import { ClassDecoratorFactory } from '../interfaces/class-decorator-factory.interface';
import { getFieldsAndDecoratorForType } from '../schema-builder/utils/get-fields-and-decorator.util';
+import { applyFieldDecorators } from './type-helpers.utils';
export function IntersectionType(
classARef: Type,
@@ -41,6 +42,7 @@ export function IntersectionType(
IntersectionObjectType.prototype,
item.name,
);
+ applyFieldDecorators(IntersectionObjectType, item);
});
Object.defineProperty(IntersectionObjectType, 'name', {
diff --git a/lib/type-helpers/omit-type.helper.ts b/lib/type-helpers/omit-type.helper.ts
index 7f4ae543a..5d4a4f8ee 100644
--- a/lib/type-helpers/omit-type.helper.ts
+++ b/lib/type-helpers/omit-type.helper.ts
@@ -8,6 +8,7 @@ import {
import { Field } from '../decorators';
import { ClassDecoratorFactory } from '../interfaces/class-decorator-factory.interface';
import { getFieldsAndDecoratorForType } from '../schema-builder/utils/get-fields-and-decorator.util';
+import { applyFieldDecorators } from './type-helpers.utils';
export function OmitType(
classRef: Type,
@@ -47,6 +48,7 @@ export function OmitType(
OmitObjectType.prototype,
item.name,
);
+ applyFieldDecorators(OmitObjectType, item);
});
return OmitObjectType as Type>;
}
diff --git a/lib/type-helpers/partial-type.helper.ts b/lib/type-helpers/partial-type.helper.ts
index 5742a33c8..814cea620 100644
--- a/lib/type-helpers/partial-type.helper.ts
+++ b/lib/type-helpers/partial-type.helper.ts
@@ -10,6 +10,7 @@ import { Field } from '../decorators';
import { ClassDecoratorFactory } from '../interfaces/class-decorator-factory.interface';
import { METADATA_FACTORY_NAME } from '../plugin/plugin-constants';
import { getFieldsAndDecoratorForType } from '../schema-builder/utils/get-fields-and-decorator.util';
+import { applyFieldDecorators } from './type-helpers.utils';
export function PartialType(
classRef: Type,
@@ -44,6 +45,7 @@ export function PartialType(
item.name,
);
applyIsOptionalDecorator(PartialObjectType, item.name);
+ applyFieldDecorators(PartialObjectType, item);
});
if (PartialObjectType[METADATA_FACTORY_NAME]) {
diff --git a/lib/type-helpers/pick-type.helper.ts b/lib/type-helpers/pick-type.helper.ts
index d05e7148c..08ef6d430 100644
--- a/lib/type-helpers/pick-type.helper.ts
+++ b/lib/type-helpers/pick-type.helper.ts
@@ -8,6 +8,7 @@ import {
import { Field } from '../decorators';
import { ClassDecoratorFactory } from '../interfaces/class-decorator-factory.interface';
import { getFieldsAndDecoratorForType } from '../schema-builder/utils/get-fields-and-decorator.util';
+import { applyFieldDecorators } from './type-helpers.utils';
export function PickType(
classRef: Type,
@@ -48,6 +49,7 @@ export function PickType(
PickObjectType.prototype,
item.name,
);
+ applyFieldDecorators(PickObjectType, item);
});
return PickObjectType as Type>;
}
diff --git a/lib/type-helpers/type-helpers.utils.ts b/lib/type-helpers/type-helpers.utils.ts
new file mode 100644
index 000000000..ee2d5aa57
--- /dev/null
+++ b/lib/type-helpers/type-helpers.utils.ts
@@ -0,0 +1,16 @@
+import { Directive, Extensions } from '../decorators';
+import { PropertyMetadata } from '../schema-builder/metadata';
+
+export function applyFieldDecorators(
+ targetClass: Function,
+ item: PropertyMetadata,
+) {
+ if (item.extensions) {
+ Extensions(item.extensions)(targetClass.prototype, item.name);
+ }
+ if (item.directives?.length) {
+ item.directives.map((directive) => {
+ Directive(directive.sdl)(targetClass.prototype, item.name);
+ });
+ }
+}
diff --git a/tests/type-helpers/intersection-type.helper.spec.ts b/tests/type-helpers/intersection-type.helper.spec.ts
index b9cc0da13..15274cd38 100644
--- a/tests/type-helpers/intersection-type.helper.spec.ts
+++ b/tests/type-helpers/intersection-type.helper.spec.ts
@@ -1,4 +1,4 @@
-import { Field, ObjectType } from '../../lib/decorators';
+import { Directive, Extensions, Field, ObjectType } from '../../lib/decorators';
import { METADATA_FACTORY_NAME } from '../../lib/plugin/plugin-constants';
import { getFieldsAndDecoratorForType } from '../../lib/schema-builder/utils/get-fields-and-decorator.util';
import { IntersectionType } from '../../lib/type-helpers';
@@ -7,6 +7,8 @@ describe('IntersectionType', () => {
@ObjectType()
class ClassA {
@Field({ nullable: true })
+ @Directive('@upper')
+ @Extensions({ extension: true })
login: string;
@Field()
@@ -16,6 +18,8 @@ describe('IntersectionType', () => {
@ObjectType()
class ClassB {
@Field()
+ @Directive('@upper')
+ @Extensions({ extension: true })
lastName: string;
firstName?: string;
@@ -30,13 +34,30 @@ describe('IntersectionType', () => {
class UpdateUserDto extends IntersectionType(ClassA, ClassB) {}
it('should inherit all fields from two types', () => {
- const { fields } = getFieldsAndDecoratorForType(
- Object.getPrototypeOf(UpdateUserDto),
- );
+ const prototype = Object.getPrototypeOf(UpdateUserDto);
+ const { fields } = getFieldsAndDecoratorForType(prototype);
expect(fields.length).toEqual(4);
expect(fields[0].name).toEqual('login');
expect(fields[1].name).toEqual('password');
expect(fields[2].name).toEqual('lastName');
expect(fields[3].name).toEqual('firstName');
+ expect(fields[0].directives.length).toEqual(1);
+ expect(fields[0].directives).toContainEqual({
+ fieldName: 'login',
+ sdl: '@upper',
+ target: prototype,
+ });
+ expect(fields[0].extensions).toEqual({
+ extension: true,
+ });
+ expect(fields[2].directives.length).toEqual(1);
+ expect(fields[2].directives).toContainEqual({
+ fieldName: 'lastName',
+ sdl: '@upper',
+ target: prototype,
+ });
+ expect(fields[2].extensions).toEqual({
+ extension: true,
+ });
});
});
diff --git a/tests/type-helpers/omit-type.helper.spec.ts b/tests/type-helpers/omit-type.helper.spec.ts
index ce67abc2f..587dbb8cf 100644
--- a/tests/type-helpers/omit-type.helper.spec.ts
+++ b/tests/type-helpers/omit-type.helper.spec.ts
@@ -1,6 +1,6 @@
import { Transform } from 'class-transformer';
import { MinLength } from 'class-validator';
-import { Field, ObjectType } from '../../lib/decorators';
+import { Directive, Extensions, Field, ObjectType } from '../../lib/decorators';
import { getFieldsAndDecoratorForType } from '../../lib/schema-builder/utils/get-fields-and-decorator.util';
import { OmitType } from '../../lib/type-helpers';
@@ -14,6 +14,8 @@ describe('OmitType', () => {
@Transform((str) => str + '_transformed')
@MinLength(10)
@Field()
+ @Directive('@upper')
+ @Extensions({ extension: true })
password: string;
@Field({ name: 'id' })
@@ -23,10 +25,18 @@ describe('OmitType', () => {
class UpdateUserDto extends OmitType(CreateUserDto, ['login', '_id']) {}
it('should inherit all fields except for "login" and "_id"', () => {
- const { fields } = getFieldsAndDecoratorForType(
- Object.getPrototypeOf(UpdateUserDto),
- );
+ const prototype = Object.getPrototypeOf(UpdateUserDto);
+ const { fields } = getFieldsAndDecoratorForType(prototype);
expect(fields.length).toEqual(1);
expect(fields[0].name).toEqual('password');
+ expect(fields[0].directives.length).toEqual(1);
+ expect(fields[0].directives).toContainEqual({
+ fieldName: 'password',
+ sdl: '@upper',
+ target: prototype,
+ });
+ expect(fields[0].extensions).toEqual({
+ extension: true,
+ });
});
});
diff --git a/tests/type-helpers/partial-type.helper.spec.ts b/tests/type-helpers/partial-type.helper.spec.ts
index 644a99994..0bfc9c8ef 100644
--- a/tests/type-helpers/partial-type.helper.spec.ts
+++ b/tests/type-helpers/partial-type.helper.spec.ts
@@ -1,6 +1,6 @@
import { Expose, Transform } from 'class-transformer';
import { IsString } from 'class-validator';
-import { Field, ObjectType } from '../../lib/decorators';
+import { Directive, Extensions, Field, ObjectType } from '../../lib/decorators';
import { getFieldsAndDecoratorForType } from '../../lib/schema-builder/utils/get-fields-and-decorator.util';
import { PartialType } from '../../lib/type-helpers';
@@ -8,6 +8,8 @@ describe('PartialType', () => {
@ObjectType({ isAbstract: true })
abstract class BaseType {
@Field()
+ @Directive('@upper')
+ @Extensions({ extension: true })
id: string;
@Field()
@@ -32,9 +34,8 @@ describe('PartialType', () => {
class UpdateUserDto extends PartialType(CreateUserDto) {}
it('should inherit all fields and set "nullable" to true', () => {
- const { fields } = getFieldsAndDecoratorForType(
- Object.getPrototypeOf(UpdateUserDto),
- );
+ const prototype = Object.getPrototypeOf(UpdateUserDto);
+ const { fields } = getFieldsAndDecoratorForType(prototype);
expect(fields.length).toEqual(5);
expect(fields).toEqual(
@@ -61,5 +62,14 @@ describe('PartialType', () => {
}),
]),
);
+ expect(fields[0].directives.length).toEqual(1);
+ expect(fields[0].directives).toContainEqual({
+ fieldName: 'id',
+ sdl: '@upper',
+ target: prototype,
+ });
+ expect(fields[0].extensions).toEqual({
+ extension: true,
+ });
});
});
diff --git a/tests/type-helpers/pick-type.helper.spec.ts b/tests/type-helpers/pick-type.helper.spec.ts
index fd5d4407c..ee500b249 100644
--- a/tests/type-helpers/pick-type.helper.spec.ts
+++ b/tests/type-helpers/pick-type.helper.spec.ts
@@ -1,6 +1,12 @@
import { Transform } from 'class-transformer';
import { MinLength } from 'class-validator';
-import { ArgsType, Field, ObjectType } from '../../lib/decorators';
+import {
+ ArgsType,
+ Directive,
+ Extensions,
+ Field,
+ ObjectType,
+} from '../../lib/decorators';
import { getFieldsAndDecoratorForType } from '../../lib/schema-builder/utils/get-fields-and-decorator.util';
import { PickType } from '../../lib/type-helpers';
@@ -10,6 +16,7 @@ describe('PickType', () => {
@Transform((str) => str + '_transformed')
@MinLength(10)
@Field({ nullable: true })
+ @Directive('@upper')
login: string;
@MinLength(10)
@@ -17,6 +24,7 @@ describe('PickType', () => {
password: string;
@Field({ name: 'id' })
+ @Extensions({ extension: true })
_id: string;
}
@@ -25,11 +33,16 @@ describe('PickType', () => {
class UpdateUserWithIdDto extends PickType(CreateUserDto, ['_id']) {}
it('should inherit "login" field', () => {
- const { fields } = getFieldsAndDecoratorForType(
- Object.getPrototypeOf(UpdateUserDto),
- );
+ const prototype = Object.getPrototypeOf(UpdateUserDto);
+ const { fields } = getFieldsAndDecoratorForType(prototype);
expect(fields.length).toEqual(1);
expect(fields[0].name).toEqual('login');
+ expect(fields[0].directives.length).toEqual(1);
+ expect(fields[0].directives).toContainEqual({
+ fieldName: 'login',
+ sdl: '@upper',
+ target: prototype,
+ });
});
it('should inherit renamed "_id" field', () => {
@@ -38,6 +51,7 @@ describe('PickType', () => {
);
expect(fields.length).toEqual(1);
expect(fields[0].name).toEqual('_id');
+ expect(fields[0].extensions).toEqual({ extension: true });
});
@ArgsType()