From 65e0548d93bd5c0d382191e094f726775754d9b6 Mon Sep 17 00:00:00 2001 From: Ben Joyce Date: Wed, 8 Sep 2021 11:26:31 -0700 Subject: [PATCH] Add custom associations for fields --- Gemfile.lock | 2 +- README.md | 21 +++++++++++++++++++++ lib/graphql/eager_load/builder.rb | 12 ++++++++++++ lib/graphql/eager_load/resolver.rb | 2 +- lib/graphql/eager_load/version.rb | 2 +- spec/graphql/eager_load_spec.rb | 21 +++++++++++++++++++++ spec/internal/app/graphql/types/user.rb | 7 +++++++ 7 files changed, 64 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2873c7a..1ec72c7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - graphql-eager_load (0.2.2) + graphql-eager_load (0.2.3) GEM remote: https://rubygems.org/ diff --git a/README.md b/README.md index 66d078a..d2b58d9 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,27 @@ users { The output of the `#associations_to_eager_load` helper method would be `{estimates: {}, profile_photo: {blob: {}}`. Without the `.allow_include_builder_fields` class method the output would be `{estimates: {}}`. +If you have a field that is derived from an association, but the association is not included in the query, you can define a `#custom_associations_for_fields` method to specify which associations to include for a specific field. + +```ruby +module Types + class User < Types::Base + field :estimates, [Types::Estimate], null: false + field :org_names, [String], null: true + + def org_names + object.orgs.map(&:name) + end + + def self.custom_associations_for_fields + { + org_names: [:org] + } + end + end +end +``` + ## Development After checking out the repo, run `bundle` to install dependencies. Then, run `bundle exec rake spec` to run the tests. You can also run `bundle exec bin/console` for an interactive prompt that will allow you to experiment. diff --git a/lib/graphql/eager_load/builder.rb b/lib/graphql/eager_load/builder.rb index 7f80945..0abf7b0 100644 --- a/lib/graphql/eager_load/builder.rb +++ b/lib/graphql/eager_load/builder.rb @@ -42,6 +42,8 @@ def self.call(selections:, model:) else includes.merge!(builder.includes) end + + includes.deep_merge!(builder.custom_associations_for_selection) end end @@ -66,6 +68,16 @@ def active_storage_attachment? model.reflect_on_attachment(field_name).present? end + def custom_associations_for_selection + return {} unless field_owner.respond_to?(:custom_associations_for_fields) + + custom_associations = field_owner.custom_associations_for_fields[field_name.to_sym] + + return {} unless custom_associations + + custom_associations.map { |association| [association, {}] }.to_h + end + private attr_reader :selection, :model diff --git a/lib/graphql/eager_load/resolver.rb b/lib/graphql/eager_load/resolver.rb index fd01838..f04328c 100644 --- a/lib/graphql/eager_load/resolver.rb +++ b/lib/graphql/eager_load/resolver.rb @@ -12,7 +12,7 @@ def associations_to_include graphql_eager_load_options(model: self.class.class_variable_get(:@@eager_load_model)) end - def graphql_eager_load_options(selections: context.query.lookahead.selections, model:) + def graphql_eager_load_options(model:, selections: context.query.lookahead.selections) Builder.call(selections: selections, model: model) end diff --git a/lib/graphql/eager_load/version.rb b/lib/graphql/eager_load/version.rb index 78e5226..3ee323e 100644 --- a/lib/graphql/eager_load/version.rb +++ b/lib/graphql/eager_load/version.rb @@ -2,6 +2,6 @@ module Graphql module EagerLoad - VERSION = '0.2.2' + VERSION = '0.2.3' end end diff --git a/spec/graphql/eager_load_spec.rb b/spec/graphql/eager_load_spec.rb index 34fe01d..5ae1d4c 100644 --- a/spec/graphql/eager_load_spec.rb +++ b/spec/graphql/eager_load_spec.rb @@ -95,5 +95,26 @@ ) end end + + describe 'custom_associations_for_fields' do + let(:model) { ::User } + let(:query_string) do + <<-QUERY + query { + users { + nodes { + email + } + } + } + QUERY + end + + it 'includes the specified associations' do + expect(options).to eq( + jobs: {} + ) + end + end end end diff --git a/spec/internal/app/graphql/types/user.rb b/spec/internal/app/graphql/types/user.rb index a788882..cf48c19 100644 --- a/spec/internal/app/graphql/types/user.rb +++ b/spec/internal/app/graphql/types/user.rb @@ -7,6 +7,7 @@ class User < GraphQL::Schema::Object field :proposal_documents, [ProposalDocument], null: false field :order, Order, null: false field :photo, Types::File, null: true + field :email, String, null: true def order { code: SecureRandom.uuid } @@ -19,5 +20,11 @@ def photo def self.allow_include_builder_fields [:photo] end + + def self.custom_associations_for_fields + { + email: [:jobs] + } + end end end