Skip to content

Commit

Permalink
use semantic nullable wrapper only
Browse files Browse the repository at this point in the history
  • Loading branch information
yaacovCR committed Nov 10, 2024
1 parent 163785d commit 77ffcf2
Show file tree
Hide file tree
Showing 30 changed files with 286 additions and 367 deletions.
30 changes: 22 additions & 8 deletions src/execution/__tests__/semantic-nullability-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { parse } from '../../language/parser';
import {
GraphQLNonNull,
GraphQLObjectType,
GraphQLSemanticNonNull,
GraphQLSemanticNullable,
} from '../../type/definition';
import { GraphQLString } from '../../type/scalars';
Expand All @@ -29,9 +28,9 @@ describe('Execute: Handles Semantic Nullability', () => {
name: 'DataType',
fields: () => ({
a: { type: new GraphQLSemanticNullable(GraphQLString) },
b: { type: new GraphQLSemanticNonNull(GraphQLString) },
b: { type: GraphQLString },
c: { type: new GraphQLNonNull(GraphQLString) },
d: { type: new GraphQLSemanticNonNull(DeepDataType) },
d: { type: DeepDataType },
}),
});

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

const result = await execute({
schema: new GraphQLSchema({ query: DataType }),
schema: new GraphQLSchema({
useSemanticNullability: true,
query: DataType,
}),
document,
rootValue: data,
});
Expand Down Expand Up @@ -98,7 +100,10 @@ describe('Execute: Handles Semantic Nullability', () => {
.next().value;

const result = await execute({
schema: new GraphQLSchema({ query: DataType }),
schema: new GraphQLSchema({
useSemanticNullability: true,
query: DataType,
}),
document,
rootValue: data,
});
Expand Down Expand Up @@ -137,7 +142,10 @@ describe('Execute: Handles Semantic Nullability', () => {
`);

const result = await execute({
schema: new GraphQLSchema({ query: DataType }),
schema: new GraphQLSchema({
useSemanticNullability: true,
query: DataType,
}),
document,
rootValue: data,
});
Expand Down Expand Up @@ -180,7 +188,10 @@ describe('Execute: Handles Semantic Nullability', () => {
`);

const result = await execute({
schema: new GraphQLSchema({ query: DataType }),
schema: new GraphQLSchema({
useSemanticNullability: true,
query: DataType,
}),
document,
rootValue: data,
});
Expand All @@ -206,7 +217,10 @@ describe('Execute: Handles Semantic Nullability', () => {
`);

const result = await execute({
schema: new GraphQLSchema({ query: DataType }),
schema: new GraphQLSchema({
useSemanticNullability: true,
query: DataType,
}),
document,
rootValue: data,
});
Expand Down
127 changes: 51 additions & 76 deletions src/execution/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ import {
isListType,
isNonNullType,
isObjectType,
isSemanticNonNullType,
isSemanticNullableType,
} from '../type/definition';
import {
Expand Down Expand Up @@ -651,109 +650,85 @@ function completeValue(
throw result;
}

// If field type is NonNull, complete for inner type, and throw field error
// if result is null.
let nonNull;
let semanticNull;
let nullableType;
if (isNonNullType(returnType)) {
const completed = completeValue(
exeContext,
returnType.ofType,
fieldNodes,
info,
path,
result,
);
if (completed === null) {
throw new Error(
`Cannot return null for non-nullable field ${info.parentType.name}.${info.fieldName}.`,
);
}
return completed;
nonNull = true;
nullableType = returnType.ofType;
} else if (isSemanticNullableType(returnType)) {
semanticNull = true;
nullableType = returnType.ofType;
} else {
nullableType = returnType;
}

// If field type is SemanticNonNull, complete for inner type, and throw field error
// if result is null and an error doesn't exist.
if (isSemanticNonNullType(returnType)) {
const completed = completeValue(
let completed;
if (result == null) {
// If result value is null or undefined then return null.
completed = null;
} else if (isListType(nullableType)) {
// If field type is List, complete each item in the list with the inner type
completed = completeListValue(
exeContext,
returnType.ofType,
nullableType,
fieldNodes,
info,
path,
result,
);
if (completed === null) {
throw new Error(
`Cannot return null for semantic-non-nullable field ${info.parentType.name}.${info.fieldName}.`,
);
}
return completed;
}

// If field type is SemanticNullable, complete for inner type
if (isSemanticNullableType(returnType)) {
return completeValue(
} else if (isLeafType(nullableType)) {
// If field type is a leaf type, Scalar or Enum, serialize to a valid value,
// returning null if serialization is not possible.
completed = completeLeafValue(nullableType, result);
} else if (isAbstractType(nullableType)) {
// If field type is an abstract type, Interface or Union, determine the
// runtime Object type and complete for that type.
completed = completeAbstractValue(
exeContext,
returnType.ofType,
nullableType,
fieldNodes,
info,
path,
result,
);
}

// If result value is null or undefined then return null.
if (result == null) {
return null;
}

// If field type is List, complete each item in the list with the inner type
if (isListType(returnType)) {
return completeListValue(
} else if (isObjectType(nullableType)) {
// If field type is Object, execute and complete all sub-selections.
completed = completeObjectValue(
exeContext,
returnType,
nullableType,
fieldNodes,
info,
path,
result,
);
} else {
/* c8 ignore next 6 */
// Not reachable, all possible output types have been considered.
invariant(
false,
'Cannot complete value of unexpected output type: ' +
inspect(nullableType),
);
}

// If field type is a leaf type, Scalar or Enum, serialize to a valid value,
// returning null if serialization is not possible.
if (isLeafType(returnType)) {
return completeLeafValue(returnType, result);
}

// If field type is an abstract type, Interface or Union, determine the
// runtime Object type and complete for that type.
if (isAbstractType(returnType)) {
return completeAbstractValue(
exeContext,
returnType,
fieldNodes,
info,
path,
result,
if (nonNull && completed === null) {
throw new Error(
`Cannot return null for non-nullable field ${info.parentType.name}.${info.fieldName}.`,
);
}

// If field type is Object, execute and complete all sub-selections.
if (isObjectType(returnType)) {
return completeObjectValue(
exeContext,
returnType,
fieldNodes,
info,
path,
result,
if (
exeContext.schema.usingSemanticNullability &&
!semanticNull &&
completed === null
) {
throw new Error(
`Cannot return null for semantic-non-nullable field ${info.parentType.name}.${info.fieldName}.`,
);
}
/* c8 ignore next 6 */
// Not reachable, all possible output types have been considered.
invariant(
false,
'Cannot complete value of unexpected output type: ' + inspect(returnType),
);

return completed;
}

/**
Expand Down
9 changes: 4 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export {
GraphQLInputObjectType,
GraphQLList,
GraphQLNonNull,
GraphQLSemanticNonNull,
// Standard GraphQL Scalars
specifiedScalarTypes,
GraphQLInt,
Expand Down Expand Up @@ -97,7 +96,7 @@ export {
isInputObjectType,
isListType,
isNonNullType,
isSemanticNonNullType,
isSemanticNullableType,
isInputType,
isOutputType,
isLeafType,
Expand All @@ -123,7 +122,7 @@ export {
assertInputObjectType,
assertListType,
assertNonNullType,
assertSemanticNonNullType,
assertSemanticNullableType,
assertInputType,
assertOutputType,
assertLeafType,
Expand Down Expand Up @@ -291,7 +290,7 @@ export type {
NamedTypeNode,
ListTypeNode,
NonNullTypeNode,
SemanticNonNullTypeNode,
SemanticNullableTypeNode,
TypeSystemDefinitionNode,
SchemaDefinitionNode,
OperationTypeDefinitionNode,
Expand Down Expand Up @@ -485,7 +484,7 @@ export type {
IntrospectionNamedTypeRef,
IntrospectionListTypeRef,
IntrospectionNonNullTypeRef,
IntrospectionSemanticNonNullTypeRef,
IntrospectionSemanticNullableTypeRef,
IntrospectionField,
IntrospectionInputValue,
IntrospectionEnumValue,
Expand Down
12 changes: 4 additions & 8 deletions src/language/__tests__/parser-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -669,16 +669,12 @@ describe('Parser', () => {
it('parses semantic-non-null types', () => {
const result = parseType('MyType', { useSemanticNullability: true });
expectJSON(result).toDeepEqual({
kind: Kind.SEMANTIC_NON_NULL_TYPE,
kind: Kind.NAMED_TYPE,
loc: { start: 0, end: 6 },
type: {
kind: Kind.NAMED_TYPE,
name: {
kind: Kind.NAME,
loc: { start: 0, end: 6 },
name: {
kind: Kind.NAME,
loc: { start: 0, end: 6 },
value: 'MyType',
},
value: 'MyType',
},
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/language/__tests__/predicates-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ describe('AST node predicates', () => {
'NamedType',
'ListType',
'NonNullType',
'SemanticNonNullType',
'SemanticNullableType',
]);
});

Expand Down
9 changes: 0 additions & 9 deletions src/language/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ export type ASTNode =
| NamedTypeNode
| ListTypeNode
| NonNullTypeNode
| SemanticNonNullTypeNode
| SemanticNullableTypeNode
| SchemaDefinitionNode
| OperationTypeDefinitionNode
Expand Down Expand Up @@ -237,7 +236,6 @@ export const QueryDocumentKeys: {
NamedType: ['name'],
ListType: ['type'],
NonNullType: ['type'],
SemanticNonNullType: ['type'],
SemanticNullableType: ['type'],

SchemaDefinition: ['description', 'directives', 'operationTypes'],
Expand Down Expand Up @@ -528,7 +526,6 @@ export type TypeNode =
| NamedTypeNode
| ListTypeNode
| NonNullTypeNode
| SemanticNonNullTypeNode
| SemanticNullableTypeNode;

export interface NamedTypeNode {
Expand All @@ -549,12 +546,6 @@ export interface NonNullTypeNode {
readonly type: NamedTypeNode | ListTypeNode;
}

export interface SemanticNonNullTypeNode {
readonly kind: Kind.SEMANTIC_NON_NULL_TYPE;
readonly loc?: Location;
readonly type: NamedTypeNode | ListTypeNode;
}

export interface SemanticNullableTypeNode {
readonly kind: Kind.SEMANTIC_NULLABLE_TYPE;
readonly loc?: Location;
Expand Down
2 changes: 1 addition & 1 deletion src/language/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export type {
NamedTypeNode,
ListTypeNode,
NonNullTypeNode,
SemanticNonNullTypeNode,
SemanticNullableTypeNode,
TypeSystemDefinitionNode,
SchemaDefinitionNode,
OperationTypeDefinitionNode,
Expand Down
1 change: 0 additions & 1 deletion src/language/kinds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ enum Kind {
NAMED_TYPE = 'NamedType',
LIST_TYPE = 'ListType',
NON_NULL_TYPE = 'NonNullType',
SEMANTIC_NON_NULL_TYPE = 'SemanticNonNullType',
SEMANTIC_NULLABLE_TYPE = 'SemanticNullableType',

/** Type System Definitions */
Expand Down
Loading

0 comments on commit 77ffcf2

Please sign in to comment.