Skip to content

fix: refactor resolvers to better follow Relay spec#2457

Merged
jasonbahl merged 21 commits intowp-graphql:developfrom
justlevine:fix/connection-resolver-pagination
Aug 8, 2022
Merged

fix: refactor resolvers to better follow Relay spec#2457
jasonbahl merged 21 commits intowp-graphql:developfrom
justlevine:fix/connection-resolver-pagination

Conversation

@justlevine
Copy link
Copy Markdown
Collaborator

@justlevine justlevine commented Jul 25, 2022

What does this implement/fix? Explain your changes.

This PR addresses numerous underlying issue with paginating GraphQL connections, by refactoring AbstractConnectionResolver to better follow the Relay Connection spec, while using smaller methods to allow easier extension by child classes.

Originally surfaced by #2343, a review showed not just regressions caused by #2294, but others dating back to v1.6.x as well.

Initial work was done in #2408 , which became unwieldy due to leaky tests hiding false positives (addressed in #2455).

Changelog

  • feat: Add support for paginating a connection by both before and after args.
  • fix: Refactor AbstractConnectionResolver to support all parts of Relay Spec, including more robust over-fetching and slicing.
  • fix: Implement missing logic for some {Type}ConnectionResolver::isValidOffset() methods, and existing ones to be (slightly) more performant.
  • fix: Ensure the order of connections paginated by first and last are the same. [Possibly breaking, see comment below).
  • fix: {Type}ConnectionResolver::get_query_args() now always returns an array.
  • dev: all {Type}ConnectionResolver::$query properties have been given a type in the docblock.
  • dev: AbstractConnectionResolver::get_offset() has been deprecated in favor of AbstractConnectionResolver::get_offset_for_cursor().
  • dev: Refactor Cursor Object classes to extend AbstractCursor.
  • dev: Passing the $query to the PostCursor and UserCursor constructor has been deprecated in favor of passing the $query->query_vars instead.
  • dev: PostCursor::get_cursor_post() TermCursor::get_cursor_term() and UserCursor::get_cursor_user() have been deprecated in favor of AbstractCursor::get_cursor_node().
  • test: Extend Pagination tests to uniformly cover forward/backward pagination.
  • remove graphql_cursor_offset and graphql_cursor_compare in favor of graphql_before_cursor and graphql_after_cursor.

Does this close any currently open issues?

TBD.

Any relevant logs, error output, GraphiQL screenshots, etc?

