n_plus_one_control 0.4.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b20b8f4269aac76f3da642b271b93ddee2adf508539bba6852e02225695de155
4
- data.tar.gz: e739f342b4d46cc451229f3a065cb0e2b83ee28c301d99045d0f094e74bc137b
3
+ metadata.gz: 95b1fada3d7db7a761650c8cd63b93b93a463dcdbfcf2df2b6e3ea25ac04355a
4
+ data.tar.gz: 3a3937ad74d66ea0bc0e56b50954c585c36c401b67d9af4dfd2a94e4202ae0be
5
5
  SHA512:
6
- metadata.gz: 74805b4ea497ff96bb882557ed8a14e04d32cf5ea5c62e9c65167647c880275aec9d0f8a405a298554e9cfecbb20049d99f630b977475a75122d847c7b27e1a9
7
- data.tar.gz: 19063ec1fb2a84edcfd0e38075a3858e239a438803ffb40e03916bc8eb5d49dda9e8b03a30a60788e4e00f9c5484811740448fe3241e64658a78ccf884619321
6
+ metadata.gz: 9ce963308cf99f1c836e7d883a71dbab0b22f8326692444aa3c6639dfc87065fd3e6866ee1af5b358b42cbc67af4a1640677fc051264c8ba6bc35a1604953bd2
7
+ data.tar.gz: f914d8e34d49f7ace51c872fde24487f216b481f39b8236b9c7d24bef26530ba5cbd1040b71d0b445a73f5769762e942fd3b00a7d4211a704fa9dcebf3bd34d9
data/CHANGELOG.md CHANGED
@@ -1,4 +1,34 @@
1
- ## master (unreleased)
1
+ # Change log
2
+
3
+ ## master
4
+
5
+ ## 0.6.2 (2021-10-26)
6
+
7
+ - Fix .ignore setting (.ignore setting was ignored by the Collector ;-))
8
+ - Fix rspec matchers to allow expectations inside execution block
9
+
10
+ ## 0.6.1 (2021-03-05)
11
+
12
+ - Ruby 3.0 compatibility. ([@palkan][])
13
+
14
+ ## 0.6.0 (2020-11-27)
15
+
16
+ - Fix table stats summary when queries use backticks to surround table names ([@andrewhampton][])
17
+ - Add support to test for linear query. ([@caalberts][])
18
+
19
+ ## 0.5.0 (2020-09-07)
20
+
21
+ - **Ruby 2.5+ is required**. ([@palkan][])
22
+
23
+ - Add support for multiple backtrace lines in verbose output. ([@palkan][])
24
+
25
+ Could be specified via `NPLUSONE_BACKTRACE` env var.
26
+
27
+ - Add `NPLUSONE_TRUNCATE` env var to truncate queries in verbose mode. ([@palkan][])
28
+
29
+ - Support passing default filter via `NPLUSONE_FILTER` env var. ([@palkan][])
30
+
31
+ - Add location tracing to SQLs in verbose mode. ([@palkan][])
2
32
 
3
33
  ## 0.4.1 (2020-09-04)
4
34
 
@@ -12,3 +42,5 @@
12
42
 
13
43
  [@Earendil95]: https://github.com/Earendil95
14
44
  [@palkan]: https://github.com/palkan
