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

fix: Make sure the optimizer calls the type's get_queryset for nested lists/connections #568

Merged
merged 1 commit into from
Jun 29, 2024

Conversation

bellini666
Copy link
Member

@bellini666 bellini666 commented Jun 29, 2024

Fix #562

Summary by Sourcery

This pull request fixes an issue where the optimizer was not calling the type's get_queryset method for nested lists and connections. It also refactors the optimizer to use _default_manager for prefetching when prefetch_custom_queryset is enabled. Additionally, a new test is added to ensure the correct behavior.

  • Bug Fixes:
    • Ensure the optimizer calls the type's get_queryset method for nested lists and connections.
  • Enhancements:
    • Refactor the optimizer to use _default_manager for prefetching when prefetch_custom_queryset is enabled, otherwise use _base_manager.
  • Tests:
    • Add a test to verify that the optimizer calls the type's get_queryset method for nested lists and connections.

@bellini666 bellini666 self-assigned this Jun 29, 2024
Copy link
Contributor

sourcery-ai bot commented Jun 29, 2024

Reviewer's Guide by Sourcery

This pull request addresses issue #562 by ensuring that the optimizer calls the type's get_queryset method for nested lists and connections. The changes include modifications to the optimizer logic in strawberry_django/optimizer.py, the addition of a new test in tests/test_optimizer.py, and an update to the GraphQL schema in tests/projects/schema.py.

File-Level Changes

Files Changes
tests/test_optimizer.py
strawberry_django/optimizer.py
Enhanced the optimizer to call the type's get_queryset for nested lists/connections and added corresponding tests to validate this behavior.

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @bellini666 - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟡 Testing: 5 issues found
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

else:
qs = remote_model._base_manager.all() # type: ignore

f_type = field.type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Resolved field type

The resolution of field.type to f_type is a good step. Ensure that all possible types are correctly handled in the subsequent logic.

Suggested change
f_type = field.type
f_type = field.type
if isinstance(f_type, LazyType):
f_type = f_type.resolve_type()
elif isinstance(f_type, SomeOtherType):
f_type = handle_some_other_type(f_type)
elif isinstance(f_type, AnotherType):
f_type = handle_another_type(f_type)

@@ -1325,3 +1325,43 @@ def test_nested_prefetch_with_multiple_levels(db, gql_client: GraphQLTestClient)
"issues": expected_issues,
},
}


@pytest.mark.django_db(transaction=True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider adding a test for when get_queryset is not called

It would be beneficial to add a test case to ensure that get_queryset is not called when prefetch_custom_queryset is disabled. This will help verify that the default behavior is maintained.

Suggested change
@pytest.mark.django_db(transaction=True)
@pytest.mark.django_db(transaction=True)
def test_nested_prefetch_with_get_queryset_disabled(db):
# Setup your test data here
# Call the function or method that should not call get_queryset
# Assert that get_queryset was not called



@pytest.mark.django_db(transaction=True)
def test_nested_prefetch_with_get_queryset(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Test function name could be more descriptive

Consider renaming the test function to something more descriptive, such as test_nested_prefetch_calls_get_queryset_when_enabled. This will make it clearer what specific behavior is being tested.

Suggested change
def test_nested_prefetch_with_get_queryset(
def test_nested_prefetch_calls_get_queryset_when_enabled(

gql_client: GraphQLTestClient,
mocker: MockerFixture,
):
mock_get_queryset = mocker.spy(StaffType, "get_queryset")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider adding assertions for the query result

It would be helpful to add assertions to verify the structure and content of the query result. This ensures that the query returns the expected data.

Suggested change
mock_get_queryset = mocker.spy(StaffType, "get_queryset")
mock_get_queryset = mocker.spy(StaffType, "get_queryset")
response = gql_client.execute(query)
assert response is not None
assert "data" in response
assert "errors" not in response

for u in [user, staff]:
Assignee.objects.create(user=u, issue=issue)

res = gql_client.query(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider adding error handling tests

It would be beneficial to add tests that handle potential errors, such as when the id provided does not exist. This will help ensure that the code handles such cases gracefully.

Suggested change
res = gql_client.query(
try:
res = gql_client.query(
query,
{"id": to_base64("IssueType", issue.pk)},
)
except SomeSpecificException as e:
# Handle the exception or log it
res = None

{"id": to_base64("IssueType", issue.pk)},
)

assert isinstance(res.data, dict)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider using more specific assertions

Instead of just checking if res.data is a dictionary, consider using more specific assertions to verify the exact structure and content of the response. This will make the test more robust.

Suggested change
assert isinstance(res.data, dict)
assert "issue" in res.data
assert "id" in res.data["issue"]
assert res.data["issue"]["id"] == to_base64("IssueType", issue.pk)

Comment on lines +1352 to +1353
for u in [user, staff]:
Assignee.objects.create(user=u, issue=issue)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Avoid loops in tests. (no-loop-in-tests)

ExplanationAvoid complex code, like loops, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:

  • loops
  • conditionals

Some ways to fix this:

  • Use parametrized tests to get rid of the loop.
  • Move the complex logic into helpers.
  • Move the complex part into pytest fixtures.

Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / Don't Put Logic in Tests

@codecov-commenter
Copy link

codecov-commenter commented Jun 29, 2024

Codecov Report

Attention: Patch coverage is 75.00000% with 3 lines in your changes missing coverage. Please review.

Project coverage is 89.00%. Comparing base (1023674) to head (2f85416).

Files Patch % Lines
strawberry_django/optimizer.py 75.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #568      +/-   ##
==========================================
+ Coverage   88.88%   89.00%   +0.11%     
==========================================
  Files          41       41              
  Lines        3545     3547       +2     
==========================================
+ Hits         3151     3157       +6     
+ Misses        394      390       -4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@bellini666 bellini666 merged commit c81a037 into main Jun 29, 2024
22 checks passed
@bellini666 bellini666 deleted the fix_custom_manager branch June 29, 2024 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Optimizer ignores custom type querysets
2 participants