Last active
January 28, 2022 18:24
-
-
Save rmosolgo/29552d885f511963fb54a677351eb8ba to your computer and use it in GitHub Desktop.
Cached ActiveRecord Connection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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