ar-query-matchers 0.3.0 → 0.5.2.pre.6

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: 60c088b5a136a27e7cda68a413f8a46005c82f63ff30bb22eaadf70995390755
4
- data.tar.gz: 2be1beb74c5716601305bd6771fb2f9ba8058879a609dcb4198c640a1a5f7cd9
3
+ metadata.gz: a03e79681fb7644c916a5f3c019a5e9484f8b7176e21b6c91beae9bd2d9eb520
4
+ data.tar.gz: 1a1d6f97aab26efa604ae32dd2d4b56164e4616ff87b2ffbfb84812e87e57a75
5
5
  SHA512:
6
- metadata.gz: 24c9812af618e31c66520d52d79e6a7bf0b6695c8e99323136877061bcac6045f795bc4655af35d9aeca49bd2ed129b0227bc717544e4c5007df1493fb9fa65c
7
- data.tar.gz: c6905a488bde5a20cd45cb636d59d9c0dcf2b459cbafda156da918a0fa4a71866b60ee014ede6ec242539ced60f6915ccbecb56848b411bda97ca8d6eb0b4a5f
6
+ metadata.gz: 960fb79a70f3875f606d67364227ad6b0af6440b18fed4e885a8a44614d61f484ad7cdc33e6040b114b568d320edcc045a212a9db0c570577a039bb7a04b09c6
7
+ data.tar.gz: 379ef8320c724772bcf9fc38dda46a86fa8a24a8690a9547a13973065dcebef9fae17f77a636e059463f91afbba2aa341164ddadbe900e58fb625d3f1b64a5c4
data/CHANGELOG.md CHANGED
@@ -5,8 +5,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
- ## [0.3.0] - 2020-03-13
9
8
 
9
+ ## [0.5.2] - 2021-05-18
10
+ ### Changed
11
+ - Removes 'SELECT' from MODEL_SQL_PATTERN to allow for more granular SQL statement matching
12
+
13
+ ## [0.5.1] - 2020-11-19
14
+ ### Changed
15
+ - Removes zero count expectations from hash before comparing
16
+
17
+ ## [0.5.0] - 2020-07-23
18
+ ### Changed
19
+ - Add time information to query counter
20
+
21
+ ## [0.4.0] - 2020-07-20
22
+ ### Changed
23
+ - Upgrade the Rails dependency to allow for Rails 6.1
24
+
25
+ ## [0.3.0] - 2020-03-13
26
+ ### Changed
10
27
  - Correct the Rails dependency to allow for Rails 6.0
11
28
 
12
29
  ## [0.2.0] - 2019-09-15
@@ -18,6 +35,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
18
35
  ### Added
19
36
  - First versions as a public ruby gem.
20
37
 
21
- [Unreleased]: https://github.com/gusto/ar-query-matchers/compare/v0.2.0...HEAD
38
+ [Unreleased]: https://github.com/gusto/ar-query-matchers/compare/v0.5.1...HEAD
39
+ [0.5.1]: https://github.com/gusto/ar-query-matchers/releases/tag/v0.5.1
40
+ [0.5.0]: https://github.com/gusto/ar-query-matchers/releases/tag/v0.5.0
41
+ [0.4.0]: https://github.com/gusto/ar-query-matchers/releases/tag/v0.4.0
42
+ [0.3.0]: https://github.com/gusto/ar-query-matchers/releases/tag/v0.3.0
22
43
  [0.2.0]: https://github.com/gusto/ar-query-matchers/releases/tag/v0.2.0
23
44
  [0.1.0]: https://github.com/gusto/ar-query-matchers/releases/tag/v0.1.0
@@ -3,9 +3,16 @@
3
3
  require 'ar_query_matchers/queries/create_counter'
4
4
  require 'ar_query_matchers/queries/load_counter'
5
5
  require 'ar_query_matchers/queries/update_counter'
6
+ require 'bigdecimal'
6
7
 
7
8
  module ArQueryMatchers
8
9
  module ArQueryMatchers
10
+ class Utility
11
+ def self.remove_superfluous_expectations(expected)
12
+ expected.select { |_, v| v.positive? }
13
+ end
14
+ end
15
+
9
16
  module CreateModels
10
17
  # The following will succeed:
11
18
  # expect {
@@ -22,7 +29,7 @@ module ArQueryMatchers
22
29
 
23
30
  match do |block|
24
31
  @query_stats = Queries::CreateCounter.instrument(&block)
25
- expected == @query_stats.query_counts
32
+ Utility.remove_superfluous_expectations(expected) == @query_stats.query_counts
26
33
  end
27
34
 
28
35
  def failure_text
@@ -82,7 +89,7 @@ module ArQueryMatchers
82
89
 
83
90
  match do |block|
84
91
  @query_stats = Queries::LoadCounter.instrument(&block)
85
- expected == @query_stats.query_counts
92
+ Utility.remove_superfluous_expectations(expected) == @query_stats.query_counts
86
93
  end
87
94
 
88
95
  def failure_text
@@ -146,7 +153,7 @@ module ArQueryMatchers
146
153
 
147
154
  match do |block|
148
155
  @query_stats = Queries::UpdateCounter.instrument(&block)
149
- expected == @query_stats.query_counts
156
+ Utility.remove_superfluous_expectations(expected) == @query_stats.query_counts
150
157
  end
151
158
 
152
159
  def failure_text
@@ -23,7 +23,7 @@ module ArQueryMatchers
23
23
  # for inserts, name is always 'SQL', we have to rely on pattern matching the query string.
24
24
  select_from_table = sql.match(TABLE_NAME_SQL_PATTERN)
25
25
 
