Module: NPlusOneControl

Defined in:
lib/n_plus_one_control.rb,
lib/n_plus_one_control/rspec.rb,
lib/n_plus_one_control/railtie.rb,
lib/n_plus_one_control/version.rb,
lib/n_plus_one_control/executor.rb,
lib/n_plus_one_control/minitest.rb,
lib/n_plus_one_control/rspec/dsl.rb

Overview

:nodoc:

Defined Under Namespace

Modules: MinitestHelper, RSpec Classes: Executor, Railtie

Constant Summary collapse

EXTRACT_TABLE_RXP =

Used to extract a table name from a query

/(insert into|update|delete from|from) ['"`](\S+)['"`]/i.freeze
QUERY_PART_TO_TYPE =

Used to convert a query part extracted by the regexp above to the corresponding human-friendly type

{
  "insert into" => "INSERT",
  "update" => "UPDATE",
  "delete from" => "DELETE",
  "from" => "SELECT"
}.freeze
FAILURE_MESSAGES =
{
  constant_queries: "Expected to make the same number of queries",
  linear_queries: "Expected to make linear number of queries",
  number_of_queries: "Expected to make the specified number of queries"
}
VERSION =
"0.7.1"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.backtrace_cleanerObject

Returns the value of attribute backtrace_cleaner.



21
22
23
# File 'lib/n_plus_one_control.rb', line 21

def backtrace_cleaner
  @backtrace_cleaner
end

.backtrace_lengthObject

Returns the value of attribute backtrace_length.



21
22
23
# File 'lib/n_plus_one_control.rb', line 21

def backtrace_length
  @backtrace_length
end

.default_matchingObject

Returns the value of attribute default_matching.



24
25
26
# File 'lib/n_plus_one_control.rb', line 24

def default_matching
  @default_matching
end

.default_scale_factorsObject

Returns the value of attribute default_scale_factors.



21
22
23
# File 'lib/n_plus_one_control.rb', line 21

def default_scale_factors
  @default_scale_factors
end

.eventObject

Returns the value of attribute event.



21
22
23
# File 'lib/n_plus_one_control.rb', line 21

def event
  @event
end

.ignoreObject

Returns the value of attribute ignore.



21
22
23
# File 'lib/n_plus_one_control.rb', line 21

def ignore
  @ignore
end

.show_table_statsObject

Returns the value of attribute show_table_stats.



21
22
23
# File 'lib/n_plus_one_control.rb', line 21

def show_table_stats
  @show_table_stats
end

.truncate_query_sizeObject

Returns the value of attribute truncate_query_size.



21
22
23
# File 'lib/n_plus_one_control.rb', line 21

def truncate_query_size
  @truncate_query_size
end

.verboseObject

Returns the value of attribute verbose.



21
22
23
# File 'lib/n_plus_one_control.rb', line 21

def verbose
  @verbose
end

Class Method Details

.failure_message(type, queries) ⇒ Object

rubocop:disable Metrics/MethodLength



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/n_plus_one_control.rb', line 32

def failure_message(type, queries) # rubocop:disable Metrics/MethodLength
  msg = ["#{FAILURE_MESSAGES[type]}, but got:\n"]
  queries.each do |(scale, data)|
    msg << "  #{data.size} for N=#{scale}\n"
  end

  msg.concat(table_usage_stats(queries.map(&:last))) if show_table_stats

  if verbose
    queries.each do |(scale, data)|
      msg << "Queries for N=#{scale}\n"
      msg << data.map { |sql| "  #{truncate_query(sql)}\n" }.join.to_s
    end
  end

  msg.join
end

.table_usage_stats(runs) ⇒ Object

rubocop:disable Metrics/MethodLength



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/n_plus_one_control.rb', line 50

def table_usage_stats(runs) # rubocop:disable Metrics/MethodLength
  msg = ["Unmatched query numbers by tables:\n"]

  before, after = runs.map do |queries|
    queries.group_by do |query|
      matches = query.match(EXTRACT_TABLE_RXP)
      next unless matches

      "  #{matches[2]} (#{QUERY_PART_TO_TYPE[matches[1].downcase]})"
    end.transform_values(&:count)
  end

  before.keys.each do |k|
    next if before[k] == after&.fetch(k, nil)

    after_value = after ? " != #{after[k]}" : ""
    msg << "#{k}: #{before[k]}#{after_value}\n"
  end

  msg
end