From 76465dc39118c1cec010a231f2cbd99d157cfcff Mon Sep 17 00:00:00 2001 From: Felix Meziere <felix.meziere@gmail.com> Date: Fri, 15 Oct 2021 01:29:16 +0100 Subject: [PATCH] Allow for hints with same value on multiple different resolvers of a given DjangoObjectType. (#76) --- graphene_django_optimizer/query.py | 4 +++- tests/schema.py | 18 +++++++++++++++++ tests/test_query.py | 31 ++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/graphene_django_optimizer/query.py b/graphene_django_optimizer/query.py index e64f041..78652a7 100644 --- a/graphene_django_optimizer/query.py +++ b/graphene_django_optimizer/query.py @@ -269,7 +269,9 @@ class QueryOptimizer(object): if source: if not is_iterable(source): source = (source,) - target += source + target += [ + source_item for source_item in source if source_item not in target + ] def _get_name_from_resolver(self, resolver): optimization_hints = self._get_optimization_hints(resolver) diff --git a/tests/schema.py b/tests/schema.py index fc30203..f8124c7 100644 --- a/tests/schema.py +++ b/tests/schema.py @@ -52,6 +52,10 @@ class ItemInterface(graphene.Interface): "tests.schema.ItemType", name=graphene.String(required=True), ) + aux_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, @@ -82,6 +86,20 @@ class ItemInterface(graphene.Interface): def resolve_filtered_children(root, info, name): return getattr(root, "gql_filtered_children_" + name) + @gql_optimizer.resolver_hints( + prefetch_related=lambda info, name: Prefetch( + "children", + queryset=gql_optimizer.query( + Item.objects.filter(name=f"some_prefix {name}"), info + ), + # Different queryset than resolve_filtered_children but same to_attr, on purpose + # to check equality of Prefetch is based only on to_attr attribute, as it is implemented in Django. + to_attr="gql_filtered_children_" + name, + ), + ) + def resolve_aux_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") diff --git a/tests/test_query.py b/tests/test_query.py index fa7339d..6dedac0 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -585,3 +585,34 @@ def test_should_only_use_the_only_and_not_select_related(): items = gql_optimizer.query(qs, info) optimized_items = qs.only("id", "name") assert_query_equality(items, optimized_items) + + +@pytest.mark.django_db +def test_should_accept_two_hints_with_same_prefetch_to_attr_and_keep_one_of_them(): + info = create_resolve_info( + schema, + """ + query { + items(name: "foo") { + filteredChildren(name: "bar") { + id + name + } + auxFilteredChildren(name: "bar") { #Â Same name to generate Prefetch with same to_attr + id + name + } + } + } + """, + ) + 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").only("id", "name"), + to_attr="gql_filtered_children_foo", + ) + ) + assert_query_equality(items, optimized_items) -- GitLab