Skip to content

Instantly share code, notes, and snippets.

@andersklenke
Created October 23, 2020 08:32
Show Gist options
  • Save andersklenke/c4b41ad58af66ac378395968633e7bec to your computer and use it in GitHub Desktop.
Save andersklenke/c4b41ad58af66ac378395968633e7bec to your computer and use it in GitHub Desktop.
GraphQL loaders
module Loaders
class ForeignKeyLoader < GraphQL::Batch::Loader
attr_reader :model, :foreign_key, :merge
def self.loader_key_for(*group_args)
# avoiding including the `merge` lambda in loader key
# each lambda is unique which defeats the purpose of
# grouping queries together
[self].concat(group_args.slice(0, 2))
end
def initialize(model, foreign_key, merge: nil)
@model = model
@foreign_key = foreign_key
@merge = merge
end
def perform(foreign_ids)
# find all the records
scope = model.where(foreign_key => foreign_ids)
scope = scope.merge(merge) if merge.present?
records = scope.to_a
foreign_ids.each do |foreign_id|
# find the records required to fulfill each promise
matching_records = records.select do |r|
foreign_id == r.send(foreign_key)
end
fulfill(foreign_id, matching_records)
end
end
end
end
module Loaders
class RecordLoader < GraphQL::Batch::Loader
EMPTY_ARRAY = [].freeze
def initialize(model, column: model.primary_key, where: nil, unique: true)
@model = model
@column = column
@column_type = model.type_for_attribute(@column.to_s)
@where = where
@unique = unique
end
def load(key)
super(@column_type.cast(key))
end
def perform(keys)
if @unique
query(keys).each do |record|
fulfill(record.public_send(@column), record)
end
default = nil
else
query(keys).group_by(&@column).each do |key, result|
fulfill(key, result)
end
default = EMPTY_ARRAY
end
keys.each { |key| fulfill(key, default) unless fulfilled?(key) }
end
private
def query(keys)
scope = @model
scope = scope.where(@where) if @where
scope.where(@column => keys)
end
end
end
# Her bruger jeg record_loader
Loaders::RecordLoader.for(::Partner).load(object.partner_id)
# Her bruger jeg foreign_key_loader og en record_loader inden i
Loaders::ForeignKeyLoader.for(TeamMembership, :team_id).load(object.id).then do |memberships|
Loaders::RecordLoader.for(User).load_many(memberships.map(&:user_id))
end
# Mere avanceret forkeign key loader hvor et scope bliver merget ind
Loaders::ForeignKeyLoader.for(
Episode, :playlist_id, merge: -> { Episode.ordered_by_newest_episode }
).load(object.id)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment