-
-
Notifications
You must be signed in to change notification settings - Fork 565
Grouping implementor fields for abstract types in QueryPlan #513
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
Conversation
|
I've made the same changes for QueryPlan. |
The idea of relying on I do think we need this feature, but need to think more about ergonomics of it. Anyone having ideas are welcome to share them! |
I've added some changes to this. To prevent BC, method Every type resolution, in addition to graphql-php/tests/Type/QueryPlanTest.php Lines 439 to 450 in c1795f9
The inlineFragments array is used for inline fragments and looks like that:graphql-php/tests/Type/QueryPlanTest.php Lines 490 to 500 in c1795f9
Since a root of query plan can also contain fragments, all the root fields are wrapped in arrays like it is done for the types: graphql-php/tests/Type/QueryPlanTest.php Lines 741 to 760 in c1795f9
|
cc2f772
to
6d9fff3
Compare
There are some changes comparing to my previous post. Since now we have already no underscore fields (so-called "meta-fields") like Fields of regular and inline fragments are merged together now. So, the arrays graphql-php/tests/Type/QueryPlanTest.php Lines 748 to 758 in 6d9fff3
The tests are fully duplicated now to support both modes (with and without changes of this PR). |
How will it work when there are several fragments (or inline fragments) on the same type especially with include/skip directives, i.e. query Test {
article {
image {
...MyImage
...MyImage2
}
author {
pic {
... on Image {
height
}
... on Image {
width
}
...MyImage @include(if: false)
}
}
}
}
fragment MyImage on Image {
url
}
fragment MyImage2 on Image {
width
height
} |
Fields of the same type will be merged together. Let's see example from test. graphql-php/tests/Type/QueryPlanTest.php Lines 1168 to 1216 in 6d9fff3
are resolved to merged ( replies {body, author} ) fields list:graphql-php/tests/Type/QueryPlanTest.php Lines 1278 to 1303 in 6d9fff3
Directives are not supported as they are not supported in original QueryPlan (without changes of this PR), even for regular fields (that are not in fragments), so the resolution of fields with directives will be the same as of fields without them. |
My main concern is that it will be rather hard to cover all use-cases in the future with the current design of QueryPlan (which I had merged in the past a bit prematurely). I have a proposal which may involve some rewrite %) The idea is to have This should be way more extensible. Usage example: $fields = $info->lookAhead()
->withinFragments()
->withIncludeDirective()
->filter(function (FieldNode $field, $parentCollection) { // custom convenience filter
return $field->alias === 'myAlias' || $field->alias === 'myOtherAlias';
});
$fieldNames = $fields->names(); // returns array of field names matching filters above
$fieldUnaliased = $field->aliases();
$firstFieldArguments = $fields->first()->arguments()->names();
$firstIncludeDirective = $fields->directives()->first()->arguments()->values($variables); Technically we already have Then it will also benefit those using AST extensively. @spawnia What do you think? I know you guys work with ASTs a lot. I'd like to discuss method naming and general UX for this collection |
The most generally useful tool would be a data structure that contains the currently executing query with its given arguments together with the matching definitions. As this PR also suggests, fragments should be inlined, as they don't really matter at that level - they are merely an implementation detail that this library takes care off, rather then something that an application needs to concern itself with. |
I don't think we need exactly AST nodes in QueryPlan. I agree that it should be objects that represents current query in more flexible way (with support of filtering, chaining, etc) than it's made now with arrays. But these objects should be on higher level (to describe what data is queried) than AST nodes (that describes how data is queried). Simple example:
Here we queried 2 fields ( So, we need special objects that will describe what is requested. They need their own namespece. |
@yura3d Your notes make sense but AST is a quite flexible structure. It is easy to flatten it (unwrap fragments). It even doesn't have to pass formal GraphQL validation for this use-case. One reason why I would prefer to re-use AST vs introducing new classes is Visitor - it is a very powerful tool for traversing / modifying AST. Anyway, it seems like the scope of this new API is rather big (and the demand is questionable), so I will create a separate ticket for it and will merge your PR as is for now as it already provides value to users. Changes we discuss will likely be breaking anyway (or require a separate chainable and filterable API). |
Several days ago I totally rethought and simplified this PR. If we use fragments inside regular object types, there are no need to group fragment fields by type conditions in QueryPlan because object types and fragments type conditions will be the same. Grouping makes sense only if parent type is abstract (interface or union) and helps to determine, which fields belong to concrete object types, that listed in fragments type conditions. How QueryPlan works with interfaces now: graphql-php/tests/Type/QueryPlanTest.php Lines 326 to 346 in 62b4c38
All the fields (woofs, name) are on the same level, so a resolver doesn't know which of them belong to concrete (Dog) type. As a result, it also doesn't know table name in DB (for example), from which the object data should be retrieved. Introduced in the last commit new option graphql-php/tests/Type/QueryPlanTest.php Lines 740 to 807 in 62b4c38
So now the resolver knows that id and owner are common fields, mark and model can be found in cars table (for example), city and address - in buildings table.
|
Sounds reasonable. Ready for merge? |
@vladar Yes |
I'm using inline fragments in my projects, so I need to know what fields are requested in these fragments.
Current ResolveInfo::getFieldSelection() implementation skips a level of fragments and returns their fields on the same level with another fields, that are not in fragment:
graphql-php/tests/Type/ResolveInfoTest.php
Lines 88 to 94 in 93ccd73
graphql-php/tests/Type/ResolveInfoTest.php
Lines 131 to 135 in 93ccd73
Also, we have a warning that was left in comment inside ResolveInfo.php, so the behavior described above is expected.
graphql-php/src/Type/Definition/ResolveInfo.php
Lines 165 to 166 in d1d4455
My small correction adds to the field of resolve array, that contains inline fragments, new array with a service key __inlineFragments. This array contains fragment resolutions as items, where key is an inline fragment type, and value is an array of fragment fields:
graphql-php/tests/Type/ResolveInfoTest.php
Lines 131 to 137 in c35379c
So now there is an ability to get the fields that is requested in inline fragments.