Skip to content

Instantly share code, notes, and snippets.

@rmosolgo
Last active January 28, 2022 18:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmosolgo/29552d885f511963fb54a677351eb8ba to your computer and use it in GitHub Desktop.
Save rmosolgo/29552d885f511963fb54a677351eb8ba to your computer and use it in GitHub Desktop.
Cached ActiveRecord Connection
require "bundler/inline"
gemfile do
gem "graphql"
gem "graphql-pro"
gem "sqlite3"
gem "rails"
end
require "rails/all"
require "logger"
# I don't have `Rails.cache`, so I'm making one here:
$cache = ActiveSupport::Cache::MemoryStore.new
# Make a custom subclass of the built-in connection class, adding `cache.fetch` calls:
class CachedActiveRecordConnection < GraphQL::Pagination::ActiveRecordRelationConnection
def sliced_nodes
@sliced_nodes ||= begin
nodes = super
cache_key = nodes.to_sql
$cache.fetch(cache_key) do
nodes.to_a
end
end
end
def load_nodes
@nodes ||= begin
cache_key = limited_nodes.to_sql
$cache.fetch(cache_key) do
limited_nodes.to_a
end
end
end
end
# Make a schema with "searchable" books:
class MySchema < GraphQL::Schema
class Book < GraphQL::Schema::Object
field :author, String
field :title, String
end
class Query < GraphQL::Schema::Object
field :books, Book.connection_type do
argument :query, String, required: false
end
def books(query:)
# Manually apply the custom connection class:
CachedActiveRecordConnection.new(::Book.where("LOWER(title || ' ' || author) LIKE ?", "%#{query.downcase}%"))
end
end
query(Query)
end
# Set up the database and add some records:
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Schema.define do
self.verbose = false
create_table :books, force: true do |t|
t.column :author, :string
t.column :title, :string
end
end
class Book < ActiveRecord::Base; end
Book.create!(title: "Remembering", author: "Wendell Berry")
Book.create!(title: "The Going to Bed Book", author: "Sandra Boynton")
Book.create!(title: "Gilead", author: "Marilynne Robinson")
Book.create!(title: "Historical Brewing Techniques", author: "Lars Marius Garshol")
Book.create!(title: "The Tale of Tom Kitten", author: "Beatrix Potter")
ActiveRecord::Base.logger = Logger.new(STDOUT)
# Now run some queries. Only the first one of each pair should emit a message to the Logger:
puts "First execution:"
pp MySchema.execute("{ books(query: \"be\") { nodes { title author }} }").to_h
puts "Second execution:"
pp MySchema.execute("{ books(query: \"be\") { nodes { title author }} }").to_h
puts "\n\nFirst execution with pagination:"
pp MySchema.execute("{ books(query: \"be\", first: 2) { nodes { title author } } }").to_h
puts "Second execution with pagination:"
res = MySchema.execute("{ books(query: \"be\", first: 2) { nodes { title author } pageInfo { endCursor } } }").to_h
pp res
next_cursor = res["data"]["books"]["pageInfo"]["endCursor"]
puts "\n\nFirst execution with just pageInfo:"
pp MySchema.execute("{ books(query: \"be\", first: 1, after: #{next_cursor.inspect}) { pageInfo { hasNextPage } } }").to_h
puts "Second execution with just pageInfo:"
pp MySchema.execute("{ books(query: \"be\", first: 1, after: #{next_cursor.inspect}) { pageInfo { hasNextPage } } }").to_h
# First execution:
# D, [2022-01-28T13:18:15.875212 #52824] DEBUG -- : Book Load (0.1ms) SELECT "books".* FROM "books" WHERE (LOWER(title || ' ' || author) LIKE '%be%') LIMIT -1 OFFSET ? [["OFFSET", 0]]
# {"data"=>
# {"books"=>
# {"nodes"=>
# [{"title"=>"Remembering", "author"=>"Wendell Berry"},
# {"title"=>"The Going to Bed Book", "author"=>"Sandra Boynton"},
# {"title"=>"The Tale of Tom Kitten", "author"=>"Beatrix Potter"}]}}}
# Second execution:
# {"data"=>
# {"books"=>
# {"nodes"=>
# [{"title"=>"Remembering", "author"=>"Wendell Berry"},
# {"title"=>"The Going to Bed Book", "author"=>"Sandra Boynton"},
# {"title"=>"The Tale of Tom Kitten", "author"=>"Beatrix Potter"}]}}}
# First execution with pagination:
# D, [2022-01-28T13:18:15.885540 #52824] DEBUG -- : Book Load (0.7ms) SELECT "books".* FROM "books" WHERE (LOWER(title || ' ' || author) LIKE '%be%') LIMIT ? OFFSET ? [["LIMIT", 2], ["OFFSET", 0]]
# {"data"=>
# {"books"=>
# {"nodes"=>
# [{"title"=>"Remembering", "author"=>"Wendell Berry"},
# {"title"=>"The Going to Bed Book", "author"=>"Sandra Boynton"}]}}}
# Second execution with pagination:
# {"data"=>
# {"books"=>
# {"nodes"=>
# [{"title"=>"Remembering", "author"=>"Wendell Berry"},
# {"title"=>"The Going to Bed Book", "author"=>"Sandra Boynton"}],
# "pageInfo"=>{"endCursor"=>"Mg"}}}}
# First execution with just pageInfo:
# D, [2022-01-28T13:18:15.892276 #52824] DEBUG -- : Book Load (0.1ms) SELECT "books".* FROM "books" WHERE (LOWER(title || ' ' || author) LIKE '%be%') LIMIT -1 OFFSET ? [["OFFSET", 2]]
# {"data"=>{"books"=>{"pageInfo"=>{"hasNextPage"=>true}}}}
# Second execution with just pageInfo:
# {"data"=>{"books"=>{"pageInfo"=>{"hasNextPage"=>true}}}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment