Skip to content

Instantly share code, notes, and snippets.

@itkrt2y
Last active March 11, 2024 22:55
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save itkrt2y/1e1a947c71772044f5d67f358b4772fc to your computer and use it in GitHub Desktop.
Save itkrt2y/1e1a947c71772044f5d67f358b4772fc to your computer and use it in GitHub Desktop.
Association dataloader with graphql-ruby
# official docs: https://graphql-ruby.org/dataloader/sources.html
# app/graphql/sources/association.rb
class Sources::Association < ::GraphQL::Dataloader::Source
def initialize(association_name, scope = nil)
@association_name = association_name
@scope = scope
end
def fetch(records)
::ActiveRecord::Associations::Preloader.new.preload(records, @association_name, @scope)
# Rails7
# ::ActiveRecord::Associations::Preloader.new(records: records, associations: @association_name, scope: @scope).call
records.map { |record| record.public_send(@association_name) }
end
# https://github.com/rmosolgo/graphql-ruby/blob/821ca53048fa5803fb90596719b4fedd65029ecb/lib/graphql/dataloader/source.rb#L113-L129
def self.batch_key_for(*batch_args, **batch_kwargs)
[*batch_args.map { |arg| arg.try(:to_sql) || arg }, **batch_kwargs]
end
end
class User < ApplicationRecord
has_many :posts
end
class Post < ApplicationRecord
belongs_to :user
has_many :comments
end
class Comment < ApplicationRecord
belongs_to :post
end
module Types
class UserType < Types::BaseObject
field :id, ID, null: false
field :posts, [Types::PostType], null: false
def posts
dataloader.with(Sources::Association, :posts, ::Post.preload(:comments)).load(object)
end
end
class PostType < Types::BaseObject
field :id, ID, null: false
field :user, Types::UserType, null: false
def user
dataloader.with(Sources::Association, :user).load(object)
end
field :comments, [Types::CommentType], null: false
def comments
dataloader.with(Sources::Association, :comments).load(object)
end
end
class CommentType < Types::BaseObject
field :id, ID, null: false
field :post, Types::PostType, null: false
def post
dataloader.with(Sources::Association, :post).load(object)
end
end
end
@jgrau
Copy link

jgrau commented Feb 9, 2023

❤️

@benbonnet
Copy link

👍

@timmystephani
Copy link

Wow, I could not find an example of using DataLoader with a has_many relationship anywhere - thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment