Skip to content

Commit

Permalink
Add linear query matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
caalberts committed Oct 10, 2020
1 parent 2d46076 commit 28af9bc
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 2 deletions.
1 change: 1 addition & 0 deletions lib/n_plus_one_control/rspec.rb
Expand Up @@ -5,6 +5,7 @@
require "n_plus_one_control"
require "n_plus_one_control/rspec/dsl"
require "n_plus_one_control/rspec/matchers/perform_constant_number_of_queries"
require "n_plus_one_control/rspec/matchers/perform_linear_number_of_queries"
require "n_plus_one_control/rspec/context"

module NPlusOneControl
Expand Down
@@ -0,0 +1,35 @@
# frozen_string_literal: true

# rubocop:disable Metrics/BlockLength
::RSpec::Matchers.define :perform_linear_number_of_queries do |slope: 1, intercept: 1|
supports_block_expectations

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

raise "Missing tag :n_plus_one" unless
@matcher_execution_context.respond_to?(:n_plus_one_populate)

populate = @matcher_execution_context.n_plus_one_populate

@matcher_execution_context.executor = NPlusOneControl::Executor.new(
population: populate,
matching: nil,
scale_factors: @factors
)

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

@queries.all? do |scale, queries|
queries.size <= slope * scale + intercept
end
end

match_when_negated do |_actual|
raise "This matcher doesn't support negation"
end

# TODO: failure message for linear queries
# failure_message { |_actual| NPlusOneControl.failure_message(@queries) }
end
# rubocop:enable Metrics/BlockLength
Expand Up @@ -52,7 +52,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:\d+/im)
end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /select .+ from.*↳ .*_spec.rb:\d+/im)
end

context "when truncate size is specified" do
Expand Down Expand Up @@ -87,7 +87,7 @@
.to perform_constant_number_of_queries
end.to raise_error(
RSpec::Expectations::ExpectationNotMetError,
/select .+ from.*↳.*rspec_spec.rb:\d+.*\n.*rspec_spec.rb:\d+/im
/select .+ from.*↳.*_spec.rb:\d+.*\n.*_spec.rb:\d+/im
)
end
end
Expand Down
@@ -0,0 +1,52 @@
# frozen_string_literal: true

require "spec_helper"

describe NPlusOneControl::RSpec do
describe 'perform_linear_number_of_queries' do
context "when constant queries", :n_plus_one do
populate { |n| create_list(:post, n) }

specify do
expect { Post.preload(:user).find_each { |p| p.user.name } }
.not_to raise_error(RSpec::Expectations::ExpectationNotMetError)
end
end

context "when has linear query", :n_plus_one do
populate { |n| create_list(:post, n) }

specify do
expect { Post.find_each { |p| p.user.name } }
.to perform_linear_number_of_queries
end
end

context "when has linear query larger than expected slope", :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_linear_number_of_queries
end.to raise_error(RSpec::Expectations::ExpectationNotMetError)
end
end

context "when context is missing" do
specify do
expect do
expect { subject }.to perform_linear_number_of_queries
end.to raise_error(/missing tag/i)
end
end

context "when negated" do
specify do
expect do
expect { subject }.not_to perform_linear_number_of_queries
end.to raise_error(/support negation/i)
end
end
end
end
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 :posts
end

FactoryGirl.define do
factory :category do
name "Category"
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 28af9bc

Please sign in to comment.