Skip to content
Snippets Groups Projects
Unverified Commit 055db7d2 authored by NyanKiyoshi's avatar NyanKiyoshi
Browse files

Fix variable handling and null values

parent 16894bc3
No related branches found
No related tags found
No related merge requests found
......@@ -4,6 +4,8 @@ from django.db.models.fields.reverse_related import ManyToOneRel
from django.core.exceptions import FieldDoesNotExist
from django.db.models import ForeignKey, Prefetch
from django.db.models.constants import LOOKUP_SEP
from graphene import InputObjectType
from graphene.types.generic import GenericScalar
from graphene.types.resolver import default_resolver
from graphene_django import DjangoObjectType
from graphene_django.fields import DjangoListField
......@@ -15,7 +17,7 @@ from graphql.language.ast import (
FragmentSpread,
InlineFragment,
Variable,
ObjectValue)
)
from graphql.type.definition import (
GraphQLInterfaceType,
GraphQLUnionType,
......@@ -216,12 +218,10 @@ class QueryOptimizer(object):
if isinstance(value, Variable):
var_name = value.name.value
value = info.variable_values.get(var_name)
if isinstance(value, ObjectValue):
value = {
field.name.value:
self._get_value(info, field.value) for field in value.fields}
if isinstance(value, InputObjectType):
return value.__dict__
else:
value = value.value
return GenericScalar.parse_literal(value)
return value
def _optimize_field_by_hints(self, store, selection, field_def, parent_type):
......
......@@ -13,7 +13,7 @@ from graphql.execution.base import (
from graphql.pyutils.default_ordered_dict import DefaultOrderedDict
def create_execution_context(schema, request_string):
def create_execution_context(schema, request_string, variables=None):
source = Source(request_string, 'GraphQL request')
document_ast = parse(source)
return ExecutionContext(
......@@ -21,7 +21,7 @@ def create_execution_context(schema, request_string):
document_ast,
root_value=None,
context_value=None,
variable_values=None,
variable_values=variables,
operation_name=None,
executor=None,
middleware=None,
......@@ -42,8 +42,8 @@ def get_field_asts_from_execution_context(exe_context):
return field_asts
def create_resolve_info(schema, request_string):
exe_context = create_execution_context(schema, request_string)
def create_resolve_info(schema, request_string, variables=None):
exe_context = create_execution_context(schema, request_string, variables)
parent_type = get_operation_root_type(schema, exe_context.operation)
field_asts = get_field_asts_from_execution_context(exe_context)
......
......@@ -17,6 +17,18 @@ from .models import (
)
def _prefetch_children(info, filter_input):
if filter_input is None:
filter_input = {}
gte = filter_input.get('value', {}).get('gte', 0)
return Prefetch(
'children',
queryset=gql_optimizer.query(Item.objects.filter(value__gte=int(gte)), info),
to_attr='gql_custom_filtered_children',
)
class RangeInput(graphene.InputObjectType):
gte = graphene.Field(graphene.Int)
......@@ -42,13 +54,7 @@ class ItemInterface(graphene.Interface):
)
children_custom_filtered = gql_optimizer.field(
ConnectionField('tests.schema.ItemConnection', filter_input=ItemFilterInput()),
prefetch_related=lambda info, filter_input: Prefetch(
'children',
queryset=gql_optimizer.query(
Item.objects.filter(
value__gte=int(filter_input.get('value', {}).get('gte', 0))), info),
to_attr='gql_custom_filtered_children',
),
prefetch_related=_prefetch_children,
)
def resolve_foo(root, info):
......
......@@ -56,7 +56,6 @@ def test_should_optimize_with_prefetch_related_as_a_string():
assert_query_equality(items, optimized_items)
# @pytest.mark.django_db
def test_should_optimize_with_prefetch_related_as_a_function():
# parent = Item.objects.create(name='foo')
# Item.objects.create(name='bar', parent=parent)
......@@ -85,28 +84,49 @@ def test_should_optimize_with_prefetch_related_as_a_function():
assert_query_equality(items, optimized_items)
def test_should_optimize_with_prefetch_related_as_a_function_with_object_input():
info = create_resolve_info(schema, '''
query {
items(name: "foo") {
id
foo
childrenCustomFiltered(filterInput: {value: {gte: 11}}) {
id
value
QUERY_CONNECTION_NESTED_INPUT_OBJECT = '''
query($filters: ItemFilterInput) {
items(name: "foo") {
id
foo
childrenCustomFiltered(filterInput: $filters) {
edges {
node {
id
value
}
}
}
}
''')
qs = Item.objects.filter(value__gte=11)
items = gql_optimizer.query(qs, info)
optimized_items = qs.prefetch_related(
}
'''
@pytest.mark.parametrize("variables, expected_gte", [
({"filters": {'value': {'gte': 11}}}, 11),
({}, 0),
])
@pytest.mark.django_db
def test_should_optimize_with_prefetch_related_as_a_function_with_object_input(
variables, expected_gte
):
"""This test attempt to provide a nested object as a variable and a null value
as a filter. The objective is to ensure null and nested objects are properly
resolved.
"""
query = QUERY_CONNECTION_NESTED_INPUT_OBJECT
info = create_resolve_info(schema, query, variables=variables)
optimized_items = Item.objects.prefetch_related(
Prefetch(
'children',
queryset=Item.objects.filter(value__gte=11),
queryset=Item.objects.only('id', 'value').filter(value__gte=expected_gte),
to_attr='gql_custom_filtered_children',
),
)
items = gql_optimizer.query(Item.objects, info)
assert_query_equality(items, optimized_items)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment