n_one 1.0.1 → 1.0.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: d037a52ad1770b38646937c04fdf274fac7dfdbf5d8351eb5208e0899d4d8927
4
- data.tar.gz: eafb63f23fca359806b398c41480bad4225a46a1806dcbf05d50d88ca8fec197
3
+ metadata.gz: 6ed8520fefb3a0e04185dc4a7f234ec3f9d65d110223dfd52b568d9f1f8d9080
4
+ data.tar.gz: 1164c40f76713cab191569ff896d4309c8938194737ed31cd21897bcc10027d9
5
5
  SHA512:
6
- metadata.gz: 1e18c871f74065f1fac610a11a70717a6bd91caf447062627d91b847602300ac76abae5b7a5200d57dd65ad223f2da6fe6554ff7f0ae97df07710c609d9591e8
7
- data.tar.gz: 4b933072d3e7e62f6abfac60ea794d64049457c756497614ce2f84eb77687d008786e901bdfb1139f5b47a5b49ed9acddafd7cf036e80a6e9620d977bee45a95
6
+ metadata.gz: 98c9dedda0ec0540d55443c678c399dd1bb5bf5b3ee007769b85b6d276aa13bcf14096aa0a8ab310ddedb824df7cd0289a88f0bd952e3f6dd4e707ca0da0ce97
7
+ data.tar.gz: 19da0020d67ef61418399ecfe266c063822d63fcb3912832bc57c135b5df6739aea5d4583927f90e89ecbc557d352cc1bfa99777efdc1cd4ecf6d9983c6a4715
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- n_one (1.0.1)
4
+ n_one (1.0.2)
5
5
  pg_query
6
6
 
7
7
  GEM
@@ -23,8 +23,8 @@ GEM
23
23
  concurrent-ruby (1.1.8)
24
24
  factory_bot (6.1.0)
25
25
  activesupport (>= 5.0.0)
26
- google-protobuf (3.19.1)
27
- google-protobuf (3.19.1-x86_64-linux)
26
+ google-protobuf (3.19.4)
27
+ google-protobuf (3.19.4-x86_64-linux)
28
28
  i18n (1.8.9)
29
29
  concurrent-ruby (~> 1.0)
30
30
  method_source (1.0.0)
@@ -32,8 +32,8 @@ GEM
32
32
  parallel (1.20.1)
33
33
  parser (3.0.1.0)
34
34
  ast (~> 2.4.1)
35
- pg_query (2.1.2)
36
- google-protobuf (>= 3.17.1)
35
+ pg_query (2.1.3)
36
+ google-protobuf (>= 3.19.2)
37
37
  pry (0.14.0)
38
38
  coderay (~> 1.1)
39
39
  method_source (~> 1.0)
data/README.md CHANGED
@@ -74,9 +74,9 @@ end
74
74
  Ignore notifications for call stacks containing one or more substrings:
75
75
 
76
76
  ```ruby
77
- NOne.scan!(whitelist: ['myapp/lib/known_n_plus_ones/']) do
78
- example.run
79
- end
77
+ NOne.scan!(whitelist: ['myapp/lib/known_n_plus_ones/']) do
78
+ example.run
79
+ end
80
80
  ```
81
81
 
82
82
  ## Ignore names
@@ -84,13 +84,42 @@ Ignore notifications for call stacks containing one or more substrings:
84
84
  Ignore queries with names:
85
85
 
86
86
  ```ruby
87
- NOne.scan!(ignore_names: ['SCHEMA']) do
88
- example.run
89
- end
87
+ NOne.scan!(ignore_names: ['SCHEMA']) do
88
+ example.run
89
+ end
90
90
  ```
91
91
 
92
92
  It will skip schema queries(e.g. for column names of a given table)
93
93
 
94
+ ## Stack trace sanitizing
95
+
96
+ Sanitize the call stack trace that is used to calculate the query fingerprint:
97
+
98
+ ```ruby
99
+ sanitizer = lambda do |stacktrace|
100
+ stacktrace.reject { |s| s.include?('/active_record/relation/delegation.rb') }
101
+ end
102
+
103
+ NOne.scan!(stacktrace_sanitizer: sanitizer) do
104
+ example.run
105
+ end
106
+ ```
107
+
108
+ Consider the following example:
109
+
110
+ ```ruby
111
+ class Foo < ActiveRecord::Base
112
+ def self.bar
113
+ first(5)
114
+ end
115
+ end
116
+
117
+ 2.times { Foo.all.bar }
118
+ ```
119
+
120
+ The subsequent `Foo.all.bar` call here will not be recognized as an N+1 query since it will have a different call stack trace (see the reason [here](https://github.com/rails/rails/blob/9a400d808bdbebd5ea50cebc79bde591d2669017/activerecord/lib/active_record/relation/delegation.rb#L82-L85)).
121
+ This can be fixed with the `stacktrace_sanitizer` option as described above.
122
+
94
123
  ## Contributing
95
124
 
96
125
  Bug reports and pull requests are welcome on GitHub at https://github.com/prikha/n_one.
data/lib/n_one/runner.rb CHANGED
@@ -6,10 +6,13 @@ module NOne
6
6
  #
7
7
  # @param whitelist [<String>] frame substrings to be ignored
8
8
  # @param ignore_names [<String>] query names to be ignored
9
+ # @param stacktrace_sanitizer [Proc<Array<String>>] if given, used to filter the stack trace
10
+ # that is used to calculate the location key
9
11
  #
10
- def initialize(whitelist: [], ignore_names: [])
12
+ def initialize(whitelist: [], ignore_names: [], stacktrace_sanitizer: nil)
11
13
  @whitelist = ['active_record/validations/uniqueness'] + whitelist
12
14
  @ignore_names = ignore_names
15
+ @stacktrace_sanitizer = stacktrace_sanitizer
13
16
  end
14
17
 
15
18
  def scan(&block)
@@ -51,7 +54,7 @@ module NOne
51
54
  end.compact
52
55
  end
53
56
 
54
- def record_sql(&block) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
57
+ def record_sql(&block) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
55
58
  subscriber = ActiveSupport::Notifications.subscribe 'sql.active_record' do |_, _, _, _, data|
56
59
  sql = data[:sql]
57
60
  cached = data[:cached]
@@ -62,7 +65,9 @@ module NOne
62
65
  sql_fingerprint = Query.fingerprint(sql)
63
66
  next unless sql_fingerprint
64
67
 
65
- location_key = Digest::SHA1.hexdigest(caller.join)
68
+ stacktrace = caller
69
+ stacktrace = @stacktrace_sanitizer.call(stacktrace) if @stacktrace_sanitizer
70
+ location_key = Digest::SHA1.hexdigest(stacktrace.join)
66
71
 
67
72
  store["#{sql_fingerprint}_#{location_key}"] ||= {
68
73
  count: 0,
@@ -73,7 +78,7 @@ module NOne
73
78
  store["#{sql_fingerprint}_#{location_key}"][:count] += 1
74
79
  store["#{sql_fingerprint}_#{location_key}"][:sql] << sql
75
80
  store["#{sql_fingerprint}_#{location_key}"][:sql].uniq!
76
- store["#{sql_fingerprint}_#{location_key}"][:caller] ||= caller.dup
81
+ store["#{sql_fingerprint}_#{location_key}"][:caller] ||= stacktrace
77
82
  end
78
83
 
79
84
  block.call
data/lib/n_one/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NOne
4
- VERSION = '1.0.1'
4
+ VERSION = '1.0.2'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: n_one
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergey Prikhodko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-24 00:00:00.000000000 Z
11
+ date: 2022-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg_query