Skip to content

Commit

Permalink
Added support for client defined required field
Browse files Browse the repository at this point in the history
  • Loading branch information
xuewei8910 committed Apr 7, 2021
1 parent 7f40198 commit 668d5fd
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 13 deletions.
4 changes: 3 additions & 1 deletion src/execution/execute.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import type {
GraphQLResolveInfo,
GraphQLTypeResolver,
GraphQLList,
GraphQLNonNull,
} from '../type/definition';
import { assertValidSchema } from '../type/validate';
import {
Expand Down Expand Up @@ -597,7 +598,8 @@ function resolveField(
return;
}

const returnType = fieldDef.type;
const returnType = fieldNode.required ? new GraphQLNonNull(fieldDef.type) : fieldDef.type

const resolveFn = fieldDef.resolve ?? exeContext.fieldResolver;

const info = buildResolveInfo(
Expand Down
1 change: 1 addition & 0 deletions src/language/ast.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ export interface FieldNode {
readonly arguments?: ReadonlyArray<ArgumentNode>;
readonly directives?: ReadonlyArray<DirectiveNode>;
readonly selectionSet?: SelectionSetNode;
readonly required?: Boolean;
}

export interface ArgumentNode {
Expand Down
33 changes: 23 additions & 10 deletions src/language/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,10 @@ export class Parser {
if (this.peek(TokenKind.NAME)) {
switch (this._lexer.token.value) {
case 'query':
return this.parseOperationDefinition(true);
case 'mutation':
case 'subscription':
return this.parseOperationDefinition();
return this.parseOperationDefinition(false);
case 'fragment':
return this.parseFragmentDefinition();
case 'schema':
Expand Down Expand Up @@ -236,7 +237,7 @@ export class Parser {
* - SelectionSet
* - OperationType Name? VariableDefinitions? Directives? SelectionSet
*/
parseOperationDefinition(): OperationDefinitionNode {
parseOperationDefinition(allowRequiredField: boolean): OperationDefinitionNode {
const start = this._lexer.token;
if (this.peek(TokenKind.BRACE_L)) {
return {
Expand All @@ -245,7 +246,7 @@ export class Parser {
name: undefined,
variableDefinitions: [],
directives: [],
selectionSet: this.parseSelectionSet(),
selectionSet: this.parseSelectionSet(allowRequiredField),
loc: this.loc(start),
};
}
Expand All @@ -260,7 +261,7 @@ export class Parser {
name,
variableDefinitions: this.parseVariableDefinitions(),
directives: this.parseDirectives(false),
selectionSet: this.parseSelectionSet(),
selectionSet: this.parseSelectionSet(allowRequiredField),
loc: this.loc(start),
};
}
Expand Down Expand Up @@ -326,13 +327,17 @@ export class Parser {
/**
* SelectionSet : { Selection+ }
*/
parseSelectionSet(): SelectionSetNode {
parseSelectionSet(allowRequiredField: boolean): SelectionSetNode {
const start = this._lexer.token;
const _allowRequiredField = allowRequiredField
let parseSelectionFn: () => SelectionNode = function (): SelectionNode {
return this.parseSelection(_allowRequiredField)
}
return {
kind: Kind.SELECTION_SET,
selections: this.many(
TokenKind.BRACE_L,
this.parseSelection,
parseSelectionFn,
TokenKind.BRACE_R,
),
loc: this.loc(start),
Expand All @@ -345,23 +350,30 @@ export class Parser {
* - FragmentSpread
* - InlineFragment
*/
parseSelection(): SelectionNode {
parseSelection(allowRequiredField: boolean): SelectionNode {
return this.peek(TokenKind.SPREAD)
? this.parseFragment()
: this.parseField();
: this.parseField(allowRequiredField);
}

/**
* Field : Alias? Name Arguments? Directives? SelectionSet?
*
* Alias : Name :
*/
parseField(): FieldNode {
parseField(allowRequiredField: boolean): FieldNode {
const start = this._lexer.token;

const nameOrAlias = this.parseName();
let alias;
let name;
let required;
if (allowRequiredField && this.expectOptionalToken(TokenKind.BANG)) {
required = true
} else {
required = false
}

if (this.expectOptionalToken(TokenKind.COLON)) {
alias = nameOrAlias;
name = this.parseName();
Expand All @@ -376,9 +388,10 @@ export class Parser {
arguments: this.parseArguments(false),
directives: this.parseDirectives(false),
selectionSet: this.peek(TokenKind.BRACE_L)
? this.parseSelectionSet()
? this.parseSelectionSet(allowRequiredField)
: undefined,
loc: this.loc(start),
required: required,
};
}

Expand Down
6 changes: 4 additions & 2 deletions src/language/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ const printDocASTReducer: any = {
},
SelectionSet: { leave: ({ selections }) => block(selections) },


Field: {
leave({ alias, name, arguments: args, directives, selectionSet }) {
const prefix = wrap('', alias, ': ') + name;
leave({ alias, name, arguments: args, directives, selectionSet, required }) {
const prefix = wrap('', alias, ': ') + name + (required ? '!' : '');
let argsLine = prefix + wrap('(', join(args, ', '), ')');

if (argsLine.length > MAX_LINE_LENGTH) {
Expand All @@ -67,6 +68,7 @@ const printDocASTReducer: any = {

Argument: { leave: ({ name, value }) => name + ': ' + value },


// Fragments

FragmentSpread: {
Expand Down

0 comments on commit 668d5fd

Please sign in to comment.