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

Optional Pagination #168

Merged
merged 15 commits into from
Nov 12, 2024
Merged

Conversation

fruitymedley
Copy link
Contributor

@fruitymedley fruitymedley commented May 24, 2024

Implements optional pagination as requested in #167

Description

Types of Changes

  • Core
  • Bugfix
  • New feature
  • Enhancement/optimization
  • Documentation

Issues Fixed or Closed by This PR

#167

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • I have tested the changes and verified that they work and don't break anything (as well as I can manage).

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 @fruitymedley - 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: all looks good
  • 🟢 Complexity: 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.

src/strawberry_sqlalchemy_mapper/relay.py Outdated Show resolved Hide resolved
@botberry
Copy link
Member

botberry commented May 24, 2024

Thanks for adding the RELEASE.md file!

Here's a preview of the changelog:


Add an optional function to exclude relationships from relay pagination and use traditional strawberry lists.
Default behavior preserves original behavior for backwords compatibilty.

fruitymedley and others added 4 commits May 24, 2024 16:45
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
@fruitymedley
Copy link
Contributor Author

@bellini666 Hi! Wanted to flag this to you for review since you look like the most recent active contributor, or if you know who would be best, I would greatly appreciate it!

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.

The solution in general looks good. I would just change it to be an argument instead, so it is more aligned to how we do those kind of configurations on strawberry.

Maybe @patrick91 and/or @erikwrede can also take a look at this?

@@ -146,6 +146,20 @@ async def resolve_async(nodes=nodes):
return resolve_nodes(session)


def exclude_relay(
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if this would be better defined in mapper.type as an argument?

Also, the name itself IMO implies you are excluding relay functionality, which is not totally true. My suggestion would be do the argument and call it map_relations_as_list: bool = True, in which you can opt-out as False (would be even better to be the other way around, but then it would be a breaking change)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could see a situation in which a type might have both relay and list. Would it make sense to add a class property in the same vein as __exclude__?

Copy link

codspeed-hq bot commented May 29, 2024

CodSpeed Performance Report

Merging #168 will not alter performance

Comparing fruitymedley:optional-pagination (02ee627) with main (d1fc069)

Summary

✅ 1 untouched benchmarks

@fruitymedley
Copy link
Contributor Author

I've made a few updates in accordance with the suggestions. Please review as available.

@patrick91
Copy link
Member

@fruitymedley would this work for you as a global configuration, instead of a configuration on the type itself?

@novag
Copy link
Contributor

novag commented Sep 27, 2024

@fruitymedley Now that the project has a maintainer again in @Ckk3, perhaps we can get this merged. @Ckk3 What do you think about the global vs typed-based configuration?

@erikwrede
Copy link
Member

erikwrede commented Sep 27, 2024

Sorry, I'm a bit late to the party...

I agree with Patrick about having a global config on how to handle *-n relationships. Having a class attribute seems to be an easy fix, but I'm sceptical about the devX (no linting on field renames or other errors, the schema type will just change)

Another, perhaps more opinionated approach, would be to work with the global config and use an explicit field definition, like doNotUseRelayField: list[MyType] , or even list[auto] on each field that doesn't follow the global config. This is certainly a different approach, but I prefer that it's in line with the declarative style of other strawberry fields.

Another option would be to have a custom strawberry.sqlfield, similar to graphene-sqlalchemy's ORMField which gives an option to input the uselist param.

Generally, I think we should discuss a bit further on this and I'm open to all ideas.
@bellini666 how does strawberry Django handle this?

Copy link
Contributor

@Ckk3 Ckk3 left a comment

Choose a reason for hiding this comment

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

Thanks a lot, @fruitymedley , for your contribution! 🙌 This PR is looking great, and I just have a minor change related to the tests. I haven’t made any changes to the PR itself, but I wanted to note that if think we’ll need to update the documentation later to reflect the new functionality.

I'll also send a separate message soon with my thoughts on the global vs. type-based configuration discussion.

Looking forward to your feedback on the test updates!

assert len(mapped_department_type.__strawberry_definition__._fields) == 3
department_type_fields = mapped_department_type.__strawberry_definition__._fields
name = next(iter(filter(lambda f: f.name == "employees", department_type_fields)))
assert type(name.type) != StrawberryOptional
Copy link
Contributor

Choose a reason for hiding this comment

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

@fruitymedley, I believe the comparison should be done using isinstance(name.type, StrawberryOptional) instead of using !=. This aligns with the conventions we're following in the codebase when checking if a type is StrawberryOptional.

I came across a couple of instances in the code that confirm this pattern:

Here, we're using isinstance to check for StrawberryOptional in the type_.of_type.
Similarly, here, the same pattern is used for type_.

What do you think?

@Ckk3
Copy link
Contributor

Ckk3 commented Sep 29, 2024

@fruitymedley Now that the project has a maintainer again in @Ckk3, perhaps we can get this merged. @Ckk3 What do you think about the global vs typed-based configuration?

Hi everyone!

I don’t have a strong preference, but after reviewing the code and looking at the implementation in Strawberry Django, I think the current approach in this PR solves the issue. However, I believe a global configuration might be a better solution.

Please correct me if I’m wrong, @bellini666 , as I know you’re more familiar with the Django integration.

In Strawberry Django’s documentation, I noticed that pagination can be configured both at the type level and on individual fields.

  • In the Pagination Docs, we see pagination being set using pagination=True inside @strawberry_django.type.
    image

  • Then, in the Fields Docs, under the "Field Customization" section, pagination is set on a specific field within a type.
    image

If I understand correctly, this PR introduces the second approach (configuring pagination on individual fields within a type), but I agree with @erikwrede's point:

devX (no linting on field renames or other errors, the schema type will just change)

I also align with @bellini666 later comment. In my opinion, we should apply this configuration at the type level, similar to @strawberry_django.type(pagination=True), as it simplifies development. Afterward, we could discuss adding an option to configure it on individual fields if needed.

What do you all think? Please let me know if I misunderstood anything, I'm still getting familiar with the Django integration.

@Ckk3 Ckk3 self-assigned this Sep 30, 2024
@Ckk3
Copy link
Contributor

Ckk3 commented Oct 2, 2024

Hi, @fruitymedley , we have fixed the CI, can you please update your branch from main?

@bellini666
Copy link
Member

@Ckk3 @erikwrede so, the way Strawberry Django currently does is to enforce a declarative style, in which you can use auto or properly annotate the relation.

For example:

@strawberry_django.type(Fruit):
class FruitType:
    ...


@strawberry_django.type(Color):
class ColorType:
    # Does not auto resolve to the type, as we don't keep a mapping internally.
    # Instead, one-to-one/many-to-one relations are mapped to `DjangoModelType` and
    # one-to-many/many-to-many are mapped to `list[DjangoModelType]`
    # `DjangoModelType` is a simple type that contains `pk` in it:
    # https://github.com/strawberry-graphql/strawberry-django/blob/main/strawberry_django/fields/types.py#L75
    fruits: auto

    # The recommended way for lists. The integration will still know that we have a
    # relation in the model and do what needs to be done regarding optimization
    fruits: list[Fruit]

    # The same as list above, but use relay connections instead.
    fruits: relay.ListConnection[Fruit]

I know that strawberry-sqlalchemy currently doesn't support the declarative style very well. Hence, a solution like the one proposed here is probably the way to go for now. Still, I'd love to see this integration moving forward to now only allow, but maybe actually enforce that in the future, so it is more aligned to strawberry style and recommendations in general.

@Ckk3
Copy link
Contributor

Ckk3 commented Oct 6, 2024

I agree with @bellini666 , lets continue with this PR when you can @fruitymedley
I also hope we can improve this lib later to make declarative style easier to develop.

@Ckk3
Copy link
Contributor

Ckk3 commented Oct 23, 2024

Hi @fruitymedley,

This PR has been inactive for two weeks. Are you still able to work on it? If not, please let me know so we can continue the development from this point.

@Ckk3
Copy link
Contributor

Ckk3 commented Oct 31, 2024

I will continue the development of this PR.

@codecov-commenter
Copy link

codecov-commenter commented Oct 31, 2024

Codecov Report

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

Project coverage is 85.51%. Comparing base (d1fc069) to head (02ee627).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #168      +/-   ##
==========================================
+ Coverage   85.38%   85.51%   +0.12%     
==========================================
  Files          16       16              
  Lines        1615     1629      +14     
  Branches      128      139      +11     
==========================================
+ Hits         1379     1393      +14     
+ Misses        183      173      -10     
- Partials       53       63      +10     

@Ckk3
Copy link
Contributor

Ckk3 commented Nov 11, 2024

I've fixed this PR tests and update the code with the new strawberry version.
Please take a look again when you can @patrick91 @bellini666 !

@Ckk3
Copy link
Contributor

Ckk3 commented Nov 12, 2024

I'll merge this PR.
Thanks @fruitymedley for your work!

@Ckk3 Ckk3 merged commit 7cd14e8 into strawberry-graphql:main Nov 12, 2024
19 checks passed
@botberry
Copy link
Member

Thanks for contributing to Strawberry! 🎉 You've been invited to join
the Strawberry GraphQL organisation 😊

You can also request a free sticker by filling this form: https://forms.gle/dmnfQUPoY5gZbVT67

And don't forget to join our discord server: https://strawberry.rocks/discord 🔥

@Ckk3 Ckk3 mentioned this pull request Nov 12, 2024
3 tasks
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.

8 participants