rspec-activerecord-expectations 1.1.0 → 2.1.1
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 +4 -4
- data/.github/workflows/main.yml +41 -12
- data/CHANGELOG.md +28 -4
- data/README.md +81 -19
- data/lib/rspec/activerecord/expectations/collector.rb +25 -6
- data/lib/rspec/activerecord/expectations/matchers/load_matcher.rb +29 -0
- data/lib/rspec/activerecord/expectations/matchers/{query_count.rb → query_count_matcher.rb} +47 -13
- data/lib/rspec/activerecord/expectations/query_inspector.rb +28 -0
- data/lib/rspec/activerecord/expectations.rb +7 -1
- data/rspec-activerecord-expectations.gemspec +8 -3
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6e24b218adcab0f1e6fb117d66463a2cdf60996fe5c16f60d48f8efd37c3259
|
4
|
+
data.tar.gz: 4f0acb5f4c489f4b2ded11b7d27a1bec613d231b04d836f651a26daf1bdb5bb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d077a6aa43e9f243a4be0d5b4db338a2aa3272e49974b8cc9b987499571de846e6f5cbc4c9d1f4d3d58d50b1d91ce3d361f2719ee3073ae8eeeee589a62d3e8c
|
7
|
+
data.tar.gz: 4473b4f016d10ca617e4ef5b3b1550c44903a170e9fde1291a88097a264028a0e21383fa37324f063c9529412c52e70e6fb24fab9e7a6df2382568f6a763fbc5
|
data/.github/workflows/main.yml
CHANGED
@@ -11,22 +11,22 @@ jobs:
|
|
11
11
|
strategy:
|
12
12
|
matrix:
|
13
13
|
os: [ubuntu-latest, macos-latest]
|
14
|
-
|
14
|
+
ruby-version: ['3.1', '3.0', '2.7']
|
15
15
|
rails: ['5.0', '5.1', '5.2', '6.0', '6.1', '7.0']
|
16
16
|
|
17
17
|
runs-on: ${{ matrix.os }}
|
18
|
-
name:
|
18
|
+
name: ruby ${{ matrix.ruby-version }}, rails ${{ matrix.rails }}, ${{ matrix.os }}
|
19
19
|
|
20
20
|
steps:
|
21
21
|
- uses: actions/checkout@v2
|
22
22
|
|
23
|
-
- name: Set up Ruby ${{ matrix.
|
23
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
24
24
|
uses: ruby/setup-ruby@v1
|
25
25
|
with:
|
26
|
-
|
26
|
+
ruby-version: ${{ matrix.ruby-version }}
|
27
27
|
bundler-cache: true
|
28
28
|
|
29
|
-
- name: Install
|
29
|
+
- name: Install Gems w/ Rails ${{ matrix.rails }}
|
30
30
|
env:
|
31
31
|
MATRIX_RAILS_VERSION: ${{ matrix.rails }}
|
32
32
|
run: |
|
@@ -40,23 +40,51 @@ jobs:
|
|
40
40
|
test_legacy:
|
41
41
|
strategy:
|
42
42
|
matrix:
|
43
|
-
|
44
|
-
ruby_version: ['2.6', '2.5', '2.4', '2.3']
|
43
|
+
ruby-version: ['2.6', '2.5']
|
45
44
|
rails: ['5.0', '5.1', '5.2']
|
46
45
|
|
47
|
-
runs-on:
|
48
|
-
name:
|
46
|
+
runs-on: ubuntu-latest
|
47
|
+
name: ruby ${{ matrix.ruby-version }}, rails ${{ matrix.rails }}
|
48
|
+
|
49
|
+
steps:
|
50
|
+
- uses: actions/checkout@v2
|
51
|
+
|
52
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
53
|
+
uses: ruby/setup-ruby@v1
|
54
|
+
with:
|
55
|
+
ruby-version: ${{ matrix.ruby-version }}
|
56
|
+
bundler-cache: true
|
57
|
+
|
58
|
+
- name: Install Gems w/ Rails ${{ matrix.rails }}
|
59
|
+
env:
|
60
|
+
MATRIX_RAILS_VERSION: ${{ matrix.rails }}
|
61
|
+
run: |
|
62
|
+
export BUNDLE_GEMFILE="${GITHUB_WORKSPACE}/gemfiles/rails_${MATRIX_RAILS_VERSION}.gemfile"
|
63
|
+
gem install bundler
|
64
|
+
bundle install --jobs 4 --retry 3
|
65
|
+
|
66
|
+
- name: Run tests
|
67
|
+
run: bundle exec rspec
|
68
|
+
|
69
|
+
test_alt_rubies:
|
70
|
+
strategy:
|
71
|
+
matrix:
|
72
|
+
ruby-version: ['jruby', 'truffleruby']
|
73
|
+
rails: ['6.0', '6.1'] # jruby / jdbc-sqlite3 end up tightly bound to rails 6.x
|
74
|
+
|
75
|
+
runs-on: ubuntu-latest
|
76
|
+
name: ${{ matrix.ruby-version }}, rails ${{ matrix.rails }}
|
49
77
|
|
50
78
|
steps:
|
51
79
|
- uses: actions/checkout@v2
|
52
80
|
|
53
|
-
- name: Set up Ruby ${{ matrix.
|
81
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
54
82
|
uses: ruby/setup-ruby@v1
|
55
83
|
with:
|
56
|
-
|
84
|
+
ruby-version: ${{ matrix.ruby-version }}
|
57
85
|
bundler-cache: true
|
58
86
|
|
59
|
-
- name: Install
|
87
|
+
- name: Install Gems w/ Rails ${{ matrix.rails }}
|
60
88
|
env:
|
61
89
|
MATRIX_RAILS_VERSION: ${{ matrix.rails }}
|
62
90
|
run: |
|
@@ -66,3 +94,4 @@ jobs:
|
|
66
94
|
|
67
95
|
- name: Run tests
|
68
96
|
run: bundle exec rspec
|
97
|
+
|
data/CHANGELOG.md
CHANGED
@@ -1,13 +1,37 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## [1.1
|
4
|
-
-
|
3
|
+
## [2.1.1] - 2022-01-12
|
4
|
+
- Gemspec is really generated using the version of ruby that's locally in use.
|
5
|
+
Update that build artifact to use non-java dependencies.
|
5
6
|
|
6
|
-
## [1.0
|
7
|
+
## [2.1.0] - 2022-01-12
|
8
|
+
- Change CI matrix for more version compatibility
|
9
|
+
- Update gemspec to move some deps into development only
|
10
|
+
- README changes
|
11
|
+
|
12
|
+
## [2.0.0] - 2022-01-07
|
13
|
+
- Require much more recent ruby, to use syntax that's been around since 2017
|
14
|
+
|
15
|
+
## [1.3.0] - 2021-12-31
|
16
|
+
- Add `repeatedly_load` matcher
|
17
|
+
- Add query type matchers for `load_queries`, `schema_queries`, `transaction_queries`, `destroy_queries`
|
18
|
+
- Allow singular version of all query types (e.g. `transaction_queries` vs `transaction_query`)
|
19
|
+
- Fix failure message for `execute.exactly` matcher
|
20
|
+
|
21
|
+
## [1.2.0] - 2021-12-31
|
22
|
+
- Add `query` as a synonym for `queries`
|
23
|
+
- Ignore schema and transaction queries in query count
|
24
|
+
- Add beginning of recording specific query types
|
25
|
+
- Add query count matcher for `exactly`
|
26
|
+
|
27
|
+
## [1.1.0] - 2021-12-30
|
28
|
+
- Add query count matchers for e.g. `less_than_or_equal_to`, `greater_than`
|
29
|
+
|
30
|
+
## [1.0.1] - 2021-12-30
|
7
31
|
- Pin all the dependencies to a proper working subset
|
8
32
|
- Expand testing to many rails / ruby combinations
|
9
33
|
|
10
|
-
## [1.0.0] -
|
34
|
+
## [1.0.0] - 2021-12-30
|
11
35
|
- Basic gem w/ all the fixins and README and such
|
12
36
|
- Add `less_than` comparison, and `queries` type
|
13
37
|
- Basic tests in place, and not bad tbh
|
data/README.md
CHANGED
@@ -30,7 +30,8 @@ group 'test' do
|
|
30
30
|
end
|
31
31
|
```
|
32
32
|
|
33
|
-
Then, include the functionality within your
|
33
|
+
Then, include the functionality within your `rails_helper.rb` (or in a support
|
34
|
+
file).
|
34
35
|
|
35
36
|
```ruby
|
36
37
|
RSpec.configure do |config|
|
@@ -91,9 +92,52 @@ That's it! Refactor your report to be more efficient and then leave the test in
|
|
91
92
|
place to make sure that future developers don't accidentally cause a
|
92
93
|
performance regression.
|
93
94
|
|
94
|
-
##
|
95
|
+
## Preventing Repeated Load (N+1) Queries
|
95
96
|
|
96
|
-
|
97
|
+
Reloading, whether by e.g. `Album.find` or `album.tracks` are both antipatterns
|
98
|
+
within your code. They will load from the database for every iteration in a
|
99
|
+
loop, unless you load records outside the loop, cache responses, or use an
|
100
|
+
eager loading mechanism like `includes`. These sorts of queries are often
|
101
|
+
referred to as N+1 queries.
|
102
|
+
|
103
|
+
This sort of query can be prevented using the `repeatedly_load` expectation.
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
expect {}.not_to repeatedly_load('SomeActiveRecordClass')
|
107
|
+
```
|
108
|
+
|
109
|
+
This matcher will track ActiveRecord's built in load methods to prevent those
|
110
|
+
N+1 situations. Using eager loading (e.g. `Track.all.includes(:album)`) will
|
111
|
+
allow these expectations to pass as expected!
|
112
|
+
|
113
|
+
### Testing Batch Queries
|
114
|
+
|
115
|
+
If your code loads records in batches, it may be more difficult to create
|
116
|
+
expectations for repeated loading. After all, each batch will execute its own
|
117
|
+
queries, which may look like repeated loading.
|
118
|
+
|
119
|
+
If your test has a small enough number of records that only one batch is
|
120
|
+
loaded, your tests may work just fine. But otherwise, you may want to allow
|
121
|
+
your code to specify a batch size in order to guarantee only a single batch
|
122
|
+
is loaded.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
tracks = Track.all
|
126
|
+
|
127
|
+
expect {
|
128
|
+
TrackSerializer.perform(tracks, batch_size: tracks.count)
|
129
|
+
}.not_to repeatedly_load('Track')
|
130
|
+
```
|
131
|
+
|
132
|
+
## Counting Queries
|
133
|
+
|
134
|
+
Some services won't necessarily have N+1 issues with records loading, but might
|
135
|
+
still have problems with executing too many queries. In this case, the
|
136
|
+
`repeatedly_load` matcher might be insufficient.
|
137
|
+
|
138
|
+
In this case, consider creating an expectation on the total number of queries
|
139
|
+
executed by your code. Several comparison types are available, along with some
|
140
|
+
aliases to allow for easier to read tests.
|
97
141
|
|
98
142
|
```ruby
|
99
143
|
expect {}.to execute.less_than(20).queries
|
@@ -107,22 +151,47 @@ expect {}.to execute.more_than(20).queries
|
|
107
151
|
|
108
152
|
expect {}.to execute.greater_than_or_equal_to(20).queries
|
109
153
|
expect {}.to execute.at_least(20).queries
|
154
|
+
|
155
|
+
expect {}.to execute.exactly(20).queries
|
156
|
+
|
157
|
+
expect {}.to execute.at_least(2).queries
|
158
|
+
expect {}.to execute.at_least(1).query # singular form also accepted
|
110
159
|
```
|
111
160
|
|
161
|
+
### Specific Query Types
|
162
|
+
|
163
|
+
You can make assertions for the total number of queries executed, but sometimes
|
164
|
+
it's more valuable to assert that a particular _type_ of query was executed.
|
165
|
+
For example, a particular number of queries to destroy records. There are
|
166
|
+
matchers available for that purpose as well!
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
expect {}.to execute.exactly(20).queries
|
170
|
+
|
171
|
+
expect {}.to execute.exactly(20).insert_queries
|
172
|
+
expect {}.to execute.exactly(20).load_queries
|
173
|
+
expect {}.to execute.exactly(20).destroy_queries
|
174
|
+
expect {}.to execute.exactly(20).exists_queries
|
175
|
+
|
176
|
+
expect {}.to execute.exactly(20).schema_queries
|
177
|
+
expect {}.to execute.exactly(20).transaction_queries
|
178
|
+
```
|
179
|
+
|
180
|
+
**Note:** Transaction (for example, `ROLLBACK`) queries are not counted in any of these
|
181
|
+
categories, nor are queries that load the DB schema.
|
182
|
+
|
183
|
+
**Note:** Destroy and delete queries are both condensed into the matcher for
|
184
|
+
`destroy_queries`.
|
185
|
+
|
112
186
|
## Future Planned Functionality
|
113
187
|
|
114
188
|
This gem still has lots of future functionality. See below.
|
115
189
|
|
116
190
|
```ruby
|
117
|
-
expect {}.to execute.
|
191
|
+
expect {}.to execute.at_least(2).queries_of_type("Audited::Audit Load")
|
192
|
+
expect {}.to execute.at_least(2).load_queries("Audited::Audit")
|
118
193
|
|
119
194
|
expect {}.to execute.at_least(2).activerecord_queries
|
120
|
-
expect {}.to execute.at_least(2).insert_queries
|
121
|
-
expect {}.to execute.at_least(2).delete_queries
|
122
|
-
expect {}.to execute.at_least(2).load_queries
|
123
|
-
expect {}.to execute.at_least(2).schema_queries
|
124
|
-
expect {}.to execute.at_least(2).exists_queries
|
125
|
-
expect {}.to execute.at_least(2).queries_of_type("Audited::Audit Load")
|
126
195
|
expect {}.to execute.at_least(2).hand_rolled_queries
|
127
196
|
|
128
197
|
expect {}.not_to rollback_transaction.exactly(5).times
|
@@ -133,17 +202,10 @@ expect {}.to create.exactly(5).of_type(User)
|
|
133
202
|
expect {}.to insert.exactly(5).subscription_changes
|
134
203
|
expect {}.to update.exactly(2).of_any_type
|
135
204
|
expect {}.to delete.exactly(2).of_any_type
|
136
|
-
|
137
|
-
expect {}.not_to repeatedly_load(Audited::Audit)
|
138
|
-
|
139
|
-
expect {}.to execute.at_least(1).query
|
140
205
|
```
|
141
206
|
|
142
|
-
-
|
143
|
-
-
|
144
|
-
- differentiate AR queries from generic ones? arbitrary execution somehow?
|
145
|
-
- warn about warmup
|
146
|
-
- make sure we don't smite any built in methods (or from other libs)
|
207
|
+
- warn if we smite any built in methods (or methods from other libs)
|
208
|
+
- support Rails 6 bulk insert (still one query)
|
147
209
|
|
148
210
|
## Development
|
149
211
|
|
@@ -1,23 +1,42 @@
|
|
1
1
|
module RSpec::ActiveRecord::Expectations
|
2
2
|
class Collector
|
3
3
|
def initialize
|
4
|
-
@
|
5
|
-
|
6
|
-
}
|
4
|
+
@inspector = QueryInspector.new
|
5
|
+
@by_name = {}
|
6
|
+
@counts = QueryInspector.valid_query_types.each_with_object({}) do |query_type, hash|
|
7
|
+
hash[query_type] = 0
|
8
|
+
end
|
7
9
|
|
8
|
-
ActiveSupport::Notifications.subscribe("sql.active_record", method(:record_query))
|
10
|
+
@subscription = ActiveSupport::Notifications.subscribe("sql.active_record", method(:record_query))
|
11
|
+
end
|
12
|
+
|
13
|
+
def finalize
|
14
|
+
ActiveSupport::Notifications.unsubscribe(@subscription)
|
9
15
|
end
|
10
16
|
|
11
17
|
def queries_of_type(type)
|
12
|
-
@counts
|
18
|
+
@counts[type] || (raise ArgumentError, "Sorry, #{type} is not a valid kind of query")
|
13
19
|
end
|
14
20
|
|
15
21
|
def valid_type?(type)
|
16
22
|
@counts.include? type
|
17
23
|
end
|
18
24
|
|
25
|
+
def calls_by_name(name)
|
26
|
+
@by_name.fetch(name, 0)
|
27
|
+
end
|
28
|
+
|
19
29
|
def record_query(*_unused, data)
|
20
|
-
|
30
|
+
categories = @inspector.categorize(data)
|
31
|
+
|
32
|
+
categories.each do |category|
|
33
|
+
@counts[category] += 1
|
34
|
+
rescue NoMethodError
|
35
|
+
raise "tried to add to to #{category} but it doesn't exist"
|
36
|
+
end
|
37
|
+
|
38
|
+
@by_name[data[:name]] ||= 0
|
39
|
+
@by_name[data[:name]] += 1
|
21
40
|
end
|
22
41
|
end
|
23
42
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RSpec::ActiveRecord::Expectations
|
2
|
+
module Matchers
|
3
|
+
class LoadMatcher
|
4
|
+
def initialize(klass)
|
5
|
+
@collector = Collector.new
|
6
|
+
@klass = klass.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
def supports_block_expectations?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def matches?(block)
|
14
|
+
block.call
|
15
|
+
|
16
|
+
@count = @collector.calls_by_name("#{@klass} Load")
|
17
|
+
@count > 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def failure_message
|
21
|
+
"expected block to repeatedly load #{@klass}, but it was loaded #{@count} times"
|
22
|
+
end
|
23
|
+
|
24
|
+
def failure_message_when_negated
|
25
|
+
"expected block not to repeatedly load #{@klass}, but it was loaded #{@count} times"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -19,9 +19,11 @@ module RSpec::ActiveRecord::Expectations
|
|
19
19
|
raise NoComparisonError unless @match_method
|
20
20
|
raise NoQueryTypeError unless @collector.valid_type?(@query_type)
|
21
21
|
|
22
|
-
|
22
|
+
block.call
|
23
|
+
result = @match_method.call
|
24
|
+
@collector.finalize
|
23
25
|
|
24
|
-
|
26
|
+
result
|
25
27
|
end
|
26
28
|
|
27
29
|
# COMPARISON TYPES
|
@@ -54,22 +56,45 @@ module RSpec::ActiveRecord::Expectations
|
|
54
56
|
end
|
55
57
|
alias_method :at_least, :greater_than_or_equal_to
|
56
58
|
|
59
|
+
def exactly(n)
|
60
|
+
@comparison = n
|
61
|
+
@match_method = method(:compare_exactly)
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
57
65
|
# TARGET QUERY TYPES
|
58
66
|
|
59
|
-
|
60
|
-
|
61
|
-
|
67
|
+
RSpec::ActiveRecord::Expectations::QueryInspector.valid_query_types.each do |type|
|
68
|
+
define_method type do
|
69
|
+
@query_type = type
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
singularized_type = type.to_s.gsub('queries', 'query')
|
74
|
+
if singularized_type != type.to_s
|
75
|
+
define_method singularized_type do
|
76
|
+
@query_type = type
|
77
|
+
self
|
78
|
+
end
|
79
|
+
end
|
62
80
|
end
|
63
81
|
|
82
|
+
# TODO singularize everything
|
83
|
+
alias_method :query, :queries
|
84
|
+
|
64
85
|
private
|
65
86
|
|
87
|
+
def humanized_query_type
|
88
|
+
@query_type.to_s.gsub("_", " ")
|
89
|
+
end
|
90
|
+
|
66
91
|
# MATCHERS
|
67
92
|
|
68
93
|
def compare_less_than
|
69
94
|
count = @collector.queries_of_type(@query_type)
|
70
95
|
|
71
|
-
@failure_message = "expected block to execute fewer than #{@comparison}
|
72
|
-
@failure_message_when_negated = "expected block not to execute fewer than #{@comparison}
|
96
|
+
@failure_message = "expected block to execute fewer than #{@comparison} #{humanized_query_type}, but it executed #{count}"
|
97
|
+
@failure_message_when_negated = "expected block not to execute fewer than #{@comparison} #{humanized_query_type}, but it executed #{count}"
|
73
98
|
|
74
99
|
count < @comparison
|
75
100
|
end
|
@@ -78,8 +103,8 @@ module RSpec::ActiveRecord::Expectations
|
|
78
103
|
count = @collector.queries_of_type(@query_type)
|
79
104
|
|
80
105
|
# boy this negated operator is confusing. don't use that plz.
|
81
|
-
@failure_message = "expected block to execute at most #{@comparison}
|
82
|
-
@failure_message_when_negated = "expected block not to execute any less than #{@comparison}
|
106
|
+
@failure_message = "expected block to execute at most #{@comparison} #{humanized_query_type}, but it executed #{count}"
|
107
|
+
@failure_message_when_negated = "expected block not to execute any less than #{@comparison} #{humanized_query_type}, but it executed #{count}"
|
83
108
|
|
84
109
|
count <= @comparison
|
85
110
|
end
|
@@ -87,8 +112,8 @@ module RSpec::ActiveRecord::Expectations
|
|
87
112
|
def compare_greater_than
|
88
113
|
count = @collector.queries_of_type(@query_type)
|
89
114
|
|
90
|
-
@failure_message = "expected block to execute greater than #{@comparison}
|
91
|
-
@failure_message_when_negated = "expected block not to execute greater than #{@comparison}
|
115
|
+
@failure_message = "expected block to execute greater than #{@comparison} #{humanized_query_type}, but it executed #{count}"
|
116
|
+
@failure_message_when_negated = "expected block not to execute greater than #{@comparison} #{humanized_query_type}, but it executed #{count}"
|
92
117
|
|
93
118
|
count > @comparison
|
94
119
|
end
|
@@ -97,11 +122,20 @@ module RSpec::ActiveRecord::Expectations
|
|
97
122
|
count = @collector.queries_of_type(@query_type)
|
98
123
|
|
99
124
|
# see above, negating this matcher is so confusing.
|
100
|
-
@failure_message = "expected block to execute at least #{@comparison}
|
101
|
-
@failure_message_when_negated = "expected block not to execute any more than #{@comparison}
|
125
|
+
@failure_message = "expected block to execute at least #{@comparison} #{humanized_query_type}, but it executed #{count}"
|
126
|
+
@failure_message_when_negated = "expected block not to execute any more than #{@comparison} #{humanized_query_type}, but it executed #{count}"
|
102
127
|
|
103
128
|
count >= @comparison
|
104
129
|
end
|
130
|
+
|
131
|
+
def compare_exactly
|
132
|
+
count = @collector.queries_of_type(@query_type)
|
133
|
+
|
134
|
+
@failure_message = "expected block to execute exactly #{@comparison} #{humanized_query_type}, but it executed #{count}"
|
135
|
+
@failure_message_when_negated = "expected block not to execute exactly #{@comparison} #{humanized_query_type}, but it executed #{count}"
|
136
|
+
|
137
|
+
count == @comparison
|
138
|
+
end
|
105
139
|
end
|
106
140
|
end
|
107
141
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RSpec::ActiveRecord::Expectations
|
2
|
+
class QueryInspector
|
3
|
+
def self.valid_query_types
|
4
|
+
[:queries, :schema_queries, :transaction_queries, :insert_queries,
|
5
|
+
:load_queries, :destroy_queries, :exists_queries]
|
6
|
+
end
|
7
|
+
|
8
|
+
def categorize(query)
|
9
|
+
if query[:name] == "SCHEMA"
|
10
|
+
[:schema_queries]
|
11
|
+
elsif query[:name] == "TRANSACTION" || query[:sql] =~ /^begin/i || query[:sql] =~ /^commit/i
|
12
|
+
[:transaction_queries]
|
13
|
+
elsif query[:name] =~ /Create$/
|
14
|
+
[:queries, :insert_queries]
|
15
|
+
elsif query[:name] =~ /Load$/
|
16
|
+
[:queries, :load_queries]
|
17
|
+
elsif query[:name] =~ /Destroy$/
|
18
|
+
[:queries, :destroy_queries]
|
19
|
+
elsif query[:name] =~ /Delete All$/
|
20
|
+
[:queries, :destroy_queries]
|
21
|
+
elsif query[:name] =~ /Exists\??$/
|
22
|
+
[:queries, :exists_queries]
|
23
|
+
else
|
24
|
+
[:queries]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -4,10 +4,16 @@ module RSpec
|
|
4
4
|
def execute
|
5
5
|
Matchers::QueryCountMatcher.new
|
6
6
|
end
|
7
|
+
|
8
|
+
def repeatedly_load(klass)
|
9
|
+
Matchers::LoadMatcher.new(klass)
|
10
|
+
end
|
7
11
|
end
|
8
12
|
end
|
9
13
|
end
|
10
14
|
|
11
15
|
require_relative 'expectations/errors'
|
16
|
+
require_relative 'expectations/query_inspector'
|
12
17
|
require_relative 'expectations/collector'
|
13
|
-
require_relative 'expectations/matchers/
|
18
|
+
require_relative 'expectations/matchers/query_count_matcher'
|
19
|
+
require_relative 'expectations/matchers/load_matcher'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "rspec-activerecord-expectations"
|
3
|
-
spec.version = '1.1
|
3
|
+
spec.version = '2.1.1'
|
4
4
|
spec.authors = ["Joseph Mastey"]
|
5
5
|
spec.email = ["hello@joemastey.com"]
|
6
6
|
|
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.description = %q{Adds new matchers to rspec to help you test whether your code is executing an unreasonable number of queries.}
|
9
9
|
spec.homepage = "https://github.com/jmmastey/rspec-activerecord-expectations"
|
10
10
|
spec.license = "MIT"
|
11
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
11
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
12
12
|
|
13
13
|
spec.metadata["homepage_uri"] = spec.homepage
|
14
14
|
spec.metadata["source_code_uri"] = spec.homepage
|
@@ -23,7 +23,12 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
|
25
25
|
spec.add_dependency "activerecord", ">= 5.0.0", "< 7.1.0"
|
26
|
-
|
26
|
+
|
27
|
+
if RUBY_PLATFORM == 'java'
|
28
|
+
spec.add_development_dependency "activerecord-jdbcsqlite3-adapter", '>= 60'
|
29
|
+
else
|
30
|
+
spec.add_development_dependency "sqlite3", "~> 1.0"
|
31
|
+
end
|
27
32
|
|
28
33
|
spec.add_development_dependency "pry", "~> 0.0"
|
29
34
|
spec.add_development_dependency "appraisal", "~> 2"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-activerecord-expectations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 2.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joseph Mastey
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -37,7 +37,7 @@ dependencies:
|
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '1.0'
|
40
|
-
type: :
|
40
|
+
type: :development
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
@@ -102,7 +102,9 @@ files:
|
|
102
102
|
- lib/rspec/activerecord/expectations.rb
|
103
103
|
- lib/rspec/activerecord/expectations/collector.rb
|
104
104
|
- lib/rspec/activerecord/expectations/errors.rb
|
105
|
-
- lib/rspec/activerecord/expectations/matchers/
|
105
|
+
- lib/rspec/activerecord/expectations/matchers/load_matcher.rb
|
106
|
+
- lib/rspec/activerecord/expectations/matchers/query_count_matcher.rb
|
107
|
+
- lib/rspec/activerecord/expectations/query_inspector.rb
|
106
108
|
- rspec-activerecord-expectations.gemspec
|
107
109
|
homepage: https://github.com/jmmastey/rspec-activerecord-expectations
|
108
110
|
licenses:
|
@@ -119,7 +121,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
119
121
|
requirements:
|
120
122
|
- - ">="
|
121
123
|
- !ruby/object:Gem::Version
|
122
|
-
version: 2.
|
124
|
+
version: 2.5.0
|
123
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
126
|
requirements:
|
125
127
|
- - ">="
|