26
- TableName.new(select_from_table[:table_name]) if select_from_table
26
+ [TableName.new(select_from_table[:table_name])] if select_from_table
27
27
  end
28
28
  end
29
29
  end
@@ -15,24 +15,15 @@ module ArQueryMatchers
15
15
  end
16
16
 
17
17
  class LoadQueryFilter < Queries::QueryFilter
18
- # Matches named SQL operations like the following:
19
- # 'User Load'
20
- MODEL_LOAD_PATTERN = /\A(?<model_name>[\w:]+) (Load|Exists)\Z/.freeze
21
-
22
18
  # Matches unnamed SQL operations like the following:
23
- # "SELECT COUNT(*) FROM `users` ..."
24
- MODEL_SQL_PATTERN = /SELECT .* FROM [`"](?<table_name>[^`"]+)[`"]/.freeze
25
-
26
- def filter_map(name, sql)
27
- # First check for a `SELECT * FROM` query that ActiveRecord has
28
- # helpfully named for us in the payload
29
- match = name.match(MODEL_LOAD_PATTERN)
30
- return ModelName.new(match[:model_name]) if match
19
+ # "SELECT * FROM `users` ..."
20
+ MODEL_SQL_PATTERN = /SELECT (?:(?!SELECT).)* FROM [`"](?<table_name>[^`"]+)[`"]/.freeze
31
21
 
32
- # Fall back to pattern-matching on the table name in a COUNT and looking
22
+ def filter_map(_name, sql)
23
+ # Pattern-matching on the table name in a SELECT ... FROM and looking
33
24
  # up the table name from ActiveRecord's loaded descendants.
34
- select_from_table = sql.match(MODEL_SQL_PATTERN)
35
- TableName.new(select_from_table[:table_name]) if select_from_table
25
+ selects_from_table = sql.scan(MODEL_SQL_PATTERN)
26
+ selects_from_table.map { |(table_name)| TableName.new(table_name) } unless selects_from_table.empty?
36
27
  end
37
28
  end
38
29
  end
@@ -62,7 +62,7 @@ module ArQueryMatchers
62
62
  # @param [block] block to instrument
63
63
  # @return [QueryStats] stats about all the SQL queries executed during the block
64
64
  def instrument(&block)
65
- queries = Hash.new { |h, k| h[k] = { count: 0, lines: [] } }
65
+ queries = Hash.new { |h, k| h[k] = { count: 0, lines: [], time: BigDecimal(0) } }
66
66
  ActiveSupport::Notifications.subscribed(to_proc(queries), 'sql.active_record', &block)
67
67
  QueryStats.new(queries)
68
68
  end
@@ -75,18 +75,23 @@ module ArQueryMatchers
75
75
  private_constant :MARGINALIA_SQL_COMMENT_PATTERN
76
76
 
77
77
  def to_proc(queries)
78
- lambda do |_name, _start, _finish, _message_id, payload|
78
+ lambda do |_name, start, finish, _message_id, payload|
79
79
  return if payload[:cached]
80
80
 
81
81
  # Given a `sql.active_record` event, figure out which model is being
82
- # accessed. Some of the simpler queries have a :ame key that makes this
82
+ # accessed. Some of the simpler queries have a :name key that makes this
83
83
  # really easy. Others require parsing the SQL by hand.
84
- model_name = @query_filter.filter_map(payload[:name] || '', payload[:sql] || '')&.model_name
84
+ results = @query_filter.filter_map(payload[:name] || '', payload[:sql] || '')
85
+
86
+ # Round to microseconds
87
+ results&.each do |result|
88
+ model_name = result.model_name
89
+ next unless model_name
85
90
 
86
- if model_name
87
91
  comment = payload[:sql].match(MARGINALIA_SQL_COMMENT_PATTERN)
88
92
  queries[model_name][:lines] << comment[:line] if comment
89
93
  queries[model_name][:count] += 1
94
+ queries[model_name][:time] += (finish - start).round(6) # Round to microseconds
90
95
  end
91
96
  end
92
97
  end
@@ -22,7 +22,7 @@ module ArQueryMatchers
22
22
  def filter_map(_name, sql)
23
23
  # for updates, name is always 'SQL', we have to rely on pattern matching on the query string instead.
24
24
  select_from_table = sql.match(TABLE_NAME_SQL_PATTERN)
25
- TableName.new(select_from_table[:table_name]) if select_from_table
25
+ [TableName.new(select_from_table[:table_name])] if select_from_table
26
26
  end
27
27
  end
28
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar-query-matchers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.2.pre.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matan Zruya
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-13 00:00:00.000000000 Z
11
+ date: 2021-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '4.0'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '6.1'
22
+ version: '7.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '4.0'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '6.1'
32
+ version: '7.0'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: activesupport
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -39,7 +39,7 @@ dependencies:
39
39
  version: '4.0'
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: '6.1'
42
+ version: '7.0'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -49,7 +49,7 @@ dependencies:
49
49
  version: '4.0'
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: '6.1'
52
+ version: '7.0'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: rspec
55
55
  requirement: !ruby/object:Gem::Requirement
@@ -186,11 +186,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
186
186
  version: '0'
187
187
  required_rubygems_version: !ruby/object:Gem::Requirement
188
188
  requirements:
189
- - - ">="
189
+ - - ">"
190
190
  - !ruby/object:Gem::Version
191
- version: '0'
191
+ version: 1.3.1
192
192
  requirements: []
193
- rubygems_version: 3.0.3
193
+ rubygems_version: 3.0.3.1
194
194
  signing_key:
195
195
  specification_version: 4
196
196
  summary: Ruby test matchers for instrumenting ActiveRecord query counts