From 5478dd4216b4135442b3219c5df808fef26e5c4b Mon Sep 17 00:00:00 2001 From: nodkz Date: Fri, 27 Apr 2018 15:03:32 +0600 Subject: [PATCH] feat(TypeMapper): add `default(value: mixed)` directive for SDL in InputFieldConfigs ```js const IntRangeITC = InputTypeComposer.create(` input IntRangeInput { min: Int @default(value: 0) max: Int } `); ``` --- src/TypeComposer.d.ts | 2 ++ src/TypeComposer.js | 5 +++++ src/TypeMapper.js | 14 ++++++++++++-- src/__tests__/InputTypeComposer-test.js | 3 ++- src/__tests__/TypeMapper-test.js | 9 +++++---- src/directive/default.js | 15 +++++++++++++++ 6 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 src/directive/default.js diff --git a/src/TypeComposer.d.ts b/src/TypeComposer.d.ts index cba92c86..644a24bf 100644 --- a/src/TypeComposer.d.ts +++ b/src/TypeComposer.d.ts @@ -228,6 +228,8 @@ export class TypeComposer { public getInputTypeComposer(): InputTypeComposer; + public getITC(): InputTypeComposer; + public getResolvers(): Map>; public hasResolver(name: string): boolean; diff --git a/src/TypeComposer.js b/src/TypeComposer.js index 31658b23..d3a11fd7 100644 --- a/src/TypeComposer.js +++ b/src/TypeComposer.js @@ -683,6 +683,11 @@ export class TypeComposer { return this.gqType._gqcInputTypeComposer; } + // Alias for getInputTypeComposer() + getITC(): InputTypeComposer { + return this.getInputTypeComposer(); + } + getResolvers(): Map> { if (!this.gqType._gqcResolvers) { this.gqType._gqcResolvers = new Map(); diff --git a/src/TypeMapper.js b/src/TypeMapper.js index d69c50d1..ef50791d 100644 --- a/src/TypeMapper.js +++ b/src/TypeMapper.js @@ -7,7 +7,7 @@ import { getDescription } from 'graphql/utilities/buildASTSchema'; import keyValMap from 'graphql/jsutils/keyValMap'; import invariant from 'graphql/jsutils/invariant'; import find from 'graphql/jsutils/find'; -import { getArgumentValues } from 'graphql/execution/values'; +import { getArgumentValues, getDirectiveValues } from 'graphql/execution/values'; import type { DocumentNode, ObjectTypeDefinitionNode, @@ -76,6 +76,7 @@ import { Resolver } from './Resolver'; import { TypeStorage } from './TypeStorage'; import type { Thunk } from './utils/definitions'; import { isFunction, isObject } from './utils/is'; +import DefaultDerective from './directive/default'; export type TypeDefinitionString = string; // eg type Name { field: Int } export type TypeWrappedString = string; // eg. Int, Int!, [Int] @@ -651,6 +652,15 @@ function makeSchemaDef(def, schema: SchemaComposer) { } } +function getInputDefaultValue(value: InputValueDefinitionNode, type: GraphQLInputType): mixed { + // check getDirectiveValues become avaliable from 0.10.2 + if (Array.isArray(value.directives) && getDirectiveValues) { + const vars = getDirectiveValues(DefaultDerective, value); + if (vars && vars.hasOwnProperty('value')) return vars.value; + } + return valueFromAST(value.defaultValue, type); +} + function makeInputValues( values: ?$ReadOnlyArray, schema: SchemaComposer @@ -664,7 +674,7 @@ function makeInputValues( return { type, description: getDescription(value), - defaultValue: valueFromAST(value.defaultValue, type), + defaultValue: getInputDefaultValue(value, type), }; } ); diff --git a/src/__tests__/InputTypeComposer-test.js b/src/__tests__/InputTypeComposer-test.js index 56d2a008..3ee01bf4 100644 --- a/src/__tests__/InputTypeComposer-test.js +++ b/src/__tests__/InputTypeComposer-test.js @@ -267,7 +267,7 @@ describe('InputTypeComposer', () => { const itc1 = InputTypeComposer.create( ` input TestTypeTplInput { - f1: String + f1: String @default(value: "new") # Description for some required Int field f2: Int! } @@ -276,6 +276,7 @@ describe('InputTypeComposer', () => { expect(itc1).toBeInstanceOf(InputTypeComposer); expect(itc1.getTypeName()).toBe('TestTypeTplInput'); expect(itc1.getFieldType('f1')).toBe(GraphQLString); + expect((itc1.getField('f1'): any).defaultValue).toBe('new'); expect(itc1.getFieldType('f2')).toBeInstanceOf(GraphQLNonNull); expect((itc1.getFieldType('f2'): any).ofType).toBe(GraphQLInt); }); diff --git a/src/__tests__/TypeMapper-test.js b/src/__tests__/TypeMapper-test.js index fb14647a..bdbba624 100644 --- a/src/__tests__/TypeMapper-test.js +++ b/src/__tests__/TypeMapper-test.js @@ -113,8 +113,8 @@ describe('TypeMapper', () => { const type: GraphQLInputObjectType = (TypeMapper.createType( ` input InputIntRange { - max: Int, - min: Int! + min: Int @default(value: 0) + max: Int! } ` ): any); @@ -124,8 +124,9 @@ describe('TypeMapper', () => { const IntRangeTC = new InputTypeComposer(type); expect(IntRangeTC.getTypeName()).toBe('InputIntRange'); - expect(IntRangeTC.getField('max').type).toBe(GraphQLInt); - expect(IntRangeTC.getField('min').type).toBeInstanceOf(GraphQLNonNull); + expect(IntRangeTC.getField('min').defaultValue).toBe(0); + expect(IntRangeTC.getField('min').type).toBe(GraphQLInt); + expect(IntRangeTC.getField('max').type).toBeInstanceOf(GraphQLNonNull); }); it('should return wrapped type', () => { diff --git a/src/directive/default.js b/src/directive/default.js new file mode 100644 index 00000000..ae946bb4 --- /dev/null +++ b/src/directive/default.js @@ -0,0 +1,15 @@ +/* @flow */ + +import { GraphQLDirective, DirectiveLocation, GraphQLNonNull } from '../graphql'; +import GraphQLJSON from '../type/json'; + +export default new GraphQLDirective({ + name: 'default', + description: 'Provides default value for input field.', + locations: [DirectiveLocation.INPUT_FIELD_DEFINITION], + args: { + value: { + type: new GraphQLNonNull(GraphQLJSON), + }, + }, +});