45
+ [@caalberts]: https://github.com/caalberts
46
+ [@andrewhampton]: https://github.com/andrewhampton
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
- [![Gem Version](https://badge.fury.io/rb/n_plus_one_control.svg)](https://rubygems.org/gems/n_plus_one_control) [![Build Status](https://travis-ci.org/palkan/n_plus_one_control.svg?branch=master)](https://travis-ci.org/palkan/n_plus_one_control)
1
+ [![Gem Version](https://badge.fury.io/rb/n_plus_one_control.svg)](https://rubygems.org/gems/n_plus_one_control)
2
+ ![Build](https://github.com/palkan/n_plus_one_control/workflows/Build/badge.svg)
2
3
 
3
4
  # N + 1 Control
4
5
 
@@ -31,7 +32,7 @@ Add this line to your application's Gemfile:
31
32
 
32
33
  ```ruby
33
34
  group :test do
34
- gem 'n_plus_one_control'
35
+ gem "n_plus_one_control"
35
36
  end
36
37
  ```
37
38
 
@@ -47,8 +48,6 @@ First, add NPlusOneControl to your `spec_helper.rb`:
47
48
 
48
49
  ```ruby
49
50
  # spec_helper.rb
50
- ...
51
-
52
51
  require "n_plus_one_control/rspec"
53
52
  ```
54
53
 
@@ -86,10 +85,10 @@ Availables modifiers:
86
85
  ```ruby
87
86
  # You can specify the RegExp to filter queries.
88
87
  # By default, it only considers SELECT queries.
89
- expect { ... }.to perform_constant_number_of_queries.matching(/INSERT/)
88
+ expect { get :index }.to perform_constant_number_of_queries.matching(/INSERT/)
90
89
 
91
90
  # You can also provide custom scale factors
92
- expect { ... }.to perform_constant_number_of_queries.with_scale_factors(10, 100)
91
+ expect { get :index }.to perform_constant_number_of_queries.with_scale_factors(10, 100)
93
92
  ```
94
93
 
95
94
  #### Using scale factor in spec
@@ -97,7 +96,7 @@ expect { ... }.to perform_constant_number_of_queries.with_scale_factors(10, 100)
97
96
  Let's suppose your action accepts parameter, which can make impact on the number of returned records:
98
97
 
99
98
  ```ruby
100
- get :index, params: { per_page: 10 }
99
+ get :index, params: {per_page: 10}
101
100
  ```
102
101
 
103
102
  Then it is enough to just change `per_page` parameter between executions and do not recreate records in DB. For this purpose, you can use `current_scale` method in your example:
@@ -107,7 +106,36 @@ context "N+1", :n_plus_one do
107
106
  before { create_list :post, 3 }
108
107
 
109
108
  specify do
110
- expect { get :index, params: { per_page: current_scale } }.to perform_constant_number_of_queries
109
+ expect { get :index, params: {per_page: current_scale} }.to perform_constant_number_of_queries
110
+ end
111
+ end
112
+ ```
113
+
114
+ ### Expectations in execution block
115
+
116
+ Both rspec matchers allows you to put additional expectations inside execution block to ensure that tested piece of code actually does what expected.
117
+
118
+ ```ruby
119
+ context "N+1", :n_plus_one do
120
+ specify do
121
+ expect do
122
+ expect(my_query).to eq(actuall_results)
123
+ end.to perform_constant_number_of_queries
124
+ end
125
+ end
126
+ ```
127
+
128
+ #### Other available matchers
129
+
130
+ `perform_linear_number_of_queries(slope: 1)` allows you to test that a query generates linear number of queries with the given slope.
131
+
132
+ ```ruby
133
+ context "when has linear query", :n_plus_one do
134
+ populate { |n| create_list(:post, n) }
135
+
136
+ specify do
137
+ expect { Post.find_each { |p| p.user.name } }
138
+ .to perform_linear_number_of_queries(slope: 1)
111
139
  end
112
140
  end
113
141
  ```
@@ -118,8 +146,6 @@ First, add NPlusOneControl to your `test_helper.rb`:
118
146
 
119
147
  ```ruby
120
148
  # test_helper.rb
121
- ...
122
-
123
149
  require "n_plus_one_control/minitest"
124
150
  ```
125
151
 
@@ -135,6 +161,18 @@ def test_no_n_plus_one_error
135
161
  end
136
162
  ```
137
163
 
164
+ You can also use `assert_perform_linear_number_of_queries` to test for linear queries:
165
+
166
+ ```ruby
167
+ def test_no_n_plus_one_error
168
+ populate = ->(n) { create_list(:post, n) }
169
+
170
+ assert_perform_linear_number_of_queries(slope: 1, populate: populate) do
171
+ Post.find_each { |p| p.user.name }
172
+ end
173
+ end
174
+ ```
175
+
138
176
  You can also specify custom scale factors or filter patterns:
139
177
 
140
178
  ```ruby
@@ -153,6 +191,12 @@ assert_perform_constant_number_of_queries(
153
191
  end
154
192
  ```
155
193
 
194
+ It's possible to specify a filter via `NPLUSONE_FILTER` env var, e.g.:
195
+
196
+ ```ruby
197
+ NPLUSONE_FILTER = users bundle exec rake test
198
+ ```
199
+
156
200
  You can also specify `populate` as a test class instance method:
157
201
 
158
202
  ```ruby
@@ -165,6 +209,7 @@ def test_no_n_plus_one_error
165
209
  get :index
166
210
  end
167
211
  end
212
+
168
213
  ```
169
214
 
170
215
  As in RSpec, you can use `current_scale` factor instead of `populate` block:
@@ -172,7 +217,7 @@ As in RSpec, you can use `current_scale` factor instead of `populate` block:
172
217
  ```ruby
173
218
  def test_no_n_plus_one_error
174
219
  assert_perform_constant_number_of_queries do
175
- get :index, params: { per_page: current_scale }
220
+ get :index, params: {per_page: current_scale}
176
221
  end
177
222
  end
178
223
  ```
@@ -223,6 +268,7 @@ end
223
268
  ```
224
269
 
225
270
  If your `warmup` and testing procs are identical, you can use:
271
+
226
272
  ```ruby
227
273
  expext { get :index }.to perform_constant_number_of_queries.with_warming_up # RSpec only
228
274
  ```
@@ -254,7 +300,7 @@ NPlusOneControl.ignore = /^(BEGIN|COMMIT|SAVEPOINT|RELEASE)/
254
300
  # ActiveSupport notifications event to track queries.
255
301
  # We track ActiveRecord event by default,
256
302
  # but can also track rom-rb events ('sql.rom') as well.
257
- NPlusOneControl.event = 'sql.active_record'
303
+ NPlusOneControl.event = "sql.active_record"
258
304
 
259
305
  # configure transactional behavour for populate method
260
306
  # in case of use multiple database connections
@@ -268,6 +314,21 @@ NPlusOneControl::Executor.tap do |executor|
268
314
  connections.each(&:rollback_transaction)
269
315
  end
270
316
  end
317
+
318
+ # Provide a backtrace cleaner callable object used to filter SQL caller location to display in the verbose mode
319
+ # Set it to nil to disable tracing.
320
+ #
321
+ # In Rails apps, we use Rails.backtrace_cleaner by default.
322
+ NPlusOneControl.backtrace_cleaner = ->(locations_array) { do_some_filtering(locations_array) }
323
+
324
+ # You can also specify the number of backtrace lines to show.
325
+ # MOTE: It could be specified via NPLUSONE_BACKTRACE env var
326
+ NPlusOneControl.backtrace_length = 1
327
+
328
+ # Sometime queries could be too large to provide any meaningful insight.
329
+ # You can configure an output length limit for quries in verbose mode by setting the follwing option
330
+ # NOTE: It could be specified via NPLUSONE_TRUNCATE env var
331
+ NPlusOneControl.truncate_query_size = 100
271
332
  ```
272
333
 
273
334
  ## How does it work?
@@ -276,22 +337,29 @@ Take a look at our [Executor](https://github.com/palkan/n_plus_one_control/blob/
276
337
 
277
338
  ## What's next?
278
339
 
340
+ - More matchers.
341
+
279
342
  It may be useful to provide more matchers/assertions, for example:
280
343
 
281
344
  ```ruby
282
345
 
283
346
  # Actually, that means that it is N+1))
284
- assert_linear_number_of_queries { ... }
347
+ assert_linear_number_of_queries { some_code }
285
348
 
286
349
  # But we can tune it with `coef` and handle such cases as selecting in batches
287
350
  assert_linear_number_of_queries(coef: 0.1) do
288
- Post.find_in_batches { ... }
351
+ Post.find_in_batches { some_code }
289
352
  end
290
353
 
291
354
  # probably, also make sense to add another curve types
292
- assert_logarithmic_number_of_queries { ... }
355
+ assert_logarithmic_number_of_queries { some_code }
293
356
  ```
294
357
 
358
+ - Support custom non-SQL events.
359
+
360
+ N+1 problem is not a database specific: we can have N+1 Redis calls, N+1 HTTP external requests, etc.
361
+ We can make `n_plus_one_control` customizable to support these scenarios (technically, we need to make it possible to handle different payload in the event subscriber).
362
+
295
363
  If you want to discuss or implement any of these, feel free to open an [issue](https://github.com/palkan/n_plus_one_control/issues) or propose a [pull request](https://github.com/palkan/n_plus_one_control/pulls).
296
364
 
297
365
  ## Development
@@ -19,10 +19,28 @@ module NPlusOneControl
19
19
  @queries
20
20
  end
21
21
 
22
- def callback(_name, _start, _finish, _message_id, values)
22
+ def callback(_name, _start, _finish, _message_id, values) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/LineLength
23
23
  return if %w[CACHE SCHEMA].include? values[:name]
24
+ return if values[:sql].match?(NPlusOneControl.ignore)
24
25
 
25
- @queries << values[:sql] if @pattern.nil? || (values[:sql] =~ @pattern)
26
+ return unless @pattern.nil? || (values[:sql] =~ @pattern)
27
+
28
+ query = values[:sql]
29
+
30
+ if NPlusOneControl.backtrace_cleaner && NPlusOneControl.verbose
31
+ source = extract_query_source_location(caller)
32
+
33
+ query = "#{query}\n ↳ #{source.join("\n")}" unless source.empty?
34
+ end
35
+
36
+ @queries << query
37
+ end
38
+
39
+ private
40
+
41
+ def extract_query_source_location(locations)
42
+ NPlusOneControl.backtrace_cleaner.call(locations.lazy)
43
+ .take(NPlusOneControl.backtrace_length).to_a
26
44
  end
27
45
  end
28
46
 
@@ -18,7 +18,7 @@ module NPlusOneControl
18
18
 
19
19
  @executor = NPlusOneControl::Executor.new(
20
20
  population: populate || population_method,
21
- matching: matching || /^SELECT/i,
21
+ matching: matching || NPlusOneControl.default_matching,
22
22
  scale_factors: scale_factors || NPlusOneControl.default_scale_factors
23
23
  )
24
24
 
@@ -26,7 +26,30 @@ module NPlusOneControl
26
26
 
27
27
  counts = queries.map(&:last).map(&:size)
28
28
 
29
- assert counts.max == counts.min, NPlusOneControl.failure_message(queries)
29
+ assert counts.max == counts.min, NPlusOneControl.failure_message(:constant_queries, queries)
30
+ end
31
+
32
+ def assert_perform_linear_number_of_queries(
33
+ slope: 1,
34
+ populate: nil,
35
+ matching: nil,
36
+ scale_factors: nil,
37
+ warmup: nil
38
+ )
39
+
40
+ raise ArgumentError, "Block is required" unless block_given?
41
+
42
+ warming_up warmup
43
+
44
+ @executor = NPlusOneControl::Executor.new(
45
+ population: populate || population_method,
46
+ matching: matching || NPlusOneControl.default_matching,
47
+ scale_factors: scale_factors || NPlusOneControl.default_scale_factors
48
+ )
49
+
50
+ queries = @executor.call { yield }
51
+
52
+ assert linear?(queries, slope: slope), NPlusOneControl.failure_message(:linear_queries, queries)
30
53
  end
31
54
 
32
55
  def current_scale
@@ -42,6 +65,16 @@ module NPlusOneControl
42
65
  def population_method
43
66
  methods.include?(:populate) ? method(:populate) : nil
44
67
  end
68
+
69
+ def linear?(queries, slope:)
70
+ queries.each_cons(2).all? do |pair|
71
+ scales = pair.map(&:first)
72
+ query_lists = pair.map(&:last)
73
+
74
+ actual_slope = (query_lists[1].size - query_lists[0].size) / (scales[1] - scales[0])
75
+ actual_slope <= slope
76
+ end
77
+ end
45
78
  end
46
79
  end
47
80
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NPlusOneControl # :nodoc:
4
+ class Railtie < ::Rails::Railtie # :nodoc:
5
+ initializer "n_plus_one_control.backtrace_cleaner" do
6
+ ActiveSupport.on_load(:active_record) do
7
+ NPlusOneControl.backtrace_cleaner = lambda do |locations|
8
+ ::Rails.backtrace_cleaner.clean(locations)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -9,18 +9,18 @@ module NPlusOneControl
9
9
  # Setup warmup block, wich will run before matching
10
10
  # for example, if using cache, then later queries
11
11
  # will perform less DB queries than first
12
- def warmup
13
- return @warmup unless block_given?
12
+ def warmup(&block)
13
+ return @warmup unless block
14
14
 
15
- @warmup = Proc.new
15
+ @warmup = block
16
16
  end
17
17
 
18
18
  # Setup populate callback, which is used
19
19
  # to prepare data for each run.
20
- def populate
21
- return @populate unless block_given?
20
+ def populate(&block)
21
+ return @populate unless block
22
22
 
23
- @populate = Proc.new
23
+ @populate = block
24
24
  end
25
25
  end
26
26
 
@@ -16,7 +16,7 @@
16
16
  @warmup = true
17
17
  end
18
18
 
19
- match do |actual, *_args|
19
+ match(notify_expectation_failures: true) do |actual, *_args|
20
20
  raise ArgumentError, "Block is required" unless actual.is_a? Proc
21
21
 
22
22
  raise "Missing tag :n_plus_one" unless
@@ -27,8 +27,7 @@
27
27
 
28
28
  warmup.call if warmup.present?
29
29
 
30
- # by default we're looking for select queries
31
- pattern = @pattern || /^SELECT/i
30
+ pattern = @pattern || NPlusOneControl.default_matching
32
31
 
33
32
  @matcher_execution_context.executor = NPlusOneControl::Executor.new(
34
33
  population: populate,
@@ -47,6 +46,6 @@
47
46
  raise "This matcher doesn't support negation"
48
47
  end
49
48
 
50
- failure_message { |_actual| NPlusOneControl.failure_message(@queries) }
49
+ failure_message { |_actual| NPlusOneControl.failure_message(:constant_queries, @queries) }
51
50
  end
52
51
  # rubocop:enable Metrics/BlockLength
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/BlockLength
4
+ ::RSpec::Matchers.define :perform_linear_number_of_queries do |slope: 1|
5
+ supports_block_expectations
6
+
7
+ chain :with_scale_factors do |*factors|
8
+ @factors = factors
9
+ end
10
+
11
+ chain :matching do |pattern|
12
+ @pattern = pattern
13
+ end
14
+
15
+ chain :with_warming_up do
16
+ @warmup = true
17
+ end
18
+
19
+ match(notify_expectation_failures: true) do |actual, *_args|
20
+ raise ArgumentError, "Block is required" unless actual.is_a? Proc
21
+
22
+ raise "Missing tag :n_plus_one" unless
23
+ @matcher_execution_context.respond_to?(:n_plus_one_populate)
24
+
25
+ populate = @matcher_execution_context.n_plus_one_populate
26
+ warmup = @warmup ? actual : @matcher_execution_context.n_plus_one_warmup
27
+
28
+ warmup.call if warmup.present?
29
+
30
+ @matcher_execution_context.executor = NPlusOneControl::Executor.new(
31
+ population: populate,
32
+ matching: nil,
33
+ scale_factors: @factors
34
+ )
35
+
36
+ @queries = @matcher_execution_context.executor.call(&actual)
37
+
38
+ @queries.each_cons(2).all? do |pair|
39
+ scales = pair.map(&:first)
40
+ query_lists = pair.map(&:last)
41
+
42
+ actual_slope = (query_lists[1].size - query_lists[0].size) / (scales[1] - scales[0])
43
+ actual_slope <= slope
44
+ end
45
+ end
46
+
47
+ match_when_negated do |_actual|
48
+ raise "This matcher doesn't support negation"
49
+ end
50
+
51
+ failure_message { |_actual| NPlusOneControl.failure_message(:linear_queries, @queries) }
52
+ end
53
+ # rubocop:enable Metrics/BlockLength
@@ -4,7 +4,8 @@ gem "rspec-core", ">= 3.5"
4
4
 
5
5
  require "n_plus_one_control"
6
6
  require "n_plus_one_control/rspec/dsl"
7
- require "n_plus_one_control/rspec/matcher"
7
+ require "n_plus_one_control/rspec/matchers/perform_constant_number_of_queries"
8
+ require "n_plus_one_control/rspec/matchers/perform_linear_number_of_queries"
8
9
  require "n_plus_one_control/rspec/context"
9
10
 
10
11
  module NPlusOneControl
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NPlusOneControl
4
- VERSION = "0.4.1"
4
+ VERSION = "0.6.2"
5
5
  end
@@ -6,7 +6,7 @@ require "n_plus_one_control/executor"
6
6
  # RSpec and Minitest matchers to prevent N+1 queries problem.
7
7
  module NPlusOneControl
8
8
  # Used to extract a table name from a query
9
- EXTRACT_TABLE_RXP = /(insert into|update|delete from|from) ['"](\S+)['"]/i.freeze
9
+ EXTRACT_TABLE_RXP = /(insert into|update|delete from|from) ['"`](\S+)['"`]/i.freeze
10
10
 
11
11
  # Used to convert a query part extracted by the regexp above to the corresponding
12
12
  # human-friendly type
@@ -18,10 +18,18 @@ module NPlusOneControl
18
18
  }.freeze
19
19
 
20
20
  class << self
21
- attr_accessor :default_scale_factors, :verbose, :show_table_stats, :ignore, :event
21
+ attr_accessor :default_scale_factors, :verbose, :show_table_stats, :ignore, :event,
22
+ :backtrace_cleaner, :backtrace_length, :truncate_query_size
22
23
 
23
- def failure_message(queries) # rubocop:disable Metrics/MethodLength
24
- msg = ["Expected to make the same number of queries, but got:\n"]
24
+ attr_reader :default_matching
25
+
26
+ FAILURE_MESSAGES = {
27
+ constant_queries: "Expected to make the same number of queries",
28
+ linear_queries: "Expected to make linear number of queries"
29
+ }
30
+
31
+ def failure_message(type, queries) # rubocop:disable Metrics/MethodLength
32
+ msg = ["#{FAILURE_MESSAGES[type]}, but got:\n"]
25
33
  queries.each do |(scale, data)|
26
34
  msg << " #{data.size} for N=#{scale}\n"
27
35
  end
@@ -30,8 +38,8 @@ module NPlusOneControl
30
38
 
31
39
  if verbose
32
40
  queries.each do |(scale, data)|
33
- msg << " Queries for N=#{scale}\n"
34
- msg << data.map { |sql| " #{sql}\n" }.join.to_s
41
+ msg << "Queries for N=#{scale}\n"
42
+ msg << data.map { |sql| " #{truncate_query(sql)}\n" }.join.to_s
35
43
  end
36
44
  end
37
45
 
@@ -39,7 +47,7 @@ module NPlusOneControl
39
47
  end
40
48
 
41
49
  def table_usage_stats(runs) # rubocop:disable Metrics/MethodLength
42
- msg = ["\nUnmatched query numbers by tables:\n"]
50
+ msg = ["Unmatched query numbers by tables:\n"]
43
51
 
44
52
  before, after = runs.map do |queries|
45
53
  queries.group_by do |query|
@@ -58,6 +66,38 @@ module NPlusOneControl
58
66
 
59
67
  msg
60
68
  end
69
+
70
+ def default_matching=(val)
71
+ unless val
72
+ @default_matching = nil
73
+ return
74
+ end
75
+
76
+ @default_matching =
77
+ if val.is_a?(Regexp)
78
+ val
79
+ else
80
+ Regexp.new(val, Regexp::MULTILINE | Regexp::IGNORECASE)
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def truncate_query(sql)
87
+ return sql unless truncate_query_size
88
+
89
+ # Only truncate query, leave tracing (if any) as is
90
+ parts = sql.split(/(\s+↳)/)
91
+
92
+ parts[0] =
93
+ if truncate_query_size < 4
94
+ "..."
95
+ else
96
+ parts[0][0..(truncate_query_size - 4)] + "..."
97
+ end
98
+
99
+ parts.join
100
+ end
61
101
  end
62
102
 
63
103
  # Scale factors to use.
@@ -65,7 +105,7 @@ module NPlusOneControl
65
105
  self.default_scale_factors = [2, 3]
66
106
 
67
107
  # Print performed queries if true
68
- self.verbose = ENV['NPLUSONE_VERBOSE'] == '1'
108
+ self.verbose = ENV["NPLUSONE_VERBOSE"] == "1"
69
109
 
70
110
  # Print table hits difference
71
111
  self.show_table_stats = true
@@ -76,5 +116,16 @@ module NPlusOneControl
76
116
  # ActiveSupport notifications event to track queries.
77
117
  # We track ActiveRecord event by default,
78
118
  # but can also track rom-rb events ('sql.rom') as well.
79
- self.event = 'sql.active_record'
119
+ self.event = "sql.active_record"
120
+
121
+ # Default query filtering applied if none provided explicitly
122
+ self.default_matching = ENV["NPLUSONE_FILTER"] || /^SELECT/i
123
+
124
+ # Truncate queries in verbose mode to fit the length
125
+ self.truncate_query_size = ENV["NPLUSONE_TRUNCATE"]&.to_i
126
+
127
+ # Define the number of backtrace lines to show
128
+ self.backtrace_length = ENV.fetch("NPLUSONE_BACKTRACE", 1).to_i
80
129
  end
130
+
131
+ require "n_plus_one_control/railtie" if defined?(Rails::Railtie)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: n_plus_one_control
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - palkan
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-04 00:00:00.000000000 Z
11
+ date: 2021-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,62 +80,6 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 4.8.0
83
- - !ruby/object:Gem::Dependency
84
- name: rubocop
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 0.61.0
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 0.61.0
97
- - !ruby/object:Gem::Dependency
98
- name: activerecord
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '5.1'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '5.1'
111
- - !ruby/object:Gem::Dependency
112
- name: sqlite3
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: 1.3.6
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: 1.3.6
125
- - !ruby/object:Gem::Dependency
126
- name: pry-byebug
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
83
  description: "\n RSpec and Minitest matchers to prevent N+1 queries problem.\n\n
140
84
  \ Evaluates code under consideration several times with different scale factors\n
141
85
  \ to make sure that the number of DB queries behaves as expected (i.e. O(1) instead
@@ -152,10 +96,12 @@ files:
152
96
  - lib/n_plus_one_control.rb
153
97
  - lib/n_plus_one_control/executor.rb
154
98
  - lib/n_plus_one_control/minitest.rb
99
+ - lib/n_plus_one_control/railtie.rb
155
100
  - lib/n_plus_one_control/rspec.rb
156
101
  - lib/n_plus_one_control/rspec/context.rb
157
102
  - lib/n_plus_one_control/rspec/dsl.rb
158
- - lib/n_plus_one_control/rspec/matcher.rb
103
+ - lib/n_plus_one_control/rspec/matchers/perform_constant_number_of_queries.rb
104
+ - lib/n_plus_one_control/rspec/matchers/perform_linear_number_of_queries.rb
159
105
  - lib/n_plus_one_control/version.rb
160
106
  homepage: http://github.com/palkan/n_plus_one_control
161
107
  licenses:
@@ -166,7 +112,7 @@ metadata:
166
112
  documentation_uri: http://github.com/palkan/n_plus_one_control
167
113
  homepage_uri: http://github.com/palkan/n_plus_one_control
168
114
  source_code_uri: http://github.com/palkan/n_plus_one_control
169
- post_install_message:
115
+ post_install_message:
170
116
  rdoc_options: []
171
117
  require_paths:
172
118
  - lib
@@ -174,15 +120,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
174
120
  requirements:
175
121
  - - ">="
176
122
  - !ruby/object:Gem::Version
177
- version: 2.0.0
123
+ version: 2.5.0
178
124
  required_rubygems_version: !ruby/object:Gem::Requirement
179
125
  requirements:
180
126
  - - ">="
181
127
  - !ruby/object:Gem::Version
182
128
  version: '0'
183
129
  requirements: []
184
- rubygems_version: 3.0.6
185
- signing_key:
130
+ rubygems_version: 3.0.3
131
+ signing_key:
186
132
  specification_version: 4
187
133
  summary: RSpec and Minitest matchers to prevent N+1 queries problem
188
134
  test_files: []