diff --git a/graphene_django_optimizer/query.py b/graphene_django_optimizer/query.py index e64f041f5e44cdea4989425914ef23fa5f87f7d0..78652a730cd51243173810c7111bae1941f799f5 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 fc30203a53f33d2c468599d751538d58c1b02c78..f8124c7cba82e01d21669122a8ab5fae27392c45 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 fa7339d574bd306d2f084321b083bd97ddf4c1f1..6dedac0a4ec2e03b3aae9b1a295341d2cdb6c85b 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)