Skip to content

WIP: Graphql next #905

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions graphene_django/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
)
from graphene.types.json import JSONString
from graphene.utils.str_converters import to_camel_case, to_const
from graphql import assert_valid_name
from graphql import assert_valid_name, GraphQLError

from .settings import graphene_settings
from .compat import ArrayField, HStoreField, JSONField, RangeField
Expand All @@ -34,7 +34,7 @@ def convert_choice_name(name):
name = to_const(force_str(name))
try:
assert_valid_name(name)
except AssertionError:
except GraphQLError:
name = "A_%s" % name
return name

Expand Down Expand Up @@ -64,7 +64,7 @@ def convert_choices_to_named_enum_with_descriptions(name, choices):
class EnumWithDescriptionsType(object):
@property
def description(self):
return named_choices_descriptions[self.name]
return str(named_choices_descriptions[self.name])

return Enum(name, list(named_choices), type=EnumWithDescriptionsType)

Expand Down Expand Up @@ -276,3 +276,12 @@ def convert_postgres_range_to_string(field, registry=None):
if not isinstance(inner_type, (List, NonNull)):
inner_type = type(inner_type)
return List(inner_type, description=field.help_text, required=not field.null)


from django.utils.functional import Promise
from graphql.pyutils import register_description


# Register Django lazy()-wrapped values as GraphQL description/help_text.
# This is needed for using lazy translations, see https://github.com/graphql-python/graphql-core-next/issues/58.
register_description(Promise)
2 changes: 1 addition & 1 deletion graphene_django/debug/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def get_debug_promise(self):
if not self.debug_promise:
self.debug_promise = Promise.all(self.promises)
self.promises = []
return self.debug_promise.then(self.on_resolve_all_promises)
return self.debug_promise.then(self.on_resolve_all_promises).get()

def on_resolve_all_promises(self, values):
if self.promises:
Expand Down
16 changes: 8 additions & 8 deletions graphene_django/debug/tests/test_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class Meta:

class Query(graphene.ObjectType):
reporter = graphene.Field(ReporterType)
debug = graphene.Field(DjangoDebug, name="__debug")
debug = graphene.Field(DjangoDebug, name="_debug")

