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

feat: AbstractConnectionResolver:set_query_class() created #2821

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from

Conversation

kidunot89
Copy link
Member

@kidunot89 kidunot89 commented May 23, 2023

What does this implement/fix? Explain your changes.

While it started as a fix for the queryClass connection registration argument which is broken atm of creation in WPGraphQL v1.14.3, this PR ultimately does not fix queryClass but instead make the query class something to be set on the resolver level instead of the registration level. There is some functionality being lost here but it was actually removed a long time ago by @jasonbahl. Then patch back in by myself, @kidunot89, but in a really hacky way. Then broken again by
@justlevine. And this will be the introduction of something new but achieves the same desired effect as the queryClass argument.

  • Adds query_class and set_query_class() to AbstractConnectionResolver class.
  • Updates Comment, Post, User, and Term connection resolver classes to source the $query_class.
  • Adds testRegisteringConnectionsWithCustomQueryClasses to the ConnectionRegistrationTest case
  • WP_Query_Custom added to tests/_support/utils/class-wp-query-custom.php for testing.

Example registration call using the new functionality.

register_graphql_connection([
	'fromType'      => 'RootQuery',
	'toType'        => 'Post',
	'fromFieldName' => 'customPosts',
	'resolve'       => function ( $source, $args, $context, $info ) {
		$resolver = new \WPGraphQL\Data\Connection\PostObjectConnectionResolver( $source, $args, $context, $info, 'post' );
		$resolver->set_query_class( \WP_Query_Custom::class );
		return $resolver->get_connection();
	},
]);

Does this close any currently open issues?

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?

Where has this been tested?

Operating System:

WordPress Version:

@justlevine
Copy link
Collaborator

justlevine commented May 24, 2023

First off, love this! (@renatonascalves just suggested something like this so the timing is perfect! )

Couple questions (for context 😬) before I look at the actual code:

While it started as a fix for the queryClass connection registration argument which is broken atm of creation in WPGraphQL v1.14.3.

  1. Can you be more specific about what's currently broken?

There is some functionality being lost here

  1. What specifically are we losing (and do you mean vs what's currently working or what's currently supposed to work but is anyway broken (per 1).

The last several attempts at isolated fixes/enhancements to the Connection Resolver all resulted in regressions around cases we don't currently have unit tests for. To try and avoid that from happening again, I've been working to improve the class holistically in #2749 from which we would then backport the individual changes in a nonbreaking manner.

My recommendation for this would be the same if it's "just" an enhancement and not tackling a specific regression.

src/Data/Connection/AbstractConnectionResolver.php Outdated Show resolved Hide resolved
*
* @return void
*/
public function set_query_class( $class ) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I've got concerns/questions from a "holistic" POV - nothing that follows should be considering blocking since the same issues exist with the current method of setting the query class via WPConnectionType.

I love the fact that this pattern makes local overloading in a resolver possible, and brings Comment/User connection queries the same extensibility patten, but I'm concerned about its availability on AbstractConnectionResolver, when only 4 (including those in this PR) out of the bundled 13 Connection resolvers actually use a $query_class. Unlike when it was buried in WPConnectionType, the new pattern will see more (mis-)use, so I think it's an opportunity to consider this aspect of the DX.

Similarly, I'm concerned around the lack of checks around the provided $query_class. We dont want to enforce a WP_Query child, but we do need to make sure that the provided class string (SWP_Query, WC_Query, Tribe_Query, FWP_Query, etc etc) is actually compatible with the Connection resolver relying on it.

The latter issue can be solved with an overloadable is_valid_query_class( string $class ) that could for example check for method_exists( $class, 'query' ).

We could even in theory use the same is_valid_query_class() to throw an exception if ! empy( $this->query_class ) on the Connection Resolvers that don't use it (would need to figure out backwards-compatibility), but I think we should first confirm that AbstractConnectionResolver is really the ideal home for this instead of adding what's possibly tech debt to the majority of the included connection resolvers.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually it's more like 6 or 7 out of 13, because they extend one of the 4 connection resolvers and not the AbstractConnectionResolver class directly, Some of them don't even have a get_query() function and default to parent get_query() function in one of the 4. I agree there should be class_exists( $this->query_class ) check somewhere and a is_valid_query_class() function is a good idea. I'll add it immediately.

Copy link
Collaborator

Choose a reason for hiding this comment

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

because they extend one of the 4 connection resolvers and not the AbstractConnectionResolver class directly, Some of them don't even have a get_query() function and default to parent get_query() function in one of the 4.

Actual numbers aside ☝️is the crux of my concern: we're exposing a setter that semantically should apply on any connection but will be ignored by most of them - something that becomes less obvious from the code the better we are at DRYing out the implementing classes. But I don't have a good alternative 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

The only clean solution I can think of would be make two child classes of the AbstractConnectionResolver that all other extend. One would be something like QueryConnectionResolver and the other would be something like ConnectionResolver. You get the picture 🤷🏿‍♂️

Copy link
Collaborator

Choose a reason for hiding this comment

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

Or breaking up AbstractConnectionResolver into traits, but I think either is bad DX in this particular situation since it extenders then need to know which intermediate class / trait is right for a particular WP type, but I don't see a way to have those classes/traits to use existing WP namings. 🤷‍♂️

Copy link
Member Author

@kidunot89 kidunot89 May 24, 2023

Choose a reason for hiding this comment

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

Exactly, but the connection resolvers not using $query_class are highly unlikely to be extended for usage. EnqueuedScripts, EnqueuedStylesheet, Plugin, Taxonomy, Theme, UserRole, and ContentType. So honestly we should be fine.

*/
public function get_query() {
return new WP_Comment_Query( $this->query_args );
// Get query class.
$queryClass = ! empty( $this->query_class )
Copy link
Collaborator

Choose a reason for hiding this comment

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

Seeing this alone makes me way happier than it has any right to. 🙌🙌🙌

@@ -677,4 +679,45 @@ protected function assertValidTypes( $actual ) : void {
$this->assertEquals( 'TestObject', $actual['data']['testConnection']['nodes'][0]['__typename'] );
}

public function testRegisteringConnectionsWithCustomQueryClasses() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should also have tests for some common edge cases: bad class name, incompatible class, and using the wrong WP_{$type}_Query are the ones that jump to mind.

@@ -0,0 +1,3 @@
<?php

require __DIR__ . '/../_support/Utils/class-wp-query-custom.php';
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we do this via the autoloader instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

Tried too, and it didn't work. It was namespaced and everything. For some reason GraphQL wouldn't see the class and would throw so I eventually devolve into that in the bootstrap file, and I just removed all my PSR dev configuration.

Copy link
Member Author

Choose a reason for hiding this comment

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

Feel free to take a crack at after I make your requested changes.

Copy link

@codeclimate codeclimate 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 9896 lines exceeds the maximum allowed for the inline comments feature.

@kidunot89 kidunot89 requested a review from justlevine May 24, 2023 15:17
Copy link

@codeclimate codeclimate 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 9958 lines exceeds the maximum allowed for the inline comments feature.

Copy link

@codeclimate codeclimate 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 9956 lines exceeds the maximum allowed for the inline comments feature.

@justlevine
Copy link
Collaborator

Couple questions (for context 😬) before I look at the actual code:

While it started as a fix for the queryClass connection registration argument which is broken atm of creation in WPGraphQL v1.14.3.

  1. Can you be more specific about what's currently broken?

There is some functionality being lost here

  1. What specifically are we losing (and do you mean vs what's currently working or what's currently supposed to work but is anyway broken (per 1).

Summarized from a Slack Convo with @kidunot89 (correct me if I made a mistake):

  1. In v1.14.3, the custom queryClass passed via AppContext is ignored. This is a regression (for which I believe there is not an existing GH issue).
  2. This PR doesn't address the regression itself, since using AppContext to overload the query type is "hacky". Instead it provides an enhancement, offering a better way to overload the query class (from within the field resolver for the individual connection).

We should probably still address the actual regression in a separate PR.

With this in mind, I'm going to port this over to #2749 - even if we don't decide to wait on that PR merging this, I'm betting the effort will still unearth some code suggestions we can implement here independently.

justlevine added a commit to justlevine/wp-graphql that referenced this pull request May 25, 2023
@justlevine
Copy link
Collaborator

I've updated #2749 to implement this pattern.
This comment details the differences between this PR vs the holistic approach over there.

(If this PR goes forward independently, I highly recommend backporting at least some of the changes).

- add autoload-dev rule
- update namespace for WP_Query_Custom class
Copy link

@codeclimate codeclimate 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 9933 lines exceeds the maximum allowed for the inline comments feature.

@codeclimate
Copy link

codeclimate bot commented Jun 13, 2023

Code Climate has analyzed commit a74dcb9 and detected 0 issues on this pull request.

View more on Code Climate.

justlevine added a commit to justlevine/wp-graphql that referenced this pull request Sep 16, 2023
@jasonbahl jasonbahl added the Status: Discussion Requires a discussion to proceed label Sep 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Discussion Requires a discussion to proceed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants