# taken from: http://stackoverflow.com/questions/5490411/counting-the-number-of-queries-performed
module ActiveRecord
  class QueryCounter

    attr_reader :query_count, :performed_queries

    def initialize
      @performed_queries = []
      @query_count = 0
    end

    def to_proc
      lambda(&method(:callback))
    end

    def callback(name, start, finish, message_id, values)
      count_query = true
      count_query = false if %w[ CACHE SCHEMA SAVEPOINT ].include?(values[:name]) or values[:sql]['SAVEPOINT']
      count_query = false if %w[ BEGIN COMMIT ].include?(values[:sql])
      if count_query
        @query_count += 1
        @performed_queries << values[:sql]
      end
    end

  end
end

RSpec::Matchers.define :exceed_query_limit do |expected|

  match do |block|
    query_count(&block) > expected
  end

  failure_message_when_negated do |actual|
    "Expected to run maximum #{expected} queries, got #{@counter.query_count}\n#{@counter.performed_queries.join("\n")}"
  end

  failure_message do |actual|
    "Expected to run minimum #{expected} queries, got #{@counter.query_count}\n#{@counter.performed_queries.join("\n")}"
  end

  def query_count(&block)
    @counter = ActiveRecord::QueryCounter.new
    ActiveSupport::Notifications.subscribed(@counter.to_proc, 'sql.active_record', &block)
    @counter.query_count
  end

  def supports_block_expectations?
    true
  end

end

RSpec::Matchers.define :have_query_count do |expected|
  match do |block|
    query_count(&block) == expected
  end

  failure_message_when_negated do |actual|
    "Expected to run #{expected} queries, got #{@counter.query_count}\n#{@counter.performed_queries.join("\n")}"
  end

  failure_message do |actual|
    "Expected to not run #{expected} queries, got #{@counter.query_count}\n#{@counter.performed_queries.join("\n")}"
  end

  def query_count(&block)
    @counter = ActiveRecord::QueryCounter.new
    ActiveSupport::Notifications.subscribed(@counter.to_proc, 'sql.active_record', &block)
    @counter.query_count
  end

  def supports_block_expectations?
    true
  end

end
