Open sergeyantonov1 opened 3 years ago
Now in gfaphql base project used gem https://github.com/Shopify/graphql-batch for load associations. That gem in rare cases generate extra sql request like on screenshoot. We have 2 variants to resolve that problem - fix graphql-batch problem or try lookahead that @sergeyantonov1 refer in comments on top.
I've updated the preparing associations logic a little bit cuz implementation that I provided above doesn't work correctly with nested associations. If you have a more readable or simple solution welcome.
module Resolvers
class Base < GraphQL::Schema::Resolver
include ActionPolicy::GraphQL::Behaviour
include SortedRelation
argument_class Types::BaseArgument
def resolve(**options)
@options = options
fetch_data
end
private
attr_reader :options
def fetch_data
raise NotImplementedError
end
def current_user
@current_user ||= context[:current_user]
end
def preload_associations
[prepared_single_associations, prepared_nested_associations].flatten.compact
end
def prepared_nested_associations
raw_preload_associations.reduce({}) do |hash, element|
if element.is_a?(Hash)
hash.merge(element) { |_, v1, v2| (v1 + v2).uniq }
else
hash
end
end.presence
end
def prepared_single_associations
raw_preload_associations.map { |association| association if association.is_a?(Symbol) }.compact
end
def raw_preload_associations
@raw_preload_associations ||=
lookahead_selection_names.each_with_object([]) do |selection, associations|
associations << self.class::PRELOAD_ASSOCIATIONS_MAPPING[selection]
end.flatten.compact
end
def lookahead_selection_names
options[:lookahead].selections.map { |s| s.name.to_sym }
end
end
end
These changes will work with nested associations.
For example, we have next mapping:
PRELOAD_ASSOCIATIONS_MAPPING = {
can_make_assessment: [recent_received_feedbacks_with_assessment: [:sender]],
fired_at: [:sent_feedbacks, recent_received_feedbacks_with_assessment: [:recipient]]
}.freeze
In this case, preload associations will equal to:
[:sent_feedbacks, {:recent_received_feedbacks_with_assessment=>[:recipient, :sender]}]
How it will work without this patch:
[:sent_feedbacks, {:recent_received_feedbacks_with_assessment=>[:recipient]}, {:recent_received_feedbacks_with_assessment=>[:sender]}]
What is lookahead? https://graphql-ruby.org/queries/lookahead.html#getting-a-lookahead
How we can implement it? In the example below
recent_assessments
association will be loaded ifcan_make_assessment
will be selected in GraphQL request.