Skip to content

Commit 5265153

Browse files
authored
Merge pull request #29 from indigotech/feature/refactor-enum
Feature - EnumType and UnionType refactor
2 parents 29691ac + 37581e5 commit 5265153

26 files changed

+252
-159
lines changed

src/decorator.ts

Lines changed: 0 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ export const GQ_QUERY_KEY = 'gq_query';
1515
export const GQ_MUTATION_KEY = 'gq_mutation';
1616
export const GQ_SUBSCRIPTION_KEY = 'gq_subscription';
1717
export const GQ_FIELDS_KEY = 'gq_fields';
18-
export const GQ_VALUES_KEY = 'gq_values';
1918
export const GQ_OBJECT_METADATA_KEY = 'gq_object_type';
20-
export const GQ_ENUM_METADATA_KEY = 'gq_enum_type';
2119
export const GQ_DESCRIPTION_KEY = 'gq_description';
2220

2321
export interface TypeMetadata {
@@ -54,18 +52,6 @@ export interface ObjectTypeMetadata {
5452
isInput?: boolean;
5553
}
5654

57-
export interface EnumTypeMetadata {
58-
name?: string;
59-
description?: string;
60-
values?: EnumValueMetadata[];
61-
}
62-
63-
export interface EnumValueMetadata {
64-
name: string;
65-
value?: any;
66-
description?: string;
67-
}
68-
6955
export interface DefaultOption {
7056
description?: string;
7157
}
@@ -119,32 +105,6 @@ function createOrSetObjectTypeMetadata(target: any, metadata: ObjectTypeMetadata
119105
}
120106
}
121107

