def test_should_optimize_with_prefetch_related_as_a_function(): # parent = Item.objects.create(name='foo') # Item.objects.create(name='bar', parent=parent) # Item.objects.create(name='foobar', parent=parent) info = create_resolve_info( schema, ''' query { items(name: "foo") { id foo filteredChildren(name: "bar") { id foo } } } ''') qs = Item.objects.filter(name='foo') items = gql_optimizer.query(qs, info) optimized_items = qs.prefetch_related( Prefetch( 'children', queryset=Item.objects.filter(name='bar'), to_attr='gql_filtered_children_bar', ), ) assert_query_equality(items, optimized_items)
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', )
def test_should_optimize_with_only_hint(): info = create_resolve_info(schema, ''' query { items(name: "foo") { id title } } ''') qs = Item.objects.filter(name='foo') items = gql_optimizer.query(qs, info) optimized_items = qs.only('id', 'name') assert_query_equality(items, optimized_items)
def test_should_optimize_with_annotate_as_a_function(): info = create_resolve_info( schema, ''' query { items(name: "foo") { id nameWithPrefix(prefix: "The") } } ''') qs = Item.objects.filter(name='foo') items = gql_optimizer.query(qs, info) optimized_items = qs.only("id").annotate(gql_name_with_prefix=Concat( Value('The'), Value(' '), F('name'), output_field=CharField())) assert_query_equality(items, optimized_items)
def test_should_optimize_non_django_field_if_it_has_an_optimization_hint_in_the_field(): info = create_resolve_info(schema, ''' query { items(name: "bar") { id foo father { id } } } ''') qs = Item.objects.filter(name='bar') items = gql_optimizer.query(qs, info) optimized_items = qs.select_related('parent') assert_query_equality(items, optimized_items)
def test_should_annotate_queries_in_relay_schema(): info = create_resolve_info(schema, ''' query { relayItems { edges { node { id childrenCount } } } } ''') qs = Item.objects.all() items = gql_optimizer.query(qs, info) optimized_items = qs.only("id").annotate(gql_children_count=Count('children')) assert_query_equality(items, optimized_items)
def test_should_optimize_with_prefetch_related_as_a_string(): # parent = Item.objects.create(name='foo') # Item.objects.create(name='bar', parent=parent) # Item.objects.create(name='foobar', parent=parent) info = create_resolve_info( schema, ''' query { items(name: "foo") { id foo auxChildrenNames } } ''') qs = Item.objects.filter(name='foo') items = gql_optimizer.query(qs, info) optimized_items = qs.prefetch_related('children') assert_query_equality(items, optimized_items)
def test_should_reduce_number_of_queries_in_relay_schema_by_using_select_related(): info = create_resolve_info(schema, ''' query { relayItems { edges { node { id foo parent { id } } } } } ''') qs = Item.objects.filter(name='bar') items = gql_optimizer.query(qs, info) optimized_items = qs.select_related('parent') assert_query_equality(items, optimized_items)
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.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)
def test_should_reduce_number_of_queries_in_relay_schema_by_using_prefetch_related(): info = create_resolve_info(schema, ''' query { relayItems { edges { node { id foo children { id foo } } } } } ''') qs = Item.objects.filter(name='foo') items = gql_optimizer.query(qs, info) optimized_items = qs.prefetch_related('children') assert_query_equality(items, optimized_items)
def test_should_prefetch_related_when_using_annotated_select_related_in_relay_schema(): info = create_resolve_info(schema, ''' query { relayItems { edges { node { id parent { id childrenCount } } } } } ''') qs = Item.objects.all() items = gql_optimizer.query(qs, info) prefetch_qs = Item.objects.only("pk").annotate(gql_children_count=Count('children')) prefetch = Prefetch('parent', queryset=prefetch_qs) optimized_items = qs.only("id", "parent_id").prefetch_related(prefetch) assert_query_equality(items, optimized_items)
def test_should_optimize_non_django_field_if_it_has_an_optimization_hint_in_the_resolver( ): # parent = Item.objects.create(name='foo') # Item.objects.create(name='bar', parent=parent) # Item.objects.create(name='foobar', parent=parent) info = create_resolve_info( schema, ''' query { items(name: "foo") { id foo childrenNames } } ''') qs = Item.objects.filter(name='foo') items = gql_optimizer.query(qs, info) optimized_items = qs.prefetch_related( Prefetch( 'children', queryset=Item.objects.only('id', 'parent_id'), ), ) assert_query_equality(items, optimized_items)
def test_should_optimize_query_by_only_requesting_id_field(): try: from django.db.models import DEFERRED # noqa: F401 except ImportError: # Query cannot be optimized if DEFERRED is not present. # When the ConnectionField is used, it will throw the following error: # Expected value of type "ItemNode" but got: Item_Deferred_item_id_parent_id. return info = create_resolve_info(schema, ''' query { relayItems { edges { node { id } } } } ''') qs = Item.objects.filter(name='foo') items = gql_optimizer.query(qs, info) optimized_items = qs.only('id') assert_query_equality(items, optimized_items)
class ItemInterface(graphene.Interface): id = graphene.ID(required=True) parent_id = graphene.ID() foo = graphene.String() title = graphene.String() unoptimized_title = graphene.String() item_type = graphene.String() father = graphene.Field('tests.schema.ItemType') all_children = graphene.List('tests.schema.ItemType') prefetched_children = graphene.List('tests.schema.ItemType') children_names = graphene.String() aux_children_names = graphene.String() filtered_children = graphene.List( 'tests.schema.ItemType', name=graphene.String(required=True), ) children_custom_filtered = gql_optimizer.field( ConnectionField('tests.schema.ItemConnection', filter_input=ItemFilterInput()), prefetch_related=_prefetch_children, ) children_count = graphene.Int() name_with_prefix = graphene.String(prefix=graphene.String(required=True)) def resolve_foo(root, info): return 'bar' @gql_optimizer.resolver_hints( model_field='children', ) def resolve_children_names(root, info): return ' '.join(item.name for item in root.children.all()) @gql_optimizer.resolver_hints(prefetch_related=lambda info: Prefetch( "children", queryset=gql_optimizer.QueryOptimizer( info, parent_id_field="parent_id").optimize(Item.objects.all()), to_attr="gql_prefetched_children", )) def resolve_prefetched_children(root, info): return getattr(root, 'gql_prefetched_children') @gql_optimizer.resolver_hints( prefetch_related='children', ) def resolve_aux_children_names(root, info): return ' '.join(item.name for item in root.children.all()) @gql_optimizer.resolver_hints( prefetch_related=lambda info, name: Prefetch( 'children', queryset=gql_optimizer.query(Item.objects.filter(name=name), info), to_attr='gql_filtered_children_' + name, ), ) def resolve_filtered_children(root, info, name): return getattr(root, 'gql_filtered_children_' + name) def resolve_children_custom_filtered(root, info, *_args): return getattr(root, 'gql_custom_filtered_children') @gql_optimizer.resolver_hints( annotate={'gql_children_count': Count('children')}) def resolve_children_count(root, info): return getattr(root, 'gql_children_count') @gql_optimizer.resolver_hints( annotate=lambda info, prefix: { 'gql_name_with_prefix': Concat( Value(prefix), Value(' '), F('name'), output_field=CharField()) }) def resolve_name_with_prefix(root, info, prefix): return getattr(root, 'gql_name_with_prefix')
def resolve_other_items(root, info): return gql_optimizer.query(OtherItemType.objects.all(), info)
def resolve_relay_items(root, info, **kwargs): return gql_optimizer.query(Item.objects.all(), info)
def resolve_items(root, info, name): return gql_optimizer.query(Item.objects.filter(name=name), info)