-
Notifications
You must be signed in to change notification settings - Fork 105
Open
Labels
Description
We load some records to place into the graphql context before running a query. I'd like to warm the graphql batch loader caches with these records. At the moment I'm doing something like this (with a contrived example):
# app/graphql/record_loader.rb
class RecordLoader < GraphQL::Batch::Loader
def initialize(record_class)
@record_class = record_class
@primary_key = record_class.primary_key
end
def perform(keys)
# Resolve unfulfilled keys
records_by_key = @record_class.where(@primary_key => keys).index_by(&@primary_key)
# Fulfills both found keys as records, and unfound keys as nil
keys.each { |key| fulfill(key, records_by_key[key]) }
end
def warm(record)
key = record.public_send(@primary_key)
promise = cache[cache_key(key)] ||= Promise.new.tap { |promise| promise.source = self }
promise.fulfill(record) unless promise.fulfilled?
end
end
# app/graphql/schema.rb
Schema = GraphQL::Schema.define do
# ...
use GraphQL::Batch
use GraphQL::Batch::Warmer, with: -> (query) do
RecordLoader.for(User).warm(query.context[:current_user])
end
# ...
end
# lib/graphql/batch/warmer.rb
module GraphQL::Batch::Warmer
def self.use(schema_defn, with:)
schema_defn.instrument(:query, QueryInstrumenter.new(with))
end
class QueryInstrumenter
def initialize(block)
@block = block
end
def before_query(query)
unless GraphQL::Batch::Executor.current
raise "Move `use GraphQL::BatchWarmer` below `use GraphQL::Batch` in your schema, or remove it"
end
@block.call(query)
end
def after_query(query)
end
end
end
This feels like it dips a little too much into this gem's responsibilities. Is there any interest including some sort of cache warming facility in this gem?
Update: I've simplified the example.