(If it’s long, please paste to https://ghostbin.com/ and insert the link here.)

Any other comments?

  • Several existing tests were removed as they are covered more comprehensively by newer ones.
  • This PR does not (yet) include fixes to the {type}ObjectCursor classes, which are the source for incomplete tests for Comment and MenuItem types. These classes still rely on the logic from the now-deprecated AbstractConnectionResolver::get_offset()
  • There is also an issue when paginating PostObject connections filtered by search, which may or may not be connected.
  • A separate issue has been surfaced by these tests where draft Posts are not available on menuItems.nodes.connectedNode, but they are available on connectedObject. 🤔
  • I don't know whether the fixes to last ordering should be considered a breaking change. I want to say it isn't, and definitely feel strongly about that for any regressions caused by fix: refactor AbstractConnectionResolver::get_nodes() to prevent children double slicing #2294 , but if the order was backwards before 1.6.x, the question is whether this discrepancy between the plugin and Relay is a bug or expected behavior users have built around.

Where has this been tested?

Operating System: Ubuntu 20.01 (Wsl2 + devilbox + php8.0.19)

WordPress Version: 6.0.1

Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 8981 lines exceeds the maximum allowed for the inline comments feature.

@justlevine justlevine added type: bug Issue that causes incorrect or unexpected behavior impact: high Unblocks new use cases, substantial improvement to existing feature, fixes a major bug component: pagination Relating to pagination regression Bug that causes a regression to a previously working feature labels Jul 25, 2022
@justlevine justlevine changed the title Fix: refactor resolvers to better follow Relay spec fix: refactor resolvers to better follow Relay spec Jul 25, 2022
@coveralls
Copy link
Copy Markdown

coveralls commented Jul 25, 2022

Coverage Status

Coverage increased (+0.4%) to 82.016% when pulling 9fc6928 on justlevine:fix/connection-resolver-pagination into 8a51e40 on wp-graphql:develop.

…orks when using separate POST requests. The failing tests in the wpunit/CommentConnectionQueriesTest.php file are related to multiple calls to `graphql()` being executed in one php request. _something_ is not being cleared between separate calls to graphql(). The theory is one of the filters on the WP_Comment_Query class, but we still need to debug to identify the exact issue.
…ment. This allows different "graphql_args" to be used to determine different caches since all args are not respected when the cache key is generated
Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 9116 lines exceeds the maximum allowed for the inline comments feature.

…ursor class to build the cursor

- introduce the CommentObjectCursor class to build the cursor for comment queries
- update some functions in the other cursor classes for consistent code style
- update CommentConnectionQueriesTests to not be marked incomplete
Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 9355 lines exceeds the maximum allowed for the inline comments feature.

@jasonbahl
Copy link
Copy Markdown
Collaborator

jasonbahl commented Aug 2, 2022

@justlevine

There is also an issue when paginating PostObject connections filtered by search, which may or may not be connected.

Do you know what issue this is? Is it an open Github issue or just a bug you noticed but doesn't have a formal issue opened?

(edit: nevermind. I see the test that's marked incomplete. Checking it out now)


// Assert the 2nd item is the 4th most recent post
$this->assertSame( $this->created_post_ids[3], $actual['data']['posts']['nodes'][1]['databaseId'] );
if ( isset( $graphql_args['where']['search'] ) ) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@jasonbahl ☝️

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@justlevine looks like this was a false bug.

I tried reproducing and couldn't but then realized that the test was creating 7 posts with uniqueString and then asserting that page 3 of 2 posts per page should have hasNextPage as false. But since there were 7 posts, hasNextPage was properly resolving as true as page 3 returns nodes 5 & 6, and page 4 would return the 7th node.

I updated the test to only create 6 posts and it's good now. 🙌🏻

@justlevine
Copy link
Copy Markdown
Collaborator Author

Yeah no prior GH issue, something unearthed during tests. Though come to think of it maybe #2419 is also related?

@jasonbahl
Copy link
Copy Markdown
Collaborator

Yeah no prior GH issue, something unearthed during tests. Though come to think of it maybe #2419 is also related?

@justlevine seems loosely related, but I don't think directly. 🤔 I think that issue is maybe an issue with the argument getting mapped from the graphql input to the query_args passed to WP_Query? could be wrong tho

…ead of 7 when testing pagination as the tests make assertions based on 6 records, not 7.

- add cleanup to delete posts after the tests
Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 9346 lines exceeds the maximum allowed for the inline comments feature.

Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 9391 lines exceeds the maximum allowed for the inline comments feature.

… use a new $field_key variable

- add some compare/order logic for when menu_order is the orderby. (not really happy with this, but it works. Would love to refactor this as I feel it's very naiive right now)
- update connection resolver from MenuItem to "connectedNode" to query "any" post_status (as drafts, etc _can_ be in menus)
- remove "markTestIncomplete" from menu item connection queries tests
- set the "posts_per_page" argument for one to one connections as 1 instead of the max value
Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 9440 lines exceeds the maximum allowed for the inline comments feature.

Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 9454 lines exceeds the maximum allowed for the inline comments feature.

@jasonbahl
Copy link
Copy Markdown
Collaborator

@justlevine I pushed up a few commits.

All tests are now passing. No more are marked incomplete 👏🏻

I'm not incredibly pleased with the solution I came up with for the the pagination issues related to when posts are sorted by "menu_order". I think it needs more thought, but I don't have brilliant ideas at the moment. I got it to work, but I'm not sure I love the implementation. Open to iteration either now, or sometime in the future.

Anything else I did is of course also open to iteration, cleanup, DRYing up, etc.

I feel like there's a lot we can do in the cursor classes to DRY things up, but again, my focus was on getting things working first, before making the code DRY and abstracting patterns.

Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 9454 lines exceeds the maximum allowed for the inline comments feature.

Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 10037 lines exceeds the maximum allowed for the inline comments feature.

Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 10033 lines exceeds the maximum allowed for the inline comments feature.

@justlevine
Copy link
Copy Markdown
Collaborator Author

justlevine commented Aug 6, 2022

@jasonbahl

I'm not incredibly pleased with the solution I came up with for the the pagination issues related to when posts are sorted by "menu_order".

The important thing is that it's working and I dont think it's worth delaying this PR over (I cant think of any alternatives either 😅).

I did a basic refactor of the CursorObject classes so they extend AbstractCursor. There might me some more room for abstraction in the individual compare_{...}() methods, but unless something jumps out at you then I don't think it's worth delaying the PR for either.

One thing I'm stuck on is what to do with the old graphql_cursor_offset and graphql_cursor_compare query vars.

The only place we're actually using graphql_cursor_compare is in Config::graphql_wp_query_cursor_pagination_stability() (in the cursor objects it was being overwritten by before and after, so it's gone now), and I deprecated 3rd-party setting of graphql_cursor_offset altogether, but WPGraphQL core is still setting them both in {Comment|Post|Term|User}ConnectionResolver.

Do we get rid of them altogether, or mark them as deprecated in a comment? I think it's more likely for people to be setting them then getting them in their own projects (and rare altogether), so I'm not that worried about removing them, but its still something to consider.

Once a decision is made on that, I think this PR is good to ship.

@jasonbahl
Copy link
Copy Markdown
Collaborator

but this plugin is still setting them both in {Comment|Post|Term|User}ConnectionResolver.

@justlevine you missed the link for this plugin. What plugin?

@justlevine
Copy link
Copy Markdown
Collaborator Author

justlevine commented Aug 8, 2022

but this plugin is still setting them both in {Comment|Post|Term|User}ConnectionResolver.

@justlevine you missed the link for this plugin. What plugin?

This plugin meaning WPGraphQL core. We're still setting those custom query vars in all those connection resolvers, but only using graphql_cursor_compare for post stability, and not using graphql_cursor_offset at all. I don't know if/how any third party code might be using them..

Not sure why I wasn't explicit 😅. Updated the comment.

@jasonbahl
Copy link
Copy Markdown
Collaborator

@justlevine ah! I thought you meant like an extension plugin. Sorry about that. 🤦🏻

…olvers

- update config.php to early return when not a graphql request
- php cs fixes
…ection-resolver-pagination

# Conflicts:
#	src/Data/Config.php
#	src/Data/Cursor/CommentObjectCursor.php
#	src/Data/Cursor/PostObjectCursor.php
#	src/Data/Cursor/UserCursor.php
Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 10135 lines exceeds the maximum allowed for the inline comments feature.

@jasonbahl
Copy link
Copy Markdown
Collaborator

I don't know whether the fixes to last ordering should be considered a breaking change. I want to say it isn't, and definitely feel strongly about that for any regressions caused by #2294 , but if the order was backwards before 1.6.x, the question is whether this discrepancy between the plugin and Relay is a bug or expected behavior users have built around.

@justlevine I agree that this is a bugfix not a breaking change. Any queries that did change would have just changed the order of the items. Like 10-1 instead of 1-10. But the items will still be there.

Copy link
Copy Markdown

@qlty-cloud-legacy qlty-cloud-legacy bot left a comment

Choose a reason for hiding this comment

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

The PR diff size of 10141 lines exceeds the maximum allowed for the inline comments feature.

@qlty-cloud-legacy
Copy link
Copy Markdown

Code Climate has analyzed commit 9fc6928 and detected 3 issues on this pull request.

Here's the issue category breakdown:

Category Count
Complexity 1
Duplication 2

View more on Code Climate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: pagination Relating to pagination impact: high Unblocks new use cases, substantial improvement to existing feature, fixes a major bug regression Bug that causes a regression to a previously working feature type: bug Issue that causes incorrect or unexpected behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants