Skip to content

Commit

Permalink
Add with_buffer chain on rspec matcher
Browse files Browse the repository at this point in the history
`with_buffer` takes an integer buffer
to allow for existing N+1 queries.
  • Loading branch information
caalberts committed Oct 5, 2020
1 parent eb9966c commit a451e61
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 3 deletions.
12 changes: 11 additions & 1 deletion lib/n_plus_one_control/rspec/matcher.rb
Expand Up @@ -16,6 +16,10 @@
@warmup = true
end

chain :with_buffer do |buffer|
@buffer = buffer
end

match do |actual, *_args|
raise ArgumentError, "Block is required" unless actual.is_a? Proc

Expand All @@ -37,9 +41,15 @@

@queries = @matcher_execution_context.executor.call(&actual)

scale_factors = @queries.map(&:first)
counts = @queries.map(&:last).map(&:size)

counts.max == counts.min
if scale_factors.max == scale_factors.min
counts.max == counts.min
else
buffer = @buffer || 0
(counts.max - counts.min) / (scale_factors.max - scale_factors.min) <= buffer
end
end

match_when_negated do |_actual|
Expand Down
35 changes: 33 additions & 2 deletions spec/n_plus_one_control/rspec_spec.rb
Expand Up @@ -23,6 +23,28 @@
end
end

context "when has N+1 with buffer", :n_plus_one do
populate { |n| create_list(:post, n) }

specify do
expect do
expect { Post.find_each { |p| p.user.name } }
.to perform_constant_number_of_queries.with_buffer(1)
end.not_to raise_error
end
end

context "when has N+1 exceeding buffer", :n_plus_one do
populate { |n| create_list(:post, n) }

specify do
expect do
expect { Post.find_each { |p| "#{p.user.name} #{p.category.name}" } }
.to perform_constant_number_of_queries.with_buffer(1)
end.to raise_error(RSpec::Expectations::ExpectationNotMetError)
end
end

context "when context is missing" do
specify do
expect do
Expand Down Expand Up @@ -52,7 +74,7 @@
expect do
expect { Post.find_each { |p| p.user.name } }
.to perform_constant_number_of_queries
end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /select .+ from.*↳ .*rspec_spec.rb:53/im)
end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /select .+ from.*↳ .*rspec_spec.rb:75/im)
end

context "when truncate size is specified" do
Expand Down Expand Up @@ -87,7 +109,7 @@
.to perform_constant_number_of_queries
end.to raise_error(
RSpec::Expectations::ExpectationNotMetError,
/select .+ from.*↳.*rspec_spec.rb:86.*\n.*rspec_spec.rb:86/im
/select .+ from.*↳.*rspec_spec.rb:108.*\n.*rspec_spec.rb:108/im
)
end
end
Expand All @@ -113,6 +135,15 @@
context "with scale_factors", :n_plus_one do
populate { |n| create_list(:post, n) }

specify do
expect { Post.preload(:user).find_each { |p| p.user.name } }
.to perform_constant_number_of_queries.with_scale_factors(1, 2)
end
end

context "with equal scale_factors", :n_plus_one do
populate { |n| create_list(:post, n) }

specify do
expect { Post.find_each { |p| p.user.name } }
.to perform_constant_number_of_queries.with_scale_factors(1, 1)
Expand Down
17 changes: 17 additions & 0 deletions spec/support/category.rb
@@ -0,0 +1,17 @@
# frozen_string_literal: true

ActiveRecord::Schema.define do
create_table :categories do |t|
t.string :name
end
end

class Category < ActiveRecord::Base
has_many :post
end

FactoryGirl.define do
factory :category do
name "Fiction"
end
end
3 changes: 3 additions & 0 deletions spec/support/post.rb
Expand Up @@ -4,16 +4,19 @@
create_table :posts do |t|
t.string :title
t.integer :user_id
t.integer :category_id
end
end

class Post < ActiveRecord::Base
belongs_to :user
belongs_to :category
end

FactoryGirl.define do
factory :post do
title "Title"
user
category
end
end

0 comments on commit a451e61

Please sign in to comment.