Skip to content

Instantly share code, notes, and snippets.

@haseebeqx
Created October 9, 2018 17:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save haseebeqx/aef6e73f88508bdc3aa1f8010b20aa05 to your computer and use it in GitHub Desktop.
Save haseebeqx/aef6e73f88508bdc3aa1f8010b20aa05 to your computer and use it in GitHub Desktop.
n+1 issue find using rspec
# from gitlab/spec/support/matchers/exceed_query_limit.rb
RSpec::Matchers.define :exceed_query_limit do |expected|
supports_block_expectations
match do |block|
@subject_block = block
actual_count > expected_count + threshold
end
failure_message_when_negated do |actual|
threshold_message = threshold > 0 ? " (+#{@threshold})" : ''
counts = "#{expected_count}#{threshold_message}"
"Expected a maximum of #{counts} queries, got #{actual_count}:\n\n#{log_message}"
end
def with_threshold(threshold)
@threshold = threshold
self
end
def for_query(query)
@query = query
self
end
def threshold
@threshold.to_i
end
def expected_count
if expected.is_a?(ActiveRecord::QueryRecorder)
expected.count
else
expected
end
end
def actual_count
@actual_count ||= if @query
recorder.log.select { |recorded| recorded =~ @query }.size
else
recorder.count
end
end
def recorder
@recorder ||= ActiveRecord::QueryRecorder.new(&@subject_block)
end
def count_queries(queries)
queries.each_with_object(Hash.new(0)) { |query, counts| counts[query] += 1 }
end
def log_message
if expected.is_a?(ActiveRecord::QueryRecorder)
counts = count_queries(expected.log)
extra_queries = @recorder.log.reject { |query| counts[query] -= 1 unless counts[query].zero? }
extra_queries_display = count_queries(extra_queries).map { |query, count| "[#{count}] #{query}" }
(['Extra queries:'] + extra_queries_display).join("\n\n")
else
@recorder.log_message
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment