Skip to content

Commit 77ffcf2

Browse files
committed
use semantic nullable wrapper only
1 parent 163785d commit 77ffcf2

30 files changed

+286
-367
lines changed

src/execution/__tests__/semantic-nullability-test.ts

+22-8
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { parse } from '../../language/parser';
99
import {
1010
GraphQLNonNull,
1111
GraphQLObjectType,
12-
GraphQLSemanticNonNull,
1312
GraphQLSemanticNullable,
1413
} from '../../type/definition';
1514
import { GraphQLString } from '../../type/scalars';
@@ -29,9 +28,9 @@ describe('Execute: Handles Semantic Nullability', () => {
2928
name: 'DataType',
3029
fields: () => ({
3130
a: { type: new GraphQLSemanticNullable(GraphQLString) },
32-
b: { type: new GraphQLSemanticNonNull(GraphQLString) },
31+
b: { type: GraphQLString },
3332
c: { type: new GraphQLNonNull(GraphQLString) },
34-
d: { type: new GraphQLSemanticNonNull(DeepDataType) },
33+
d: { type: DeepDataType },
3534
}),
3635
});
3736

@@ -49,7 +48,10 @@ describe('Execute: Handles Semantic Nullability', () => {
4948
`);
5049

5150
const result = await execute({
52-
schema: new GraphQLSchema({ query: DataType }),
51+
schema: new GraphQLSchema({
52+
useSemanticNullability: true,
53+
query: DataType,
54+
}),
5355
document,
5456
rootValue: data,
5557
});
@@ -98,7 +100,10 @@ describe('Execute: Handles Semantic Nullability', () => {
98100
.next().value;
99101

100102
const result = await execute({
101-
schema: new GraphQLSchema({ query: DataType }),
103+
schema: new GraphQLSchema({
104+
useSemanticNullability: true,
105+
query: DataType,
106+
}),
102107
document,
103108
rootValue: data,
104109
});
@@ -137,7 +142,10 @@ describe('Execute: Handles Semantic Nullability', () => {
137142
`);
138143

139144
const result = await execute({
140-
schema: new GraphQLSchema({ query: DataType }),
145+
schema: new GraphQLSchema({
146+
useSemanticNullability: true,
147+
query: DataType,
148+
}),
141149
document,
142150
rootValue: data,
143151
});
@@ -180,7 +188,10 @@ describe('Execute: Handles Semantic Nullability', () => {
180188
`);
181189

182190
const result = await execute({
183-
schema: new GraphQLSchema({ query: DataType }),
191+
schema: new GraphQLSchema({
192+
useSemanticNullability: true,
193+
query: DataType,
194+
}),
184195
document,
185196
rootValue: data,
186197
});
@@ -206,7 +217,10 @@ describe('Execute: Handles Semantic Nullability', () => {
206217
`);
207218

208219
const result = await execute({
209-
schema: new GraphQLSchema({ query: DataType }),
220+
schema: new GraphQLSchema({
221+
useSemanticNullability: true,
222+
query: DataType,
223+
}),
210224
document,
211225
rootValue: data,
212226
});

src/execution/execute.ts

+51-76
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ import {
4343
isListType,
4444
isNonNullType,
4545
isObjectType,
46-
isSemanticNonNullType,
4746
isSemanticNullableType,
4847
} from '../type/definition';
4948
import {
@@ -651,109 +650,85 @@ function completeValue(
651650
throw result;
652651
}
653652

654-
// If field type is NonNull, complete for inner type, and throw field error
655-
// if result is null.
653+
let nonNull;
654+
let semanticNull;
655+
let nullableType;
656656
if (isNonNullType(returnType)) {
657-
const completed = completeValue(
658-
exeContext,
659-
returnType.ofType,
660-
fieldNodes,
661-
info,
662-
path,
663-
result,
664-
);
665-
if (completed === null) {
666-
throw new Error(
667-
`Cannot return null for non-nullable field ${info.parentType.name}.${info.fieldName}.`,
668-
);
669-
}
670-
return completed;
657+
nonNull = true;
658+
nullableType = returnType.ofType;
659+
} else if (isSemanticNullableType(returnType)) {
660+
semanticNull = true;
661+
nullableType = returnType.ofType;
662+
} else {
663+
nullableType = returnType;
671664
}
672665

673-
// If field type is SemanticNonNull, complete for inner type, and throw field error
674-
// if result is null and an error doesn't exist.
675-
if (isSemanticNonNullType(returnType)) {
676-
const completed = completeValue(
666+
let completed;
667+
if (result == null) {
668+
// If result value is null or undefined then return null.
669+
completed = null;
670+
} else if (isListType(nullableType)) {
671+
// If field type is List, complete each item in the list with the inner type
672+
completed = completeListValue(
677673
exeContext,
678-
returnType.ofType,
674+
nullableType,
679675
fieldNodes,
680676
info,
681677
path,
682678
result,
683679
);
684-
if (completed === null) {
685-
throw new Error(
686-
`Cannot return null for semantic-non-nullable field ${info.parentType.name}.${info.fieldName}.`,
687-
);
688-
}
689-
return completed;
690-
}
691-
692-
// If field type is SemanticNullable, complete for inner type
693-
if (isSemanticNullableType(returnType)) {
694-
return completeValue(
680+
} else if (isLeafType(nullableType)) {
681+
// If field type is a leaf type, Scalar or Enum, serialize to a valid value,
682+
// returning null if serialization is not possible.
683+
completed = completeLeafValue(nullableType, result);
684+
} else if (isAbstractType(nullableType)) {
685+
// If field type is an abstract type, Interface or Union, determine the
686+
// runtime Object type and complete for that type.
687+
completed = completeAbstractValue(
695688
exeContext,
696-
returnType.ofType,
689+
nullableType,
697690
fieldNodes,
698691
info,
699692
path,
700693
result,
701694
);
702-
}
703-
704-
// If result value is null or undefined then return null.
705-
if (result == null) {
706-
return null;
707-
}
708-
709-
// If field type is List, complete each item in the list with the inner type
710-
if (isListType(returnType)) {
711-
return completeListValue(
695+
} else if (isObjectType(nullableType)) {
696+
// If field type is Object, execute and complete all sub-selections.
697+
completed = completeObjectValue(
712698
exeContext,
713-
returnType,
699+
nullableType,
714700
fieldNodes,
715701
info,
716702
path,
717703
result,
718704
);
705+
} else {
706+
/* c8 ignore next 6 */
707+
// Not reachable, all possible output types have been considered.
708+
invariant(
709+
false,
710+
'Cannot complete value of unexpected output type: ' +
711+
inspect(nullableType),
712+
);
719713
}
720714

721-
// If field type is a leaf type, Scalar or Enum, serialize to a valid value,
722-
// returning null if serialization is not possible.
723-
if (isLeafType(returnType)) {
724-
return completeLeafValue(returnType, result);
725-
}
726-
727-
// If field type is an abstract type, Interface or Union, determine the
728-
// runtime Object type and complete for that type.
729-
if (isAbstractType(returnType)) {
730-
return completeAbstractValue(
731-
exeContext,
732-
returnType,
733-
fieldNodes,
734-
info,
735-
path,
736-
result,
715+
if (nonNull && completed === null) {
716+
throw new Error(
717+
`Cannot return null for non-nullable field ${info.parentType.name}.${info.fieldName}.`,
737718
);
738719
}
739720

740-
// If field type is Object, execute and complete all sub-selections.
741-
if (isObjectType(returnType)) {
742-
return completeObjectValue(
743-
exeContext,
744-
returnType,
745-
fieldNodes,
746-
info,
747-
path,
748-
result,
721+
if (
722+
exeContext.schema.usingSemanticNullability &&
723+
!semanticNull &&
724+
completed === null
725+
) {
726+
throw new Error(
727+
`Cannot return null for semantic-non-nullable field ${info.parentType.name}.${info.fieldName}.`,
749728
);
750729
}
751-
/* c8 ignore next 6 */
752-
// Not reachable, all possible output types have been considered.
753-
invariant(
754-
false,
755-
'Cannot complete value of unexpected output type: ' + inspect(returnType),
756-
);
730+
731+
return completed;
757732
}
758733

759734
/**

src/index.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ export {
4848
GraphQLInputObjectType,
4949
GraphQLList,
5050
GraphQLNonNull,
51-
GraphQLSemanticNonNull,
5251
// Standard GraphQL Scalars
5352
specifiedScalarTypes,
5453
GraphQLInt,
@@ -97,7 +96,7 @@ export {
9796
isInputObjectType,
9897
isListType,
9998
isNonNullType,
100-
isSemanticNonNullType,
99+
isSemanticNullableType,
101100
isInputType,
102101
isOutputType,
103102
isLeafType,
@@ -123,7 +122,7 @@ export {
123122
assertInputObjectType,
124123
assertListType,
125124
assertNonNullType,
126-
assertSemanticNonNullType,
125+
assertSemanticNullableType,
127126
assertInputType,
128127
assertOutputType,
129128
assertLeafType,
@@ -291,7 +290,7 @@ export type {
291290
NamedTypeNode,
292291
ListTypeNode,
293292
NonNullTypeNode,
294-
SemanticNonNullTypeNode,
293+
SemanticNullableTypeNode,
295294
TypeSystemDefinitionNode,
296295
SchemaDefinitionNode,
297296
OperationTypeDefinitionNode,
@@ -485,7 +484,7 @@ export type {
485484
IntrospectionNamedTypeRef,
486485
IntrospectionListTypeRef,
487486
IntrospectionNonNullTypeRef,
488-
IntrospectionSemanticNonNullTypeRef,
487+
IntrospectionSemanticNullableTypeRef,
489488
IntrospectionField,
490489
IntrospectionInputValue,
491490
IntrospectionEnumValue,

src/language/__tests__/parser-test.ts

+4-8
Original file line numberDiff line numberDiff line change
@@ -669,16 +669,12 @@ describe('Parser', () => {
669669
it('parses semantic-non-null types', () => {
670670
const result = parseType('MyType', { useSemanticNullability: true });
671671
expectJSON(result).toDeepEqual({
672-
kind: Kind.SEMANTIC_NON_NULL_TYPE,
672+
kind: Kind.NAMED_TYPE,
673673
loc: { start: 0, end: 6 },
674-
type: {
675-
kind: Kind.NAMED_TYPE,
674+
name: {
675+
kind: Kind.NAME,
676676
loc: { start: 0, end: 6 },
677-
name: {
678-
kind: Kind.NAME,
679-
loc: { start: 0, end: 6 },
680-
value: 'MyType',
681-
},
677+
value: 'MyType',
682678
},
683679
});
684680
});

src/language/__tests__/predicates-test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ describe('AST node predicates', () => {
9292
'NamedType',
9393
'ListType',
9494
'NonNullType',
95-
'SemanticNonNullType',
95+
'SemanticNullableType',
9696
]);
9797
});
9898

src/language/ast.ts

-9
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ export type ASTNode =
161161
| NamedTypeNode
162162
| ListTypeNode
163163
| NonNullTypeNode
164-
| SemanticNonNullTypeNode
165164
| SemanticNullableTypeNode
166165
| SchemaDefinitionNode
167166
| OperationTypeDefinitionNode
@@ -237,7 +236,6 @@ export const QueryDocumentKeys: {
237236
NamedType: ['name'],
238237
ListType: ['type'],
239238
NonNullType: ['type'],
240-
SemanticNonNullType: ['type'],
241239
SemanticNullableType: ['type'],
242240

243241
SchemaDefinition: ['description', 'directives', 'operationTypes'],
@@ -528,7 +526,6 @@ export type TypeNode =
528526
| NamedTypeNode
529527
| ListTypeNode
530528
| NonNullTypeNode
531-
| SemanticNonNullTypeNode
532529
| SemanticNullableTypeNode;
533530

534531
export interface NamedTypeNode {
@@ -549,12 +546,6 @@ export interface NonNullTypeNode {
549546
readonly type: NamedTypeNode | ListTypeNode;
550547
}
551548

552-
export interface SemanticNonNullTypeNode {
553-
readonly kind: Kind.SEMANTIC_NON_NULL_TYPE;
554-
readonly loc?: Location;
555-
readonly type: NamedTypeNode | ListTypeNode;
556-
}
557-
558549
export interface SemanticNullableTypeNode {
559550
readonly kind: Kind.SEMANTIC_NULLABLE_TYPE;
560551
readonly loc?: Location;

src/language/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export type {
6767
NamedTypeNode,
6868
ListTypeNode,
6969
NonNullTypeNode,
70-
SemanticNonNullTypeNode,
70+
SemanticNullableTypeNode,
7171
TypeSystemDefinitionNode,
7272
SchemaDefinitionNode,
7373
OperationTypeDefinitionNode,

src/language/kinds.ts

-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ enum Kind {
3737
NAMED_TYPE = 'NamedType',
3838
LIST_TYPE = 'ListType',
3939
NON_NULL_TYPE = 'NonNullType',
40-
SEMANTIC_NON_NULL_TYPE = 'SemanticNonNullType',
4140
SEMANTIC_NULLABLE_TYPE = 'SemanticNullableType',
4241

4342
/** Type System Definitions */

0 commit comments

Comments
 (0)