122-
function createOrSetEnumTypeMetadata(target: any, metadata: EnumTypeMetadata) {
123-
if (!Reflect.hasMetadata(GQ_ENUM_METADATA_KEY, target.prototype)) {
124-
let mergedMetadata = mergeDescriptionMetadata(target, metadata);
125-
Reflect.defineMetadata(GQ_ENUM_METADATA_KEY, mergedMetadata, target.prototype);
126-
} else {
127-
const originalMetadata = Reflect.getMetadata(GQ_ENUM_METADATA_KEY, target.prototype) as EnumTypeMetadata;
128-
Object.assign(originalMetadata, metadata);
129-
}
130-
}
131-
132-
function createOrSetValueTypeMetadata(target: any, metadata: EnumValueMetadata) {
133-
let valueDefs: EnumValueMetadata[];
134-
if (!Reflect.hasMetadata(GQ_VALUES_KEY, target)) {
135-
valueDefs = [];
136-
Reflect.defineMetadata(GQ_VALUES_KEY, valueDefs, target);
137-
} else {
138-
valueDefs = Reflect.getMetadata(GQ_VALUES_KEY, target);
139-
}
140-
const def = valueDefs.find(d => d.name === metadata.name);
141-
if (!def) {
142-
let propertyDescriptionMetadata = getPropertyDescriptionMetadata(target, metadata.name);
143-
Object.assign(metadata, propertyDescriptionMetadata);
144-
valueDefs.push(metadata);
145-
}
146-
}
147-
148108
function createOrSetFieldTypeMetadata(target: any, metadata: FieldTypeMetadata) {
149109
let fieldDefs: FieldTypeMetadata[];
150110
if (!Reflect.hasMetadata(GQ_FIELDS_KEY, target)) {
@@ -202,13 +162,6 @@ export function getFieldMetadata(target: any, name: string) {
202162
return (<FieldTypeMetadata[]>Reflect.getMetadata(GQ_FIELDS_KEY, target)).find(m => m.name === name);
203163
}
204164

205-
export function getValueMetadata(target: any, name: string) {
206-
if (!Reflect.hasMetadata(GQ_VALUES_KEY, target)) {
207-
return null;
208-
}
209-
return (<EnumValueMetadata[]>Reflect.getMetadata(GQ_VALUES_KEY, target)).find(m => m.name === name);
210-
}
211-
212165
function setArgumentMetadata(target: any, propertyKey: any, index: number, metadata: ArgumentMetadata) {
213166
const fieldMetadata = getFieldMetadata(target, propertyKey);
214167
if (fieldMetadata && fieldMetadata.args && fieldMetadata.args[index]) {
@@ -258,11 +211,6 @@ function setDescriptionMetadata(description: string, target: any, propertyKey: s
258211
name: propertyKey,
259212
description: description,
260213
});
261-
} else if (getValueMetadata(target, propertyKey) != null) {
262-
createOrSetValueTypeMetadata(target, {
263-
name: propertyKey,
264-
description: description,
265-
});
266214
} else {
267215
createPropertyDescriptionMetadata(target, description, propertyKey);
268216
}
@@ -271,10 +219,6 @@ function setDescriptionMetadata(description: string, target: any, propertyKey: s
271219
createOrSetObjectTypeMetadata(target, {
272220
description: description,
273221
});
274-
} else if (Reflect.hasMetadata(GQ_ENUM_METADATA_KEY, target.prototype)) {
275-
createOrSetEnumTypeMetadata(target, {
276-
description: description,
277-
});
278222
} else {
279223
createDescriptionMetadata(target, description);
280224
}
@@ -321,22 +265,6 @@ function setPaginationMetadata(target: any, propertyKey: string, methodDescripto
321265
};
322266
}
323267

324-
325-
export function EnumType(option?: DefaultOption) {
326-
return function (target: any) {
327-
createOrSetEnumTypeMetadata(target, {
328-
name: target.name,
329-
});
330-
331-
if (option) {
332-
// description
333-
if (option.description) {
334-
setDescriptionMetadata(option.description, target);
335-
}
336-
}
337-
} as Function;
338-
}
339-
340268
export function ObjectType(option?: DefaultOption) {
341269
return function (target: any) {
342270
createOrSetObjectTypeMetadata(target, {
@@ -415,22 +343,6 @@ export function Field(option?: FieldOption) {
415343
} as Function;
416344
}
417345

418-
export function Value(value?: any, option?: DefaultOption) {
419-
return function (target: any, propertyKey: any) {
420-
createOrSetValueTypeMetadata(target, {
421-
name: propertyKey,
422-
value: value,
423-
});
424-
425-
if (option) {
426-
// description
427-
if (option.description) {
428-
setDescriptionMetadata(option.description, target, propertyKey);
429-
}
430-
}
431-
} as Function;
432-
}
433-
434346
export function NonNull() {
435347
return function (target: any, propertyKey: any, index?: number) {
436348
setNonNullMetadata(target, propertyKey, index);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { EnumOption, EnumValueOption } from '../metadata';
2+
import { getMetadataArgsStorage } from '../metadata-builder';
3+
4+
/**
5+
* It can be used just like {@link ObjectType} in order to create {@link GraphQLEnumType} objects.
6+
* See [GraphQL Documentation - Enum Types]{@http://graphql.org/learn/schema/#enumeration-types}
7+
*
8+
* @param option Options for a Enum Type
9+
*/
10+
export function EnumType(option?: EnumOption) {
11+
return function (target: any) {
12+
getMetadataArgsStorage().enums.push({
13+
target: target,
14+
name: target.name,
15+
description: option ? option.description : null,
16+
});
17+
} as Function;
18+
}
19+
20+
/**
21+
* Used to define a value for an {@link EnumType} definition.
22+
*
23+
* Example usage:
24+
*
25+
* ```typescript
26+
* @EnumType()
27+
* class MyEnum {
28+
* @Value('1', {description: 'Value One'})
29+
* VALUE_ONE: string;
30+
*
31+
* @Value('2', {description: 'Value Two'})
32+
* VALUE_TWO: string;
33+
* }
34+
*```
35+
*
36+
* @param value Value to be assigned to the property at schema level
37+
* @param option Options for a Enum Value
38+
*/
39+
export function Value(value: any, option?: EnumValueOption) {
40+
return function (target: any, propertyKey: any, methodDescriptor: any) {
41+
getMetadataArgsStorage().enumValues.push({
42+
target: target,
43+
name: propertyKey,
44+
value: value,
45+
description: option ? option.description : null,
46+
});
47+
} as Function;
48+
}

src/decorator/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export * from './enum-type.decorator';
12
export * from './union-type.decorator';

src/decorator/union-type.decorator.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import { MetadataStorage } from '../metadata-storage';
1+
import { getMetadataArgsStorage } from '../metadata-builder';
22
import { UnionOption } from '../metadata';
33

44
/**
5-
* Union Type. ref: http://graphql.org/learn/schema/#union-types
5+
* Union Type.
6+
* See [GraphQL Documentation - Union Types]{@link http://graphql.org/learn/schema/#union-types}
7+
*
68
* @param option Options for a Union Type
79
*/
810
export function UnionType<T>(option: UnionOption<T>) {
911
return function (target: any) {
10-
MetadataStorage.addUnionMetadata({
12+
getMetadataArgsStorage().union.push({
13+
target: target,
1114
name: target.name,
1215
types: option.types,
1316
resolver: option.resolver,

src/enum.type-factory.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/field_type_factory.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,21 @@ import {
44
ArgumentMetadata,
55
ContextMetadata,
66
FieldTypeMetadata,
7-
GQ_ENUM_METADATA_KEY,
87
GQ_FIELDS_KEY,
98
GQ_OBJECT_METADATA_KEY,
109
Middleware,
1110
RootMetadata,
1211
TypeMetadata,
1312
} from './decorator';
14-
import { MetadataStorage } from './metadata-storage';
13+
import { getMetadataArgsStorage } from './metadata-builder';
1514

1615
import { SchemaFactoryError, SchemaFactoryErrorType } from './schema_factory';
1716

1817
import { IoCContainer } from './ioc-container';
1918
import { OrderByTypeFactory } from './order-by.type-factory';
2019
import { PaginationType } from './pagination.type';
21-
import { enumTypeFactory } from './enum.type-factory';
2220
import { objectTypeFactory } from './object_type_factory';
23-
import { unionTypeFactory } from './type-factory';
21+
import { unionTypeFactory, enumTypeFactory } from './type-factory';
2422

2523

2624
export interface ResolverHolder {
@@ -53,13 +51,12 @@ function convertType(typeFn: Function, metadata: TypeMetadata, isInput: boolean,
5351
} else {
5452
returnType = metadata.explicitType;
5553

56-
if (returnType && returnType.prototype && MetadataStorage.containsUnionMetadata(returnType.name)) {
57-
returnType = unionTypeFactory(returnType.name, isInput);
54+
if (returnType && returnType.prototype && getMetadataArgsStorage().filterUnionTypeByClass(returnType).length > 0) {
55+
returnType = unionTypeFactory(returnType, isInput);
5856
} else if (returnType && returnType.prototype && Reflect.hasMetadata(GQ_OBJECT_METADATA_KEY, returnType.prototype)) {
5957
// recursively call objectFactory
6058
returnType = objectTypeFactory(returnType, isInput);
61-
} else if (returnType && returnType.prototype && Reflect.hasMetadata(GQ_ENUM_METADATA_KEY, returnType.prototype)) {
62-
let enumMetadata = Reflect.getMetadata(GQ_ENUM_METADATA_KEY, returnType.prototype);
59+
} else if (returnType && returnType.prototype && getMetadataArgsStorage().filterEnumsByClass(returnType).length > 0) {
6360
returnType = enumTypeFactory(returnType);
6461
}
6562
}

src/metadata-builder/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './metadata-args.storage';
2+
export * from './metadata.builder';
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {
2+
EnumTypeArg,
3+
EnumValueArg,
4+
UnionTypeArgs,
5+
} from '../metadata/args';
6+
7+
/**
8+
* Gets metadata args storage.
9+
* Metadata args storage follows the best practices and stores metadata in a global variable.
10+
*/
11+
export function getMetadataArgsStorage(): MetadataArgsStorage {
12+
if (!(global as any).graphqlSchemaMetadataArgsStorage) {
13+
(global as any).graphqlSchemaMetadataArgsStorage = new MetadataArgsStorage();
14+
}
15+
16+
return (global as any).graphqlSchemaMetadataArgsStorage;
17+
}
18+
19+
export class MetadataArgsStorage {
20+
enums: EnumTypeArg[] = [];
21+
enumValues: EnumValueArg[] = [];
22+
union: UnionTypeArgs[] = [];
23+
24+
filterEnumsByClass(target: any): EnumTypeArg[] {
25+
return this.enums.filter(item => item.target === target);
26+
}
27+
28+
filterEnumValuesByClass(target: any): EnumValueArg[] {
29+
return this.enumValues.filter(item => item.target === target.prototype);
30+
}
31+
32+
filterUnionTypeByClass(target: any): UnionTypeArgs[] {
33+
return this.union.filter(item => item.target === target);
34+
}
35+
}
36+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import {
2+
EnumTypeMetadata,
3+
EnumValueMetadata,
4+
UnionTypeMetadata,
5+
} from '../metadata/types';
6+
7+
import { getMetadataArgsStorage } from './metadata-args.storage';
8+
9+
/**
10+
* Gets metadata builder
11+
* Metadata builder follows the best practices and stores metadata in a global variable.
12+
*/
13+
export function getMetadataBuilder(): MetadataBuilder {
14+
if (!(global as any).graphqlSchemaMetadataBuilder) {
15+
(global as any).graphqlSchemaMetadataBuilder = new MetadataBuilder();
16+
}
17+
18+
return (global as any).graphqlSchemaMetadataBuilder;
19+
}
20+
21+
export class MetadataBuilder {
22+
23+
buildEnumMetadata(target: any): EnumTypeMetadata[] | undefined {
24+
return getMetadataArgsStorage()
25+
.filterEnumsByClass(target)
26+
.map(enumArg => ({
27+
target: enumArg.target,
28+
name: enumArg.name,
29+
description: enumArg.description,
30+
values: this.buildEnumValueMetadata(target),
31+
}));
32+
}
33+
34+
buildUnionTypeMetadata(target: any): UnionTypeMetadata[] | undefined {
35+
return getMetadataArgsStorage()
36+
.filterUnionTypeByClass(target)
37+
.map(unionArg => ({
38+
target: unionArg.target,
39+
name: unionArg.name,
40+
resolver: unionArg.resolver,
41+
types: unionArg.types,
42+
description: unionArg.description,
43+
}));
44+
}
45+
46+
protected buildEnumValueMetadata(target: any): EnumValueMetadata[] | undefined {
47+
return getMetadataArgsStorage()
48+
.filterEnumValuesByClass(target)
49+
.map(enumValueArg => ({
50+
target: enumValueArg.target,
51+
name: enumValueArg.name,
52+
value: enumValueArg.value,
53+
description: enumValueArg.description,
54+
}));
55+
}
56+
57+
}

src/metadata-storage/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)