-
Notifications
You must be signed in to change notification settings - Fork 11
Feature - Union Type #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export * from './union-type.decorator'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { MetadataStorage } from '../metadata-storage'; | ||
| import { UnionOpton } from '../metadata'; | ||
|
|
||
| /** | ||
| * Union Type. ref: http://graphql.org/learn/schema/#union-types | ||
| * @param option Options for a Union Type | ||
| */ | ||
| export function UnionType<T>(option: UnionOpton<T>) { | ||
| return function (target: any) { | ||
| MetadataStorage.addUnionMetadata({ | ||
| name: target.name, | ||
| types: option.types, | ||
| resolver: option.resolver, | ||
| description: option.description, | ||
| }); | ||
| } as Function; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| export * from './decorator'; | ||
| export * from './decorator/'; | ||
| export * from './metadata/options'; | ||
| export { schemaFactory } from './schema_factory'; | ||
| export * from './order-by-item'; | ||
| export * from './pagination.type'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export * from './metadata-storage'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import { UnionTypeMetadata } from '../metadata/types/union.metadata'; | ||
|
|
||
| const unionMetadata: UnionTypeMetadata[] = []; | ||
|
|
||
| const MetadataStorage = { | ||
|
|
||
| addUnionMetadata: function(metadata: UnionTypeMetadata) { | ||
| unionMetadata.push(metadata); | ||
| }, | ||
| getUnionMetadata: function(): UnionTypeMetadata[] { | ||
| return unionMetadata; | ||
| }, | ||
| containsUnionMetadata: function(name: string) { | ||
| return unionMetadata.some(metadata => metadata.name === name); | ||
| }, | ||
| }; | ||
|
|
||
| export { MetadataStorage }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export * from './options'; | ||
| export * from './types'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export * from './union.option'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| /** | ||
| * Arguments for a Union type on graphql schema | ||
| */ | ||
| export interface UnionOpton<T> { | ||
| /** | ||
| * (Optional) Description | ||
| */ | ||
| description?: string; | ||
|
|
||
| /** | ||
| * Concrete object types | ||
| */ | ||
| types: any[]; | ||
|
|
||
| /** | ||
| * Resolver function to inform schema what type should be returned based on the value provided | ||
| */ | ||
| resolver: (obj: T, context: any, info: any) => Promise<string> | string | null; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export * from './union.metadata'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| export interface UnionTypeMetadata { | ||
| name: string; | ||
| description?: string; | ||
| types: any[]; | ||
| resolver: (obj: any, context: any, info: any) => Promise<string> | string | null; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| import 'reflect-metadata'; | ||
|
|
||
| import * as D from './decorator'; | ||
| import * as DD from './decorator/'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I fell a little bit uneasy with these "duplicated" decorators
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. managed to expose everything from inside the old |
||
| import * as graphql from 'graphql'; | ||
|
|
||
| import { SchemaFactoryError, SchemaFactoryErrorType, schemaFactory } from './schema_factory'; | ||
|
|
@@ -354,4 +355,54 @@ describe('schemaFactory', function() { | |
|
|
||
| }); | ||
|
|
||
| describe('UnionType', () => { | ||
|
|
||
| it('creates schema with union type', () => { | ||
|
|
||
| @D.ObjectType() | ||
| class ObjA { @D.Field() fieldA: string; } | ||
|
|
||
| @D.ObjectType() | ||
| class ObjB { @D.Field() fieldB: string; } | ||
|
|
||
| type MyType = ObjA | ObjB; | ||
| @DD.UnionType<MyType>({ | ||
| types: [ObjA, ObjB], | ||
| resolver: (obj: any): string | null => { | ||
| if (obj.fieldA) { return ObjA.name; } | ||
| if (obj.fieldB) { return ObjB.name; } | ||
| return null; | ||
| }, | ||
| }) | ||
| class MyUnionType { } | ||
|
|
||
|
|
||
| @D.ObjectType() class Query { | ||
| @D.Field({ type: MyUnionType }) | ||
| async aQuery(): Promise<MyType> { | ||
| return { fieldA: '' }; | ||
| } | ||
| } | ||
| @D.Schema() class Schema { @D.Query() query: Query; } | ||
| const schema = schemaFactory(Schema); | ||
| const ast = parse(` | ||
| query { | ||
| aQuery { | ||
| ...on ObjA { | ||
| fieldA | ||
| } | ||
| ...on ObjB { | ||
| fieldB | ||
| } | ||
| } | ||
| }`); | ||
|
|
||
| assert.deepEqual(validate(schema, ast), []); | ||
|
|
||
| }); | ||
|
|
||
| }); | ||
|
|
||
|
|
||
|
|
||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export * from './union.type-factory'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import * as graphql from 'graphql'; | ||
| import { MetadataStorage } from '../metadata-storage'; | ||
| import { UnionTypeMetadata } from '../metadata'; | ||
| import { objectTypeFactory } from '../object_type_factory'; | ||
|
|
||
| export function unionTypeFactory(name: string, isInput: boolean): graphql.GraphQLUnionType { | ||
| return MetadataStorage.getUnionMetadata() | ||
| .filter(union => union.name === name) | ||
| .map(union => { | ||
| return new graphql.GraphQLUnionType({ | ||
| description: union.description, | ||
| name: union.name, | ||
| resolveType: union.resolver, | ||
| types: union.types | ||
| .map(type => objectTypeFactory(type, isInput)) | ||
| .filter(_ => _), //filter null values | ||
| }); | ||
| }) | ||
| .find((_, index) => index === 0) || null; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the purpose of this
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just to be explicit in the return type instead of returning |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo