Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for hints with same value on multiple different resolvers of a given DjangoObjectType. #76

Merged
merged 1 commit into from
Oct 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion graphene_django_optimizer/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,9 @@ def _add_optimization_hints(self, source, target):
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)
Expand Down
18 changes: 18 additions & 0 deletions tests/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -82,6 +86,20 @@ def resolve_aux_children_names(root, info):
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")

Expand Down
31 changes: 31 additions & 0 deletions tests/test_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)