Skip to content

Commit

Permalink
Merge pull request #1363 from madzhup/master
Browse files Browse the repository at this point in the history
fix: inherit directive and extensions in type helpers, compile unique directives
  • Loading branch information
kamilmysliwiec committed Mar 17, 2021
2 parents c8853a3 + b97030c commit 2d4c1a9
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 18 deletions.
21 changes: 19 additions & 2 deletions lib/schema-builder/storages/type-metadata.storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions lib/type-helpers/intersection-type.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<A, B>(
classARef: Type<A>,
Expand Down Expand Up @@ -41,6 +42,7 @@ export function IntersectionType<A, B>(
IntersectionObjectType.prototype,
item.name,
);
applyFieldDecorators(IntersectionObjectType, item);
});

Object.defineProperty(IntersectionObjectType, 'name', {
Expand Down
2 changes: 2 additions & 0 deletions lib/type-helpers/omit-type.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, K extends keyof T>(
classRef: Type<T>,
Expand Down Expand Up @@ -47,6 +48,7 @@ export function OmitType<T, K extends keyof T>(
OmitObjectType.prototype,
item.name,
);
applyFieldDecorators(OmitObjectType, item);
});
return OmitObjectType as Type<Omit<T, typeof keys[number]>>;
}
2 changes: 2 additions & 0 deletions lib/type-helpers/partial-type.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(
classRef: Type<T>,
Expand Down Expand Up @@ -44,6 +45,7 @@ export function PartialType<T>(
item.name,
);
applyIsOptionalDecorator(PartialObjectType, item.name);
applyFieldDecorators(PartialObjectType, item);
});

if (PartialObjectType[METADATA_FACTORY_NAME]) {
Expand Down
2 changes: 2 additions & 0 deletions lib/type-helpers/pick-type.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, K extends keyof T>(
classRef: Type<T>,
Expand Down Expand Up @@ -48,6 +49,7 @@ export function PickType<T, K extends keyof T>(
PickObjectType.prototype,
item.name,
);
applyFieldDecorators(PickObjectType, item);
});
return PickObjectType as Type<Pick<T, typeof keys[number]>>;
}
16 changes: 16 additions & 0 deletions lib/type-helpers/type-helpers.utils.ts
Original file line number Diff line number Diff line change
@@ -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);
});
}
}
29 changes: 25 additions & 4 deletions tests/type-helpers/intersection-type.helper.spec.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -7,6 +7,8 @@ describe('IntersectionType', () => {
@ObjectType()
class ClassA {
@Field({ nullable: true })
@Directive('@upper')
@Extensions({ extension: true })
login: string;

@Field()
Expand All @@ -16,6 +18,8 @@ describe('IntersectionType', () => {
@ObjectType()
class ClassB {
@Field()
@Directive('@upper')
@Extensions({ extension: true })
lastName: string;

firstName?: string;
Expand All @@ -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,
});
});
});
18 changes: 14 additions & 4 deletions tests/type-helpers/omit-type.helper.spec.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -14,6 +14,8 @@ describe('OmitType', () => {
@Transform((str) => str + '_transformed')
@MinLength(10)
@Field()
@Directive('@upper')
@Extensions({ extension: true })
password: string;

@Field({ name: 'id' })
Expand All @@ -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,
});
});
});
18 changes: 14 additions & 4 deletions tests/type-helpers/partial-type.helper.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
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';

describe('PartialType', () => {
@ObjectType({ isAbstract: true })
abstract class BaseType {
@Field()
@Directive('@upper')
@Extensions({ extension: true })
id: string;

@Field()
Expand All @@ -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(
Expand All @@ -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,
});
});
});
22 changes: 18 additions & 4 deletions tests/type-helpers/pick-type.helper.spec.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -10,13 +16,15 @@ describe('PickType', () => {
@Transform((str) => str + '_transformed')
@MinLength(10)
@Field({ nullable: true })
@Directive('@upper')
login: string;

@MinLength(10)
@Field()
password: string;

@Field({ name: 'id' })
@Extensions({ extension: true })
_id: string;
}

Expand All @@ -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', () => {
Expand All @@ -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()
Expand Down

0 comments on commit 2d4c1a9

Please sign in to comment.