63 lines
1.1 KiB
Ruby
63 lines
1.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Nplus1QueryHelpers
|
|
DEFAULT_THRESHOLD = 3
|
|
|
|
def with_threshold(threshold)
|
|
@threshold = threshold
|
|
self
|
|
end
|
|
|
|
def for_query(query)
|
|
@query = query
|
|
self
|
|
end
|
|
|
|
def threshold
|
|
@threshold || DEFAULT_THRESHOLD
|
|
end
|
|
|
|
def occurrences
|
|
@occurrences ||=
|
|
if @query
|
|
recorder.occurrences.select { |recorded, count| recorded =~ @query }
|
|
else
|
|
recorder.occurrences
|
|
end
|
|
end
|
|
|
|
def over_threshold
|
|
occurrences.select do |recorded, count|
|
|
count > threshold
|
|
end
|
|
end
|
|
|
|
def recorder
|
|
@recorder ||= ActiveRecord::QueryRecorder.new(&@subject_block)
|
|
end
|
|
|
|
def verify_count(&block)
|
|
@subject_block = block
|
|
over_threshold.present?
|
|
end
|
|
|
|
def failure_message
|
|
log_message = over_threshold.to_yaml
|
|
"The following queries are executed more than #{threshold} time(s):\n#{log_message}"
|
|
end
|
|
end
|
|
|
|
RSpec::Matchers.define :be_n_plus_1_query do
|
|
supports_block_expectations
|
|
|
|
include Nplus1QueryHelpers
|
|
|
|
match do |block|
|
|
verify_count(&block)
|
|
end
|
|
|
|
failure_message_when_negated do |actual|
|
|
failure_message
|
|
end
|
|
end
|