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)