Let's say that I have a PostType and it has comments field and a query may or may not contain post { comments { ... } }.
Is there a proper way to inspect the query and see if it requires comments, so I can do Post.includes(:comments)? (Or even Post.includes(:comments => :user) in case of { post { comments { ... node { user } }
As of 0.16 you can inspect ctx.irep_node to see fields which might be resolved.
field :post, PostType do
resolve -> (obj, args, ctx) {
post = obj.post
# Check if any nodes are the "comments" field
has_comments = ctx.irep_node.children.any? { |node| node.definition.name == "comments" }
if has_comments
post = post.includes(:comments)
end
post
}
end
You could continue recursively for user. It's a bit of a new feature so let me know how it works out for you!
Another important bit is graphql-batch, helpful in some cases: https://github.com/Shopify/graphql-batch
Thanks!
I ended up with this:
class GraphHelper
def self.ctx_has_path?(ctx, *path)
path.reduce(ctx.irep_node) do |curr_node, path_item|
new_curr_node = curr_node.children.find { |k, v| v.definition_name == path_item.to_s }.try(:[], 1)
return false if new_curr_node.nil?
new_curr_node
end.present?
end
end
# ...
QueryType = GraphQL::ObjectType.define do
# ...
field :collection do
type CollectionType
argument :id, !types.String
resolve -> (root, args, ctx) {
type_name, id = NodeIdentification.from_global_id(args[:id])
q = Collection
q = q.includes(:items) if GraphHelper.ctx_has_path?(ctx, :items)
q = q.includes(:items => :entity) if GraphHelper.ctx_has_path?(ctx, :items, :edges, :node, :entity)
q.find(id)
}
end
end
CollectionType = GraphQL::ObjectType.define do
name 'Collection'
# ...
connection :items do
type CollectionItemType.connection_type
resolve -> (root, args, ctx) {
items = root.items
items = items.includes(:entity) if GraphHelper.ctx_has_path?(ctx, :edges, :node, :entity)
items
}
end
end
graphql-batch is also super useful!
Instead of taking care about N+1 queries in resolvers, the query executor should handle them.
Both
and
are right places to solve N + 1 queries.
Most helpful comment
Instead of taking care about N+1 queries in resolvers, the query executor should handle them.
Both
and
are right places to solve N + 1 queries.