Created
April 1, 2025 22:24
-
-
Save rmosolgo/e52b021f1b693b1cae5a91fe4342641b to your computer and use it in GitHub Desktop.
Avoiding N+1 loads in different GraphQL subtrees
This file contains hidden or 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", "2.5.0" | |
gem "activerecord", require: "active_record" | |
gem "sqlite3" | |
gem "logger" | |
end | |
# Set up the database for the example | |
ActiveRecord::Base.establish_connection({ adapter: "sqlite3", database: ":memory:" }) | |
ActiveRecord::Schema.define do | |
self.verbose = false | |
create_table :books do |t| | |
t.string :title | |
t.integer :author_id | |
end | |
create_table :authors do |t| | |
t.string :name | |
end | |
end | |
class Author < ActiveRecord::Base | |
has_many :books | |
end | |
class Book < ActiveRecord::Base | |
belongs_to :author | |
end | |
a1 = Author.create(name: "Beatrix Potter") | |
a1.books.create!(title: "The Tale of Ginger and Pickles") | |
a1.books.create!(title: "The Tale of Samuel Whiskers") | |
a2 = Author.create!(name: "Sandra Boynton") | |
a2.books.create!(title: "Birthday Monsters") | |
a2.books.create!(title: "But Not the Hippopotamus") | |
class MySchema < GraphQL::Schema | |
class Author < GraphQL::Schema::Object | |
field :name, String | |
end | |
class Book < GraphQL::Schema::Object | |
field :title, String | |
field :author, Author | |
if ENV["WITH_DATALOADER"] | |
def author | |
# Could also be: | |
# dataloader.with(GraphQL::Dataloader::ActiveRecordAssociationSource, :author).load(object) | |
dataload_association(:author) | |
end | |
end | |
end | |
class Query < GraphQL::Schema::Object | |
field :books, [Book] do | |
argument :ids, [ID] | |
end | |
def books(ids:) | |
::Book.where(id: ids) | |
end | |
end | |
query(Query) | |
use GraphQL::Dataloader | |
end | |
ActiveRecord::Base.logger = Logger.new(STDOUT) | |
pp MySchema.execute <<~GRAPHQL | |
query GetManyBooks { | |
books(ids: [1, 2, 3, 4]) { | |
title | |
author { | |
name | |
} | |
} | |
} | |
GRAPHQL | |
# ruby list_of_nodes_example.rb | |
# D, [2025-04-01T18:22:15.672155 #86219] DEBUG -- : Book Load (0.1ms) SELECT "books".* FROM "books" WHERE "books"."id" IN (?, ?, ?, ?) [["id", 1], ["id", 2], ["id", 3], ["id", 4]] | |
# D, [2025-04-01T18:22:15.673230 #86219] DEBUG -- : Author Load (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] | |
# D, [2025-04-01T18:22:15.673620 #86219] DEBUG -- : Author Load (0.0ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] | |
# D, [2025-04-01T18:22:15.673945 #86219] DEBUG -- : Author Load (0.0ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]] | |
# D, [2025-04-01T18:22:15.674262 #86219] DEBUG -- : Author Load (0.0ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]] | |
# | |
# WITH_DATALOADER=1 ruby list_of_nodes_example.rb | |
# D, [2025-04-01T18:22:23.088179 #86235] DEBUG -- : Book Load (0.2ms) SELECT "books".* FROM "books" WHERE "books"."id" IN (?, ?, ?, ?) [["id", 1], ["id", 2], ["id", 3], ["id", 4]] | |
# D, [2025-04-01T18:22:23.095555 #86235] DEBUG -- : Author Load (0.2ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" IN (?, ?) [["id", 1], ["id", 2]] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment