Skip to content

Instantly share code, notes, and snippets.

@nbulaj
Last active June 20, 2019 10:23
Show Gist options
  • Save nbulaj/6d6c2af5955503d9fd7b4a6702dcf564 to your computer and use it in GitHub Desktop.
Save nbulaj/6d6c2af5955503d9fd7b4a6702dcf564 to your computer and use it in GitHub Desktop.
# frozen_string_literal: true
RSpec::Matchers.define :exceed_query_limit do |expected, pattern = nil|
supports_block_expectations
match do |block|
query_count(pattern, &block) > expected
end
failure_message_when_negated do |actual|
"Expected to run maximum #{expected} queries, got #{@counter.query_count}"
end
def query_count(pattern, &block)
@counter = ActiveRecord::QueryCounter.new(pattern)
ActiveSupport::Notifications.subscribed(@counter.to_proc, 'sql.active_record', &block)
@counter.query_count
end
end
# frozen_string_literal: true
# spec/support/active_record_query_counter.rb
module ActiveRecord
class QueryCounter
IGNORED_SQL = [
/^PRAGMA (?!(table_info))/,
/^SELECT currval/,
/^SELECT CAST/,
/^SELECT @@IDENTITY/,
/^SELECT @@ROWCOUNT/,
/^SAVEPOINT/,
/^ROLLBACK TO SAVEPOINT/,
/^RELEASE SAVEPOINT/,
/^SHOW max_identifier_length/,
].freeze
attr_reader :pattern, :queries_count
def initialize(pattern)
@pattern = pattern
@queries_count = 0
end
def to_proc
lambda(&method(:callback))
end
def callback(_name, _start, _finish, _message_id, values)
@queries_count += 1 if !ignore?(values) && match_pattern?(values)
end
def ignore?(values)
%w[CACHE SCHEMA].include?(values[:name]) ||
IGNORED_SQL.any? { |query| values[:sql] =~ query }
end
def match_pattern?(values)
return true if @pattern.nil?
values[:sql] =~ @pattern
end
end
end
it "checks for N+1 on querying" do
# .with_some_associations must perform includes with JOIN and perform only one SELECT query
expect { SomeModel.with_some_associations.first }.not_to exceed_query_limit(1)
end
it "checks count of UPDATE statements" do
# just an example
expect { MySyperRepository.create_invocve!}.not_to exceed_query_limit(2, /^UPDATE/)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment