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

Enable sorting when batching is enabled #355

Merged
merged 7 commits into from
Sep 9, 2022

Conversation

PaulSchweizer
Copy link
Collaborator

This is a followup of our discussion from July 18th about batching and sorting.
I took a deeper dive into the batching feature and have a better understanding of it now.
Basically the core issue was, that the batching resolver did not take care of running the initial query. Instead, the initial query had to be run "manually" in a custom "resolve_" field as indicated in the tests:

def resolve_articles(self, info):

That of course bypassed the "get_query" function in the resolver and thus also made sorting "impossible".
Let me know what you think.

# Cache this across `batch_load_fn` calls
# This is so SQL string generation is cached under-the-hood via `bakery`
# Caching the relationship loader for each relationship prop.
RELATIONSHIP_LOADERS_CACHE = {}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We store the loaders per relationship so each item accesses the same cached result ensuring that the selectin is only triggered once

)
RELATIONSHIP_LOADERS_CACHE[relationship_prop] = loader
else:
loader.loop = get_event_loop()
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm not 100% sure about this. Do any of you see issues with this?

Copy link
Member

Choose a reason for hiding this comment

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

Why do we need the get_event_loop() call in the else part? Isn't that initially covered by aiodataloader already, and shouldn't the cache also get a full reset if the event loop changes (implying thread restart/change)?

aiodataloader recommends to create a new loader for each request, this would keep the loaders between different queries, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Makse sense, I changed it

Copy link
Contributor

Choose a reason for hiding this comment

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

September update: There is also preliminary work in Graphene to vendor the DataLoader from aiodataloader into Graphene, and also change it's __init__ behavior to not ask for an even loop so early on init. Just warning because that might touch the same points we are touching here.

)


class ArticleReader(Base):
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Had to add some deeper nesting in the test data for more robust tests

Copy link
Collaborator

Choose a reason for hiding this comment

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

I added a Tags class in #357. Will see if there's a way to consolidate over there after this is merged.

batching = True
connection_class = Connection

class Query(graphene.ObjectType):
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

As mentioned, the original test schema defines custom resolve_ methods which I find odd, but maybe people use it like that. We use it like this.

Copy link
Member

Choose a reason for hiding this comment

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

Also using it the way you suggest it, LGTM. Original schema doesn't use relay - without the relay connection field classes your resolvers don't automatically generate the SQA-Queries.

)
session.add(reporter_1)
reporter_2 = Reporter(
first_name='Reporter_2',
first_name='Reporter_2',
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

unfortunately there were some flake8 errors I had to fix, so ignore these indentation changes

@erikwrede
Copy link
Member

asc_name = get_name(column.key, True)

Changing this to field_name would fix the errors with sqa-13.
It seems like column_prop of Reporter has the name set to something similar to %(4447102096 anon)s at the time of sort enum generation. This causes def sort_enum_for_object_type to generate a sort enum with field names not allowed by GQL (%(4447102096 anon)s_ASC & %(4447102096 anon)s_DESC), causing the test failure. Couldn't figure out why get_schema does not reproduce the same behavior although the same models were used.

@PaulSchweizer
Copy link
Collaborator Author

I still need to investigate those failing tests

@codecov-commenter
Copy link

codecov-commenter commented Aug 6, 2022

Codecov Report

Merging #355 (027ea0e) into master (bb7af4b) will increase coverage by 0.12%.
The diff coverage is 96.38%.

@@            Coverage Diff             @@
##           master     #355      +/-   ##
==========================================
+ Coverage   96.37%   96.50%   +0.12%     
==========================================
  Files           9        9              
  Lines         773      801      +28     
==========================================
+ Hits          745      773      +28     
  Misses         28       28              
Impacted Files Coverage Δ
graphene_sqlalchemy/batching.py 95.45% <94.11%> (+1.70%) ⬆️
graphene_sqlalchemy/fields.py 99.15% <97.87%> (+0.13%) ⬆️
graphene_sqlalchemy/enums.py 97.80% <100.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@PaulSchweizer
Copy link
Collaborator Author

The tests pass now, the remaining issue was that sqla1.2 is creating slighlty different select statments so my asserts where not working there. This is ready from my side now, please give it another look.

Copy link
Member

@erikwrede erikwrede left a comment

Choose a reason for hiding this comment

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

Tested this locally. Working nicely!
I suggested a few minor adjustments. Please check my comments.

graphene_sqlalchemy/batching.py Show resolved Hide resolved
graphene_sqlalchemy/enums.py Show resolved Hide resolved
graphene_sqlalchemy/fields.py Show resolved Hide resolved
batching = True
connection_class = Connection

class Query(graphene.ObjectType):
Copy link
Member

Choose a reason for hiding this comment

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

Also using it the way you suggest it, LGTM. Original schema doesn't use relay - without the relay connection field classes your resolvers don't automatically generate the SQA-Queries.

@erikwrede erikwrede mentioned this pull request Aug 12, 2022
9 tasks
Copy link
Collaborator

@sabard sabard left a comment

Choose a reason for hiding this comment

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

Aside from Erik's comments, all LGTM! Let me know if you'd like me to write a test case for custom ORMField attributes.

graphene_sqlalchemy/enums.py Show resolved Hide resolved
)


class ArticleReader(Base):
Copy link
Collaborator

Choose a reason for hiding this comment

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

I added a Tags class in #357. Will see if there's a way to consolidate over there after this is merged.

@PaulSchweizer
Copy link
Collaborator Author

It would be great @sabard, if you could write the test for the potential issue you have in mind. If it fails I will look into it and work on a solution.

Copy link
Collaborator

@sabard sabard left a comment

Choose a reason for hiding this comment

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

Looks like all works well for custom ORMField names.

Off topic, but is sorting supported on non-Relay-style batching? I wasn't able to get it to work; maybe deserves its own test if supported?

graphene_sqlalchemy/tests/test_batching.py Show resolved Hide resolved
graphene_sqlalchemy/tests/test_batching.py Show resolved Hide resolved
@sabard sabard self-requested a review September 9, 2022 14:49
@sabard sabard requested a review from erikwrede September 9, 2022 14:53
@erikwrede
Copy link
Member

erikwrede commented Sep 9, 2022

@PaulSchweizer @sabard are we ready to merge?

@erikwrede erikwrede merged commit 43df4eb into master Sep 9, 2022
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.

5 participants