Skip to content

Instantly share code, notes, and snippets.

@itkrt2y
Last active Sep 17, 2022
Embed
What would you like to do?
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment