Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: add nullable type definition
  • Loading branch information
KingDarBoja committed Mar 24, 2020
commit 0a9a36fc085dae9eba9ce4be9c576683d60a26c0
78 changes: 58 additions & 20 deletions graphql/type/definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,6 @@ def is_input_type(type_):
)


def is_output_type(type_):
# type: (Any) -> bool
named_type = get_named_type(type_)
return isinstance(
named_type,
(
GraphQLScalarType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLEnumType,
),
)


def get_nullable_type(type_):
if isinstance(type_, GraphQLNonNull):
return type_.of_type
Expand Down Expand Up @@ -738,12 +723,40 @@ def is_same_type(self, other):
)


# These types can all accept null as a value.
graphql_nullable_types = (
GraphQLScalarType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLEnumType,
GraphQLInputObjectType,
GraphQLList,
)

GraphQLNullableType = Union[
GraphQLScalarType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLEnumType,
GraphQLInputObjectType,
GraphQLList,
]


def is_nullable_type(type_):
# type: (Any) -> bool
return isinstance(type_, graphql_nullable_types)


class GraphQLNonNull(GraphQLType):
"""Non-Null Modifier

A non-null is a kind of type marker, a wrapping type which points to another type. Non-null types enforce that their values are never null
and can ensure an error is raised if this ever occurs during a request. It is useful for fields which you can make a strong guarantee on
non-nullability, for example usually the id field of a database row will never be null.
A non-null is a kind of type marker, a wrapping type which points to another type. Non-null types enforce
that their values are never null and can ensure an error is raised if this ever occurs during a request.
It is useful for fields which you can make a strong guarantee on non-nullability,
for example usually the id field of a database row will never be null.

Example:

Expand All @@ -760,13 +773,13 @@ class RowType(GraphQLObjectType):

def __init__(
self,
type_, # type: Union[GraphQLList, GraphQLObjectType, GraphQLScalarType, GraphQLInputObjectType, GraphQLInterfaceType]
type_, # type: GraphQLNullableType
):
# type: (...) -> None
assert is_type(type_) and not isinstance(
type_, GraphQLNonNull
), "Can only create NonNull of a Nullable GraphQLType but got: {}.".format(type_)
self.of_type = type_ # type: Union[GraphQLList, GraphQLObjectType, GraphQLScalarType, GraphQLInputObjectType, GraphQLInterfaceType]
self.of_type = type_ # type: GraphQLNullableType

def __str__(self):
# type: () -> str
Expand All @@ -778,6 +791,31 @@ def is_same_type(self, other):
)


# These types may be used as output types as the result of fields.
graphql_output_types = (
GraphQLScalarType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLEnumType,
)

GraphQLOutputType = Union[
GraphQLScalarType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLEnumType,
GraphQLNullableType
]


def is_output_type(type_):
# type: (Any) -> bool
named_type = get_named_type(type_)
return isinstance(named_type, graphql_output_types)


def is_union_type(type_):
# type: (Any) -> bool
return isinstance(type_, GraphQLUnionType)
Expand Down
56 changes: 33 additions & 23 deletions graphql/validation/rules/overlapping_fields_can_be_merged.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import itertools
from collections import OrderedDict

from typing import cast

from ...error import GraphQLError
from ...language import ast
from ...language.printer import print_ast
Expand All @@ -10,8 +12,11 @@
GraphQLList,
GraphQLNonNull,
GraphQLObjectType,
GraphQLOutputType,
get_named_type,
is_leaf_type,
is_list_type,
is_non_null_type,
)
from ...utils.type_comparators import is_equal_type
from ...utils.type_from_ast import type_from_ast
Expand Down Expand Up @@ -545,7 +550,7 @@ def _find_conflict(

# Two field calls must have the same arguments.
if not _same_arguments(ast1.arguments, ast2.arguments):
return ((response_name, "they have differing arguments"), [ast1], [ast2])
return (response_name, "they have differing arguments"), [ast1], [ast2]

if type1 and type2 and do_types_conflict(type1, type2):
return (
Expand Down Expand Up @@ -685,37 +690,42 @@ def _subfield_conflicts(
if conflicts:
return (
(response_name, [conflict[0] for conflict in conflicts]), # type: ignore
tuple(itertools.chain([ast1], *[conflict[1] for conflict in conflicts])),
tuple(itertools.chain([ast2], *[conflict[2] for conflict in conflicts])),
list(itertools.chain([ast1], *[conflict[1] for conflict in conflicts])),
list(itertools.chain([ast2], *[conflict[2] for conflict in conflicts])),
)
return None


def do_types_conflict(type1, type2):
# type: (GraphQLScalarType, GraphQLScalarType) -> bool
if isinstance(type1, GraphQLList):
if isinstance(type2, GraphQLList):
return do_types_conflict(type1.of_type, type2.of_type)
return True

if isinstance(type2, GraphQLList):
if isinstance(type1, GraphQLList):
return do_types_conflict(type1.of_type, type2.of_type)
return True
# type: (GraphQLOutputType, GraphQLOutputType) -> bool
"""Check whether two types conflict

if isinstance(type1, GraphQLNonNull):
if isinstance(type2, GraphQLNonNull):
return do_types_conflict(type1.of_type, type2.of_type)
Two types conflict if both types could not apply to a value simultaneously.
Composite types are ignored as their individual field types will be compared later
recursively. However List and Non-Null types must match.
"""
if is_list_type(type1):
return (
do_types_conflict(
cast(GraphQLList, type1).of_type, cast(GraphQLList, type2).of_type
)
if is_list_type(type2)
else True
)
if is_list_type(type2):
return True

if isinstance(type2, GraphQLNonNull):
if isinstance(type1, GraphQLNonNull):
return do_types_conflict(type1.of_type, type2.of_type)
if is_non_null_type(type1):
return (
do_types_conflict(
cast(GraphQLNonNull, type1).of_type, cast(GraphQLNonNull, type2).of_type
)
if is_non_null_type(type2)
else True
)
if is_non_null_type(type2):
return True

if is_leaf_type(type1) or is_leaf_type(type2):
return type1 != type2

return type1 is not type2
return False


Expand Down