def resolve_reporter(self, info, **args):
return Reporter.objects.first()
Expand All @@ -82,7 +82,7 @@ def resolve_reporter(self, info, **args):
pets { edges { node { lastName } } }
} } }
}
__debug {
_debug {
sql {
rawSql
}
Expand Down Expand Up @@ -110,12 +110,12 @@ def resolve_reporter(self, info, **args):
)
assert not result.errors
query = str(Reporter.objects.order_by("pk")[:1].query)
assert result.data["__debug"]["sql"][0]["rawSql"] == query
assert "COUNT" in result.data["__debug"]["sql"][1]["rawSql"]
assert "tests_reporter_pets" in result.data["__debug"]["sql"][2]["rawSql"]
assert "COUNT" in result.data["__debug"]["sql"][3]["rawSql"]
assert "tests_reporter_pets" in result.data["__debug"]["sql"][4]["rawSql"]
assert len(result.data["__debug"]["sql"]) == 5
assert result.data["_debug"]["sql"][0]["rawSql"] == query
assert "COUNT" in result.data["_debug"]["sql"][1]["rawSql"]
assert "tests_reporter_pets" in result.data["_debug"]["sql"][2]["rawSql"]
assert "COUNT" in result.data["_debug"]["sql"][3]["rawSql"]
assert "tests_reporter_pets" in result.data["_debug"]["sql"][4]["rawSql"]
assert len(result.data["_debug"]["sql"]) == 5

assert result.data["reporter"] == expected["reporter"]

Expand Down
16 changes: 9 additions & 7 deletions graphene_django/fields.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from functools import partial

from django.db.models.query import QuerySet
from graphql_relay.connection.arrayconnection import connection_from_list_slice
from graphene.relay.connection import page_info_adapter, connection_adapter

from graphql_relay.connection.arrayconnection import connection_from_array_slice
from promise import Promise

from graphene import NonNull
from graphene.relay import ConnectionField, PageInfo
from graphene.relay import ConnectionField
from graphene.types import Field, List

from .settings import graphene_settings
Expand Down Expand Up @@ -122,15 +124,15 @@ def resolve_connection(cls, connection, args, iterable):
_len = iterable.count()
else:
_len = len(iterable)
connection = connection_from_list_slice(
connection = connection_from_array_slice(
iterable,
args,
slice_start=0,
list_length=_len,
list_slice_length=_len,
connection_type=connection,
array_length=_len,
array_slice_length=_len,
connection_type=partial(connection_adapter, connection),
edge_type=connection.Edge,
pageinfo_type=PageInfo,
page_info_type=page_info_adapter,
)
connection.iterable = iterable
connection.length = _len
Expand Down
106 changes: 71 additions & 35 deletions graphene_django/filter/tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -806,38 +806,56 @@ class Query(ObjectType):

assert str(schema) == dedent(
"""\
schema {
query: Query
type Query {
pets(before: String = null, after: String = null, first: Int = null, last: Int = null, age: Int = null): PetTypeConnection
}

interface Node {
id: ID!
type PetTypeConnection {
\"""Pagination data for this connection.\"""
pageInfo: PageInfo!

\"""Contains the nodes in this connection.\"""
edges: [PetTypeEdge]!
}

\"""
The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.
\"""
type PageInfo {
\"""When paginating forwards, are there more items?\"""
hasNextPage: Boolean!

\"""When paginating backwards, are there more items?\"""
hasPreviousPage: Boolean!

\"""When paginating backwards, the cursor to continue.\"""
startCursor: String

\"""When paginating forwards, the cursor to continue.\"""
endCursor: String
}

type PetType implements Node {
age: Int!
id: ID!
}

type PetTypeConnection {
pageInfo: PageInfo!
edges: [PetTypeEdge]!
}


\"""A Relay edge containing a `PetType` and its cursor.\"""
type PetTypeEdge {
\"""The item at the end of the edge\"""
node: PetType

\"""A cursor for use in pagination\"""
cursor: String!
}

type Query {
pets(before: String, after: String, first: Int, last: Int, age: Int): PetTypeConnection

type PetType implements Node {
\"""\"""
age: Int!

\"""The ID of the object\"""
id: ID!
}

\"""An object with an ID\"""
interface Node {
\"""The ID of the object\"""
id: ID!
}
"""
)
Expand All @@ -858,40 +876,58 @@ class Query(ObjectType):

assert str(schema) == dedent(
"""\
schema {
query: Query
type Query {
pets(before: String = null, after: String = null, first: Int = null, last: Int = null, age: Int = null, age_Isnull: Boolean = null, age_Lt: Int = null): PetTypeConnection
}

interface Node {
id: ID!
type PetTypeConnection {
\"""Pagination data for this connection.\"""
pageInfo: PageInfo!

\"""Contains the nodes in this connection.\"""
edges: [PetTypeEdge]!
}

\"""
The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.
\"""
type PageInfo {
\"""When paginating forwards, are there more items?\"""
hasNextPage: Boolean!

\"""When paginating backwards, are there more items?\"""
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}

type PetType implements Node {
age: Int!
id: ID!
}
\"""When paginating backwards, the cursor to continue.\"""
startCursor: String

type PetTypeConnection {
pageInfo: PageInfo!
edges: [PetTypeEdge]!
\"""When paginating forwards, the cursor to continue.\"""
endCursor: String
}

\"""A Relay edge containing a `PetType` and its cursor.\"""
type PetTypeEdge {
\"""The item at the end of the edge\"""
node: PetType

\"""A cursor for use in pagination\"""
cursor: String!
}

type Query {
pets(before: String, after: String, first: Int, last: Int, age: Int, age_Isnull: Boolean, age_Lt: Int): PetTypeConnection
type PetType implements Node {
\"""\"""
age: Int!

\"""The ID of the object\"""
id: ID!
}
"""

\"""An object with an ID\"""
interface Node {
\"""The ID of the object\"""
id: ID!
}
"""
)


Expand Down
2 changes: 1 addition & 1 deletion graphene_django/management/commands/graphql_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def save_json_file(self, out, schema_dict, indent):

def save_graphql_file(self, out, schema):
with open(out, "w") as outfile:
outfile.write(print_schema(schema))
outfile.write(print_schema(schema.graphql_schema))

def get_schema(self, schema, out, indent):
schema_dict = {"data": schema.introspect()}
Expand Down
1 change: 1 addition & 0 deletions graphene_django/rest_framework/tests/test_mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def mock_info():
None,
None,
None,
path=None,
schema=None,
fragments=None,
root_value=None,
Expand Down
4 changes: 0 additions & 4 deletions graphene_django/tests/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ class Query(ObjectType):
schema_output = handle.write.call_args[0][0]
assert schema_output == dedent(
"""\
schema {
query: Query
}

type Query {
hi: String
}
Expand Down
21 changes: 11 additions & 10 deletions graphene_django/tests/test_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,9 +612,9 @@ class Query(graphene.ObjectType):

result = schema.execute(query)
assert len(result.errors) == 1
assert str(result.errors[0]) == (
assert str(result.errors[0]).startswith(
"You must provide a `first` or `last` value to properly "
"paginate the `allReporters` connection."
"paginate the `allReporters` connection.\n"
)
assert result.data == expected

Expand Down Expand Up @@ -653,9 +653,9 @@ class Query(graphene.ObjectType):

result = schema.execute(query)
assert len(result.errors) == 1
assert str(result.errors[0]) == (
assert str(result.errors[0]).startswith(
"Requesting 101 records on the `allReporters` connection "
"exceeds the `first` limit of 100 records."
"exceeds the `first` limit of 100 records.\n"
)
assert result.data == expected

Expand Down Expand Up @@ -694,9 +694,9 @@ class Query(graphene.ObjectType):

result = schema.execute(query)
assert len(result.errors) == 1
assert str(result.errors[0]) == (
assert str(result.errors[0]).startswith(
"Requesting 101 records on the `allReporters` connection "
"exceeds the `last` limit of 100 records."
"exceeds the `last` limit of 100 records.\n"
)
assert result.data == expected

Expand All @@ -713,7 +713,7 @@ class Query(graphene.ObjectType):
all_reporters = DjangoConnectionField(ReporterType)

def resolve_all_reporters(self, info, **args):
return Promise.resolve([Reporter(id=1)])
return Promise.resolve([Reporter(id=1)]).get()

schema = graphene.Schema(query=Query)
query = """
Expand Down Expand Up @@ -842,7 +842,7 @@ class Meta:
articles = DjangoConnectionField(ArticleType)

def resolve_articles(self, info, **args):
return article_loader.load(self.id)
return article_loader.load(self.id).get()

class Query(graphene.ObjectType):
all_reporters = DjangoConnectionField(ReporterType)
Expand Down Expand Up @@ -1075,7 +1075,7 @@ class Meta:
class Query(graphene.ObjectType):
films = DjangoConnectionField(FilmType)

def resolve_films(root, info):
def resolve_films(root, info, **kwargs):
qs = Film.objects.prefetch_related("reporters")
return qs

Expand Down Expand Up @@ -1105,6 +1105,7 @@ def resolve_films(root, info):
}
"""
schema = graphene.Schema(query=Query)

with django_assert_num_queries(3) as captured:
result = schema.execute(query)
assert not result.errors
Expand All @@ -1127,7 +1128,7 @@ class Meta:
class Query(graphene.ObjectType):
films = DjangoConnectionField(FilmType)

def resolve_films(root, info):
def resolve_films(root, info, **kwargs):
qs = Film.objects.prefetch_related("reporters")
return qs.annotate(reporters_count=models.Count("reporters"))

Expand Down
Loading