Last active
May 5, 2016 12:57
-
-
Save pithyless/19a585657532a7fb0a6b to your computer and use it in GitHub Desktop.
Helper to check for N+1 queries in rspec
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'method_struct' | |
class CheckForN1Queries < MethodStruct.new(:generator, :operation, :debug) | |
IGNORED_SQL = [ | |
/^SHOW/, /^EXPLAIN/, /^PRAGMA (?!(table_info))/, /^SELECT currval/, /^SELECT CAST/, | |
/^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, | |
/^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/ | |
] | |
def call | |
2.times { generator.call } | |
log("BEFORE:") | |
old_count = count_total_queries { operation.call } | |
generator.call | |
log("AFTER:") | |
new_count = count_total_queries { operation.call } | |
[old_count, new_count] | |
end | |
private | |
def log(msg) | |
puts(["\n", msg, "\n"].join) if debug | |
end | |
def count_total_queries(&block) | |
query_count = 0 | |
callback = proc do |name, start, finish, message_id, values| | |
next if values[:name] == 'CACHE' || IGNORED_SQL.any? { |r| values[:sql] =~ r } | |
log(values[:sql]) | |
query_count += 1 | |
end | |
subscribed(callback, "sql.active_record", &block) | |
query_count | |
end | |
# Backported from Rails 3.2.1 | |
def subscribed(callback, *args, &block) | |
subscriber = ActiveSupport::Notifications.subscribe(*args, &callback) | |
yield | |
ensure | |
ActiveSupport::Notifications.unsubscribe(subscriber) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
describe PostController do | |
it 'avoids N+1 queries' do | |
old_count, new_count = CheckForN1Queries.call( | |
generator: proc { create_blog_post }, | |
operation: proc { get :index }, | |
debug: false | |
) | |
expect(new_count).to eq(old_count) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment