Reputation: 342
Let's say I have 2 tables:
- Users (id, name, post)
- Posts (id, message, user)
How can I fetch first 10 Posts order by User's name(desc)?
Here's how my schema looks like:
var PostType = new GraphQLObjectType({
name: "Post",
fields: () => ({
id: { type: GraphQLInt },
message: { type: GraphQLString },
user: {
type: UserType,
args: {
orderBy: { type: sortType }
},
resolve(parent, args) {
console.info("Post resolve called.");
return userMap[parent.user];
}
}
})
});
var RootQuery = new GraphQLObjectType({
name: "RootQueryType",
fields: {
allPosts: {
type: new GraphQLList(PostType),
resolve(parentValue, args) {
console.info("allPosts resolve called.");
return postData;
}
}
}
});
And Query:
{
allPosts {
message
user (orderBy: {field: "name", direction: ASC}) {
name
}
}
}
Is there any way, I can call user resolver function before allPosts resolver function? Because, I am trying to fetch 10 users sorted by name and then pass post ids to allPosts resolver.
Upvotes: 14
Views: 14500
Reputation: 84687
GraphQL fields are resolved in a top-down fashion. That means allPosts
is resolved first, then then message
and user
fields (simultaneously) and then the name
field. This has to happen, as the "parent" or root field's resolved value determine's the value that's then passed to the resolver for its children fields as the root value. Information flows from "higher" resolvers to "lower" ones, but not the other way around.
Your orderBy
argument here probably should be an argument on the allPosts
field rather than the user
field. There's two reasons to do that: (1) conceptually, regardless of the sort criteria, you are sorting the Posts returned by allPosts
-- by convention, it just makes sense to put the sort there; (2) the argument is probably needed by the allPosts
resolver more than it's needed by the user
resolver.
To make the above work, you'll probably need to modify how you identify the sort criteria (making field
a path like user.name
for example). You may also need "lift" the logic for populating the users up into the allPosts
resolver. For example:
resolve(parentValue, { sortBy: { path, direction } }) {
const data = postData.map(post => {
post.user = userMap[post.user]
return post
});
// using lodash
return orderBy(data, [(post) => get(post, path)], [direction])
}
It is possible to determine the selection set for other fields inside the request, including the arguments, by parsing the info
object that's passed in as the fourth parameter to the resolver function. It's a pain though and I don't know if this particular case really justifies doing all that. You can read more about that approach in this answer.
Upvotes: 5