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

Add support for optional connections #3707

Merged
merged 11 commits into from
Dec 20, 2024
Merged

Add support for optional connections #3707

merged 11 commits into from
Dec 20, 2024

Conversation

patrick91
Copy link
Member

@patrick91 patrick91 commented Nov 20, 2024

Closes #3703

Summary by Sourcery

Add support for optional Relay connections to enhance flexibility in permission handling and update tests and documentation accordingly.

New Features:

  • Add support for making Relay connections optional, allowing for more flexible permission handling.

Documentation:

  • Add a new release note detailing the introduction of optional Relay connections and providing an example of its usage.

Tests:

  • Introduce tests to verify the functionality of optional Relay connections, including scenarios with permissions and different Python versions.

sourcery-ai bot and others added 3 commits November 20, 2024 12:10
Enable nullable Connection types in the connection field decorator by updating type checking logic and adding validation for inner types. Update documentation and add tests to ensure compatibility with permission extensions and different nullable syntax.

New Features:
- Support nullable Connection types in the connection field decorator in strawberry.relay.fields.

Enhancements:
- Update type checking logic to handle Optional[Connection[T]] and Connection[T] | None annotations.

Documentation:
- Update documentation to reflect that connection fields can now be nullable.

Tests:
- Add tests to verify nullable connection fields work correctly with permission extensions and both Optional[Connection[T]] and Connection[T] | None syntax.

Resolves #3703
Copy link
Contributor

sourcery-ai bot commented Nov 20, 2024

Reviewer's Guide by Sourcery

This PR adds support for optional Relay connections in Strawberry GraphQL, allowing connections to be nullable. The implementation modifies the connection field handling to support Optional types and includes type checking adjustments to accommodate this change.

Updated class diagram for Relay connection handling

classDiagram
    class Connection {
        <<interface>>
    }
    class Node {
        <<interface>>
    }
    class StrawberryField {
        +type: Any
    }
    class StrawberryOptional {
        +of_type: Any
    }
    class RelayField {
        +apply(field: StrawberryField) void
        +resolve() void
        +connection_type: Type[Connection[Node]]
    }
    RelayField --> StrawberryField
    RelayField --> StrawberryOptional
    StrawberryField --> Connection
    StrawberryField --> Node
    note for RelayField "Handles optional connection types"
Loading

File-Level Changes

Change Details Files
Added support for optional connection types in the Relay connection field handler
  • Added handling for StrawberryOptional type in connection field application
  • Modified type checking to handle union types in resolver annotations
  • Updated connection type casting to use the inner type instead of the optional wrapper
strawberry/relay/fields.py
Simplified connection type definition to support optional connections
  • Removed specific NodeType overloads in favor of a more flexible Any type
  • Added documentation explaining the type checking limitations with Optional connections
strawberry/relay/fields.py
Added comprehensive tests for optional connections
  • Added test cases for nullable connections with Optional type
  • Added test cases for nullable connections with pipe syntax (Python 3.10+)
  • Added test cases for nullable connections with permission classes
tests/relay/test_connection.py
Fixed typos in documentation and comments
  • Corrected 'di' to 'do' in annotation comments
  • Fixed 'GrapQL' to 'GraphQL' in schema subscribe comments
  • Corrected 'behaviour' spelling
strawberry/annotation.py
strawberry/schema/subscribe.py
strawberry/relay/fields.py

Assessment against linked issues

Issue Objective Addressed Explanation
#3703 Allow strawberry.connection fields to be nullable/optional

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time. You can also use
    this command to specify where the summary should be inserted.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

codspeed-hq bot commented Nov 20, 2024

CodSpeed Performance Report

Merging #3707 will not alter performance

Comparing fix-3703 (304c648) with main (c9dac1d)

Summary

✅ 21 untouched benchmarks

Copy link

codecov bot commented Nov 21, 2024

Codecov Report

Attention: Patch coverage is 98.43750% with 1 line in your changes missing coverage. Please review.

Project coverage is 96.97%. Comparing base (c9dac1d) to head (304c648).
Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3707   +/-   ##
=======================================
  Coverage   96.97%   96.97%           
=======================================
  Files         503      504    +1     
  Lines       33708    33768   +60     
  Branches     5627     5639   +12     
=======================================
+ Hits        32689    32748   +59     
- Misses        809      810    +1     
  Partials      210      210           

@patrick91 patrick91 requested a review from bellini666 December 9, 2024 00:15
@patrick91 patrick91 marked this pull request as ready for review December 9, 2024 00:15
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 @patrick91 - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 3 issues found
  • 🟢 Security: all looks good
  • 🟡 Testing: 1 issue 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 and I'll use the feedback to improve your reviews.

@@ -253,13 +256,18 @@ def apply(self, field: StrawberryField) -> None:
None,
)

if is_union(resolver_type):
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): The current union type handling is unsafe as it assumes the first type argument is the correct one

Consider implementing proper validation of the union type structure to ensure we're handling optional types correctly. The current approach could lead to runtime errors if the assumptions about the type structure don't hold.

@@ -138,7 +138,7 @@ async def subscribe(
middleware_manager,
execution_context_class,
)
# GrapQL-core might return an initial error result instead of an async iterator.
# GraphQL-core might return an initial error result instead of an async iterator.
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick (typo): Fix typo in comment: 'GrapQL' should be 'GraphQL'

Copy link
Member

Choose a reason for hiding this comment

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

Hrm, isn't this suggestion correct? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, the suggestion is correct. The original comment had a typo, "GrapQL," which should indeed be corrected to "GraphQL." This change ensures clarity and accuracy in the code comments. Let me know if you have any other questions or need further clarification!

tests/relay/test_connection.py Outdated Show resolved Hide resolved
RELEASE.md Show resolved Hide resolved
@botberry
Copy link
Member

botberry commented Dec 9, 2024

Thanks for adding the RELEASE.md file!

Here's a preview of the changelog:


This release adds support for making Relay connection optional, this is useful
when you want to add permission classes to the connection and not fail the whole
query if the user doesn't have permission to access the connection.

Example:

import strawberry
from strawberry import relay
from strawberry.permission import BasePermission


class IsAuthenticated(BasePermission):
    message = "User is not authenticated"

    # This method can also be async!
    def has_permission(
        self, source: typing.Any, info: strawberry.Info, **kwargs
    ) -> bool:
        return False


@strawberry.type
class Fruit(relay.Node):
    code: relay.NodeID[int]
    name: str
    weight: float

    @classmethod
    def resolve_nodes(
        cls,
        *,
        info: strawberry.Info,
        node_ids: Iterable[str],
    ):
        return []


@strawberry.type
class Query:
    node: relay.Node = relay.node()

    @relay.connection(
        relay.ListConnection[Fruit] | None, permission_classes=[IsAuthenticated()]
    )
    def fruits(self) -> Iterable[Fruit]:
        # This can be a database query, a generator, an async generator, etc
        return all_fruits.values()

Here's the tweet text:

🆕 Release (next) is out! Thanks to @patrick91 for the PR 👏

Get it here 👉 https://strawberry.rocks/release/(next)

Copy link
Member

@bellini666 bellini666 left a comment

Choose a reason for hiding this comment

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

LGTM :)

Left a couple of suggestions

tests/relay/test_connection.py Outdated Show resolved Hide resolved
Comment on lines 260 to 261
# TODO: actually check if is optional and get correct type
resolver_type = get_args(resolver_type)[0]
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: we can probably use is_optional to check and get_optional_annotation in this line from strawberry.utils.typing

@patrick91 patrick91 merged commit 8a8e3aa into main Dec 20, 2024
103 checks passed
@patrick91 patrick91 deleted the fix-3703 branch December 20, 2024 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for nullable Connection
3 participants