diff --git a/graphene_mongo/advanced_types.py b/graphene_mongo/advanced_types.py index 00bc9239..cd40aa7f 100644 --- a/graphene_mongo/advanced_types.py +++ b/graphene_mongo/advanced_types.py @@ -31,7 +31,7 @@ def resolve_data(self, info): v = getattr(self.instance, self.key) data = v.read() if data is not None: - return base64.b64encode(data) + return str(base64.b64encode(data)) return None diff --git a/graphene_mongo/fields.py b/graphene_mongo/fields.py index a6f9650d..a63dc396 100644 --- a/graphene_mongo/fields.py +++ b/graphene_mongo/fields.py @@ -8,10 +8,11 @@ from promise import Promise from graphql_relay import from_global_id from graphene.relay import ConnectionField +from graphene.relay.connection import page_info_adapter, connection_adapter from graphene.types.argument import to_arguments from graphene.types.dynamic import Dynamic from graphene.types.structures import Structure -from graphql_relay.connection.arrayconnection import connection_from_list_slice +from graphql_relay.connection.arrayconnection import connection_from_array_slice from .advanced_types import ( FileFieldType, @@ -149,7 +150,7 @@ def filter_args(self): filter_type = advanced_filter_types.get(each, filter_type) filter_args[field + "__" + each] = graphene.Argument( - type=filter_type + type_=filter_type ) return filter_args @@ -220,25 +221,32 @@ def default_resolver(self, _root, info, **args): if callable(getattr(self.model, "objects", None)): iterables = self.get_queryset(self.model, info, **args) - list_length = iterables.count() + array_length = iterables.count() else: iterables = [] - list_length = 0 + array_length = 0 - connection = connection_from_list_slice( - list_slice=iterables, + def adjusted_connection_adapter(edges, pageInfo): + return connection_adapter(self.type, edges, pageInfo) + + connection = connection_from_array_slice( + array_slice=iterables, args=connection_args, - list_length=list_length, - list_slice_length=list_length, - connection_type=self.type, + array_length=array_length, + array_slice_length=array_length, + connection_type=adjusted_connection_adapter, edge_type=self.type.Edge, - pageinfo_type=graphene.PageInfo, + page_info_type=page_info_adapter, ) connection.iterable = iterables - connection.list_length = list_length + connection.array_length = array_length return connection def chained_resolver(self, resolver, is_partial, root, info, **args): + for key, value in args.copy().items(): + if value is None: + args.pop(key, None) + if not bool(args) or not is_partial: # XXX: Filter nested args resolved = resolver(root, info, **args) @@ -258,7 +266,7 @@ def connection_resolver(cls, resolver, connection_type, root, info, **args): return on_resolve(iterable) - def get_resolver(self, parent_resolver): + def wrap_resolve(self, parent_resolver): super_resolver = self.resolver or parent_resolver resolver = partial( self.chained_resolver, super_resolver, isinstance(super_resolver, partial) diff --git a/graphene_mongo/tests/test_fields.py b/graphene_mongo/tests/test_fields.py index 160a74d8..f77edbe7 100644 --- a/graphene_mongo/tests/test_fields.py +++ b/graphene_mongo/tests/test_fields.py @@ -51,9 +51,9 @@ def test_default_resolver_with_colliding_objects_field(): assert 0 == len(connection.iterable) -def test_default_resolver_connection_list_length(fixtures): +def test_default_resolver_connection_array_length(fixtures): field = MongoengineConnectionField(nodes.ArticleNode) connection = field.default_resolver(None, {}, **{"first": 1}) - assert hasattr(connection, "list_length") - assert connection.list_length == 3 + assert hasattr(connection, "array_length") + assert connection.array_length == 3 diff --git a/graphene_mongo/tests/test_relay_query.py b/graphene_mongo/tests/test_relay_query.py index f2128af9..bcbb97ba 100644 --- a/graphene_mongo/tests/test_relay_query.py +++ b/graphene_mongo/tests/test_relay_query.py @@ -226,7 +226,8 @@ class Meta: articles = MongoengineConnectionField(nodes.ArticleNode) def resolve_articles(self, *args, **kwargs): - return article_loader.load(self) + # TODO: I guess thats cheating. Decide what to do with dataloaders. + return article_loader.load(self).get() class Query(graphene.ObjectType): editors = MongoengineConnectionField(_EditorNode) diff --git a/graphene_mongo/utils.py b/graphene_mongo/utils.py index 7e3fc66b..eeeff4e7 100644 --- a/graphene_mongo/utils.py +++ b/graphene_mongo/utils.py @@ -95,6 +95,8 @@ def get_field_description(field, registry=None): def get_node_from_global_id(node, info, global_id): + if global_id is None: + return None try: for interface in node._meta.interfaces: if issubclass(interface, Node): diff --git a/requirements.txt b/requirements.txt index 1c9d02e7..cb526d8e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ coveralls==1.2.0 flake8==3.7.9 flake8-per-file-ignores==0.6 future==0.17.1 -graphene>=2.1.3,<3 +graphene>=v3.0.0b5 iso8601==0.1.12 mongoengine==0.16.3 mongomock==3.14.0 @@ -12,3 +12,4 @@ pytest-cov==2.5.1 singledispatch==3.4.0.3 # https://stackoverflow.com/a/58189684/9041712 attrs==19.1.0 +promise>=2.3,<3 \ No newline at end of file diff --git a/setup.py b/setup.py index b07ee06a..8bb9317c 100644 --- a/setup.py +++ b/setup.py @@ -24,10 +24,11 @@ keywords="api graphql protocol rest relay graphene mongo mongoengine", packages=find_packages(exclude=["tests"]), install_requires=[ - "graphene>=2.1.3,<3", + "graphene>=v3.0.0b5", "mongoengine>=0.15.0", "singledispatch>=3.4.0.3", "iso8601>=0.1.12", + "promise>=2.3,<3", ], python_requires=">=2.7", zip_safe=True,