Created
June 21, 2022 18:47
-
-
Save JoshCheek/57205d59e42a1271174c3b0850820a49 to your computer and use it in GitHub Desktop.
ar_lazy_preload example (for graphql without N+1 issues)
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
# Config | |
require 'rails' | |
require 'ar_lazy_preload' # https://github.com/DmitryTsepelev/ar_lazy_preload | |
require 'active_record' | |
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:' | |
# not sure where this is supposed to happen, but it's necessary b/c ar_lazy_preload | |
# adds its functionality in a callback after active record finishes loading. | |
ArLazyPreload::Railtie.config.to_prepare_blocks.each(&:call) | |
# Schema | |
ActiveRecord::Schema.define do | |
self.verbose = false | |
create_table :users do |t| | |
t.string :name | |
end | |
create_table :posts do |t| | |
t.string :name | |
t.integer :user_id | |
end | |
create_table :comments do |t| | |
t.string :body | |
t.integer :post_id | |
end | |
end | |
# Models | |
class User < ActiveRecord::Base | |
has_many :posts | |
end | |
class Post < ActiveRecord::Base | |
belongs_to :user | |
has_many :comments | |
end | |
class Comment < ActiveRecord::Base | |
belongs_to :post | |
end | |
# Seed Data | |
user = User.create! name: 'Josh' | |
post1, post2 = user.posts = [Post.new(name: 'yo ho ho'), Post.new(name: 'and a bottle of rum')] | |
post1.comments.create! body: 'a pirate!' | |
post1.comments.create! body: 'blow the man down!' | |
post2.comments.create! body: 'or whiskey!' | |
user = User.create! name: 'Jan' | |
post, * = user.posts = [Post.new(name: 'Grape Jelly 4 lyfe!')] | |
post.comments.create! body: 'jan likes jam!' | |
# Helper Functions | |
def self.capture_queries(&block) | |
queries = [] | |
capturer = -> *, data { queries << data.values_at(:name, :sql).select(&:present?).join(": ") } | |
ActiveSupport::Notifications.subscribed capturer, "sql.active_record", &block | |
queries | |
end | |
# ===== Examples ===== | |
# Only loads users, b/c did not try to access posts | |
capture_queries do | |
User | |
.all | |
.lazy_preload(posts: :comments) | |
.map(&:name) # => ["Josh", "Jan"] | |
end | |
# => ["User Load: SELECT \"users\".* FROM \"users\""] | |
# Only loads users, and posts, b/c did not try to access comments | |
capture_queries do | |
User | |
.all | |
.lazy_preload(posts: :comments) | |
.map do |u| | |
{ name: u.name, | |
posts: u.posts.map { |p| p.name }, | |
} | |
end | |
# => [{:name=>"Josh", :posts=>["yo ho ho", "and a bottle of rum"]}, | |
# {:name=>"Jan", :posts=>["Grape Jelly 4 lyfe!"]}] | |
end | |
# => ["User Load: SELECT \"users\".* FROM \"users\"", | |
# "Post Load: SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" IN (?, ?)"] | |
# Loads users, posts, and comments, b/c accessed all of them | |
capture_queries do | |
User | |
.all | |
.lazy_preload(posts: :comments) | |
.map do |u| | |
{ name: u.name, | |
posts: u.posts.map { |p| | |
{ name: p.name, comments: p.comments.map(&:body) } | |
}, | |
} | |
end | |
# => [{:name=>"Josh", | |
# :posts=> | |
# [{:name=>"yo ho ho", :comments=>["a pirate!", "blow the man down!"]}, | |
# {:name=>"and a bottle of rum", :comments=>["or whiskey!"]}]}, | |
# {:name=>"Jan", | |
# :posts=> | |
# [{:name=>"Grape Jelly 4 lyfe!", :comments=>["jan likes jam!"]}]}] | |
end | |
# => ["User Load: SELECT \"users\".* FROM \"users\"", | |
# "Post Load: SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" IN (?, ?)", | |
# "Comment Load: SELECT \"comments\".* FROM \"comments\" WHERE \"comments\".\"post_id\" IN (?, ?, ?)"] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment