mirror of
https://github.com/graphql-python/graphene.git
synced 2025-02-18 12:30:37 +03:00
Improved lazy type resolvers
This commit is contained in:
parent
bdcd533bf9
commit
cfba52e6f3
|
@ -1,3 +1,4 @@
|
||||||
|
import six
|
||||||
from functools import total_ordering
|
from functools import total_ordering
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,20 +8,36 @@ class BaseType(object):
|
||||||
return getattr(cls, 'T', None)
|
return getattr(cls, 'T', None)
|
||||||
|
|
||||||
|
|
||||||
class LazyType(BaseType):
|
class MountType(BaseType):
|
||||||
def __init__(self, type_str):
|
parent = None
|
||||||
self.type_str = type_str
|
|
||||||
|
|
||||||
|
def mount(self, cls):
|
||||||
|
self.parent = cls
|
||||||
|
|
||||||
|
|
||||||
|
class LazyType(MountType):
|
||||||
|
def __init__(self, type):
|
||||||
|
self.type = type
|
||||||
|
|
||||||
|
@property
|
||||||
def is_self(self):
|
def is_self(self):
|
||||||
return self.type_str == 'self'
|
return self.type == 'self'
|
||||||
|
|
||||||
def internal_type(self, schema):
|
def internal_type(self, schema):
|
||||||
type = schema.get_type(self.type_str)
|
type = None
|
||||||
|
if callable(self.type):
|
||||||
|
type = self.type(self.parent)
|
||||||
|
elif isinstance(self.type, six.string_types):
|
||||||
|
if self.is_self:
|
||||||
|
type = self.parent
|
||||||
|
else:
|
||||||
|
type = schema.get_type(self.type)
|
||||||
|
assert type, 'Type in %s %r cannot be none' % (self.type, self.parent)
|
||||||
return schema.T(type)
|
return schema.T(type)
|
||||||
|
|
||||||
|
|
||||||
@total_ordering
|
@total_ordering
|
||||||
class OrderedType(BaseType):
|
class OrderedType(MountType):
|
||||||
creation_counter = 0
|
creation_counter = 0
|
||||||
|
|
||||||
def __init__(self, _creation_counter=None):
|
def __init__(self, _creation_counter=None):
|
||||||
|
@ -44,6 +61,12 @@ class OrderedType(BaseType):
|
||||||
return self.creation_counter < other.creation_counter
|
return self.creation_counter < other.creation_counter
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
# This is needed because bisect does not take a comparison function.
|
||||||
|
if type(self) == type(other):
|
||||||
|
return self.creation_counter > other.creation_counter
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash((self.creation_counter))
|
return hash((self.creation_counter))
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import six
|
import six
|
||||||
from graphql.core.type import (GraphQLList, GraphQLNonNull)
|
from graphql.core.type import (GraphQLList, GraphQLNonNull)
|
||||||
|
|
||||||
from .base import MountedType, LazyType
|
from .base import MountType, MountedType, LazyType
|
||||||
|
|
||||||
|
|
||||||
class OfType(MountedType):
|
class OfType(MountedType):
|
||||||
|
@ -14,6 +14,11 @@ class OfType(MountedType):
|
||||||
def internal_type(self, schema):
|
def internal_type(self, schema):
|
||||||
return self.T(schema.T(self.of_type))
|
return self.T(schema.T(self.of_type))
|
||||||
|
|
||||||
|
def mount(self, cls):
|
||||||
|
self.parent = cls
|
||||||
|
if isinstance(self.of_type, MountType):
|
||||||
|
self.of_type.mount(cls)
|
||||||
|
|
||||||
|
|
||||||
class List(OfType):
|
class List(OfType):
|
||||||
T = GraphQLList
|
T = GraphQLList
|
||||||
|
|
|
@ -4,7 +4,7 @@ from functools import wraps
|
||||||
|
|
||||||
from graphql.core.type import GraphQLField, GraphQLInputObjectField
|
from graphql.core.type import GraphQLField, GraphQLInputObjectField
|
||||||
|
|
||||||
from .base import LazyType, OrderedType
|
from .base import MountType, LazyType, OrderedType
|
||||||
from .argument import ArgumentsGroup
|
from .argument import ArgumentsGroup
|
||||||
from .definitions import NonNull
|
from .definitions import NonNull
|
||||||
from ...utils import to_camel_case, ProxySnakeDict
|
from ...utils import to_camel_case, ProxySnakeDict
|
||||||
|
@ -47,8 +47,9 @@ class Field(OrderedType):
|
||||||
self.name = to_camel_case(attname)
|
self.name = to_camel_case(attname)
|
||||||
self.attname = attname
|
self.attname = attname
|
||||||
self.object_type = cls
|
self.object_type = cls
|
||||||
if isinstance(self.type, LazyType) and self.type.is_self():
|
self.mount(cls)
|
||||||
self.type = cls
|
if isinstance(self.type, MountType):
|
||||||
|
self.type.mount(cls)
|
||||||
cls._meta.add_field(self)
|
cls._meta.add_field(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -68,13 +69,16 @@ class Field(OrderedType):
|
||||||
return getattr(instance, self.attname, self.default)
|
return getattr(instance, self.attname, self.default)
|
||||||
return default_getter
|
return default_getter
|
||||||
|
|
||||||
|
def get_type(self, schema):
|
||||||
|
return self.type
|
||||||
|
|
||||||
def internal_type(self, schema):
|
def internal_type(self, schema):
|
||||||
resolver = self.resolver
|
resolver = self.resolver
|
||||||
description = self.description
|
description = self.description
|
||||||
arguments = self.arguments
|
arguments = self.arguments
|
||||||
if not description and resolver:
|
if not description and resolver:
|
||||||
description = resolver.__doc__
|
description = resolver.__doc__
|
||||||
type = schema.T(self.type)
|
type = schema.T(self.get_type(schema))
|
||||||
type_objecttype = schema.objecttype(type)
|
type_objecttype = schema.objecttype(type)
|
||||||
if type_objecttype and type_objecttype._meta.is_mutation:
|
if type_objecttype and type_objecttype._meta.is_mutation:
|
||||||
assert len(arguments) == 0
|
assert len(arguments) == 0
|
||||||
|
@ -120,6 +124,9 @@ class InputField(OrderedType):
|
||||||
self.name = to_camel_case(attname)
|
self.name = to_camel_case(attname)
|
||||||
self.attname = attname
|
self.attname = attname
|
||||||
self.object_type = cls
|
self.object_type = cls
|
||||||
|
self.mount(cls)
|
||||||
|
if isinstance(self.type, MountType):
|
||||||
|
self.type.mount(cls)
|
||||||
cls._meta.add_field(self)
|
cls._meta.add_field(self)
|
||||||
|
|
||||||
def internal_type(self, schema):
|
def internal_type(self, schema):
|
||||||
|
|
|
@ -3,6 +3,7 @@ from graphql.core.type import GraphQLField, GraphQLInputObjectField, GraphQLStri
|
||||||
from ..field import Field, InputField
|
from ..field import Field, InputField
|
||||||
from ..scalars import String
|
from ..scalars import String
|
||||||
from ..base import LazyType
|
from ..base import LazyType
|
||||||
|
from ..definitions import List
|
||||||
from graphene.core.types import ObjectType, InputObjectType
|
from graphene.core.types import ObjectType, InputObjectType
|
||||||
from graphene.core.schema import Schema
|
from graphene.core.schema import Schema
|
||||||
|
|
||||||
|
@ -59,7 +60,19 @@ def test_field_self():
|
||||||
class MyObjectType(ObjectType):
|
class MyObjectType(ObjectType):
|
||||||
my_field = field
|
my_field = field
|
||||||
|
|
||||||
assert field.type == MyObjectType
|
schema = Schema()
|
||||||
|
|
||||||
|
assert schema.T(field).type == schema.T(MyObjectType)
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_mounted():
|
||||||
|
field = Field(List('MyObjectType'), name='my_customName')
|
||||||
|
|
||||||
|
class MyObjectType(ObjectType):
|
||||||
|
my_field = field
|
||||||
|
|
||||||
|
assert field.parent == MyObjectType
|
||||||
|
assert field.type.parent == MyObjectType
|
||||||
|
|
||||||
|
|
||||||
def test_field_string_reference():
|
def test_field_string_reference():
|
||||||
|
|
|
@ -23,6 +23,7 @@ class ConnectionField(Field):
|
||||||
def wrap_resolved(self, value, instance, args, info):
|
def wrap_resolved(self, value, instance, args, info):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def resolve(self, instance, args, info):
|
def resolve(self, instance, args, info):
|
||||||
from graphene.relay.types import PageInfo
|
from graphene.relay.types import PageInfo
|
||||||
schema = info.schema.graphene_schema
|
schema = info.schema.graphene_schema
|
||||||
|
@ -50,9 +51,10 @@ class ConnectionField(Field):
|
||||||
def get_edge_type(self, node):
|
def get_edge_type(self, node):
|
||||||
return self.edge_type or node.get_edge_type()
|
return self.edge_type or node.get_edge_type()
|
||||||
|
|
||||||
def internal_type(self, schema):
|
def get_type(self, schema):
|
||||||
from graphene.relay.utils import is_node
|
from graphene.relay.utils import is_node
|
||||||
node = self.get_object_type(schema)
|
type = schema.T(self.type)
|
||||||
|
node = schema.objecttype(type)
|
||||||
assert is_node(node), 'Only nodes have connections.'
|
assert is_node(node), 'Only nodes have connections.'
|
||||||
schema.register(node)
|
schema.register(node)
|
||||||
connection_type = self.get_connection_type(node)
|
connection_type = self.get_connection_type(node)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from graphene.core.fields import BooleanField, Field, ListField, StringField
|
from graphene.core.fields import BooleanField, Field, ListField, StringField
|
||||||
from graphene.core.types import (InputObjectType, Interface, Mutation,
|
from graphene.core.types import (InputObjectType, Interface, Mutation,
|
||||||
ObjectType)
|
ObjectType)
|
||||||
|
from graphene.core.types.base import LazyType
|
||||||
from graphene.core.types.argument import ArgumentsGroup
|
from graphene.core.types.argument import ArgumentsGroup
|
||||||
from graphene.core.types.definitions import NonNull
|
from graphene.core.types.definitions import NonNull
|
||||||
from graphene.relay.fields import GlobalIDField
|
from graphene.relay.fields import GlobalIDField
|
||||||
|
@ -24,7 +25,7 @@ class Edge(ObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
type_name = 'DefaultEdge'
|
type_name = 'DefaultEdge'
|
||||||
|
|
||||||
node = Field(lambda field: field.object_type.node_type,
|
node = Field(LazyType(lambda object_type: object_type.node_type),
|
||||||
description='The item at the end of the edge')
|
description='The item at the end of the edge')
|
||||||
cursor = StringField(
|
cursor = StringField(
|
||||||
required=True, description='A cursor for use in pagination')
|
required=True, description='A cursor for use in pagination')
|
||||||
|
@ -44,7 +45,7 @@ class Connection(ObjectType):
|
||||||
|
|
||||||
page_info = Field(PageInfo, required=True,
|
page_info = Field(PageInfo, required=True,
|
||||||
description='The Information to aid in pagination')
|
description='The Information to aid in pagination')
|
||||||
edges = ListField(lambda field: field.object_type.edge_type,
|
edges = ListField(LazyType(lambda object_type: object_type.edge_type),
|
||||||
description='Information to aid in pagination.')
|
description='Information to aid in pagination.')
|
||||||
|
|
||||||
_connection_data = None
|
_connection_data = None
|
||||||
|
|
Loading…
Reference in New Issue
Block a user