bullet 5.7.0 → 6.0.0
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 +5 -5
- data/.travis.yml +2 -0
- data/CHANGELOG.md +27 -1
- data/Gemfile.mongoid-7.0 +15 -0
- data/Gemfile.rails-4.0 +1 -1
- data/Gemfile.rails-4.1 +1 -1
- data/Gemfile.rails-4.2 +1 -1
- data/Gemfile.rails-5.0 +1 -1
- data/Gemfile.rails-5.1 +1 -1
- data/Gemfile.rails-5.2 +2 -2
- data/Gemfile.rails-6.0 +15 -0
- data/Guardfile +1 -1
- data/README.md +10 -5
- data/Rakefile +5 -5
- data/bullet.gemspec +12 -6
- data/lib/bullet/active_record4.rb +10 -14
- data/lib/bullet/active_record41.rb +8 -14
- data/lib/bullet/active_record42.rb +16 -22
- data/lib/bullet/active_record5.rb +69 -49
- data/lib/bullet/active_record52.rb +40 -40
- data/lib/bullet/active_record60.rb +245 -0
- data/lib/bullet/bullet_xhr.js +58 -0
- data/lib/bullet/dependency.rb +19 -5
- data/lib/bullet/detector/association.rb +18 -16
- data/lib/bullet/detector/base.rb +2 -0
- data/lib/bullet/detector/counter_cache.rb +13 -10
- data/lib/bullet/detector/n_plus_one_query.rb +21 -19
- data/lib/bullet/detector/unused_eager_loading.rb +27 -22
- data/lib/bullet/detector.rb +2 -0
- data/lib/bullet/ext/object.rb +9 -5
- data/lib/bullet/ext/string.rb +3 -1
- data/lib/bullet/mongoid4x.rb +7 -2
- data/lib/bullet/mongoid5x.rb +7 -2
- data/lib/bullet/mongoid6x.rb +11 -6
- data/lib/bullet/mongoid7x.rb +61 -0
- data/lib/bullet/notification/base.rb +21 -15
- data/lib/bullet/notification/counter_cache.rb +2 -0
- data/lib/bullet/notification/n_plus_one_query.rb +6 -4
- data/lib/bullet/notification/unused_eager_loading.rb +6 -4
- data/lib/bullet/notification.rb +2 -0
- data/lib/bullet/notification_collector.rb +2 -1
- data/lib/bullet/rack.rb +52 -31
- data/lib/bullet/registry/association.rb +2 -0
- data/lib/bullet/registry/base.rb +2 -0
- data/lib/bullet/registry/object.rb +2 -0
- data/lib/bullet/registry.rb +2 -0
- data/lib/bullet/stack_trace_filter.rb +57 -21
- data/lib/bullet/version.rb +2 -1
- data/lib/bullet.rb +48 -31
- data/lib/generators/bullet/install_generator.rb +5 -3
- data/perf/benchmark.rb +9 -7
- data/rails/init.rb +2 -0
- data/spec/bullet/detector/association_spec.rb +2 -0
- data/spec/bullet/detector/base_spec.rb +2 -0
- data/spec/bullet/detector/counter_cache_spec.rb +2 -0
- data/spec/bullet/detector/n_plus_one_query_spec.rb +33 -8
- data/spec/bullet/detector/unused_eager_loading_spec.rb +2 -0
- data/spec/bullet/ext/object_spec.rb +12 -5
- data/spec/bullet/ext/string_spec.rb +2 -0
- data/spec/bullet/notification/base_spec.rb +8 -6
- data/spec/bullet/notification/counter_cache_spec.rb +3 -1
- data/spec/bullet/notification/n_plus_one_query_spec.rb +3 -1
- data/spec/bullet/notification/unused_eager_loading_spec.rb +3 -1
- data/spec/bullet/notification_collector_spec.rb +2 -0
- data/spec/bullet/rack_spec.rb +22 -12
- data/spec/bullet/registry/association_spec.rb +4 -2
- data/spec/bullet/registry/base_spec.rb +5 -3
- data/spec/bullet/registry/object_spec.rb +2 -0
- data/spec/bullet_spec.rb +9 -7
- data/spec/integration/active_record/association_spec.rb +70 -19
- data/spec/integration/counter_cache_spec.rb +5 -3
- data/spec/integration/mongoid/association_spec.rb +2 -0
- data/spec/models/address.rb +2 -0
- data/spec/models/author.rb +2 -0
- data/spec/models/base_user.rb +2 -0
- data/spec/models/category.rb +2 -0
- data/spec/models/city.rb +2 -0
- data/spec/models/client.rb +4 -0
- data/spec/models/comment.rb +2 -0
- data/spec/models/company.rb +2 -0
- data/spec/models/country.rb +2 -0
- data/spec/models/document.rb +2 -0
- data/spec/models/entry.rb +2 -0
- data/spec/models/firm.rb +3 -0
- data/spec/models/folder.rb +2 -0
- data/spec/models/group.rb +4 -0
- data/spec/models/mongoid/address.rb +3 -1
- data/spec/models/mongoid/category.rb +4 -2
- data/spec/models/mongoid/comment.rb +3 -1
- data/spec/models/mongoid/company.rb +3 -1
- data/spec/models/mongoid/entry.rb +3 -1
- data/spec/models/mongoid/post.rb +6 -4
- data/spec/models/mongoid/user.rb +2 -0
- data/spec/models/newspaper.rb +2 -0
- data/spec/models/page.rb +2 -0
- data/spec/models/person.rb +2 -0
- data/spec/models/pet.rb +2 -0
- data/spec/models/post.rb +17 -0
- data/spec/models/relationship.rb +2 -0
- data/spec/models/reply.rb +2 -0
- data/spec/models/student.rb +2 -0
- data/spec/models/submission.rb +2 -0
- data/spec/models/teacher.rb +2 -0
- data/spec/models/user.rb +2 -0
- data/spec/models/writer.rb +2 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/support/bullet_ext.rb +2 -0
- data/spec/support/mongo_seed.rb +32 -30
- data/spec/support/rack_double.rb +9 -16
- data/spec/support/sqlite_seed.rb +84 -75
- data/tasks/bullet_tasks.rake +2 -0
- data/test.sh +2 -0
- data/update.sh +1 -0
- metadata +17 -9
|
@@ -1,16 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module SaveWithBulletSupport
|
|
3
|
-
def
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
end
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def save!(*args)
|
|
11
|
-
was_new_record = new_record?
|
|
12
|
-
super(*args).tap do |result|
|
|
13
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
|
|
5
|
+
def _create_record(*)
|
|
6
|
+
super do
|
|
7
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
|
8
|
+
yield(self) if block_given?
|
|
14
9
|
end
|
|
15
10
|
end
|
|
16
11
|
end
|
|
@@ -18,7 +13,7 @@ module Bullet
|
|
|
18
13
|
module ActiveRecord
|
|
19
14
|
def self.enable
|
|
20
15
|
require 'active_record'
|
|
21
|
-
::ActiveRecord::Base.extend(Module.new
|
|
16
|
+
::ActiveRecord::Base.extend(Module.new do
|
|
22
17
|
def find_by_sql(sql, binds = [], preparable: nil, &block)
|
|
23
18
|
result = super
|
|
24
19
|
if Bullet.start?
|
|
@@ -37,11 +32,11 @@ module Bullet
|
|
|
37
32
|
end
|
|
38
33
|
result
|
|
39
34
|
end
|
|
40
|
-
|
|
35
|
+
end)
|
|
41
36
|
|
|
42
37
|
::ActiveRecord::Base.prepend(SaveWithBulletSupport)
|
|
43
38
|
|
|
44
|
-
::ActiveRecord::Relation.prepend(Module.new
|
|
39
|
+
::ActiveRecord::Relation.prepend(Module.new do
|
|
45
40
|
# if select a collection of objects, then these objects have possible to cause N+1 query.
|
|
46
41
|
# if select only one object, then the only one object has impossible to cause N+1 query.
|
|
47
42
|
def records
|
|
@@ -59,9 +54,9 @@ module Bullet
|
|
|
59
54
|
end
|
|
60
55
|
result
|
|
61
56
|
end
|
|
62
|
-
|
|
57
|
+
end)
|
|
63
58
|
|
|
64
|
-
::ActiveRecord::Associations::Preloader.prepend(Module.new
|
|
59
|
+
::ActiveRecord::Associations::Preloader.prepend(Module.new do
|
|
65
60
|
def preloaders_for_one(association, records, scope)
|
|
66
61
|
if Bullet.start?
|
|
67
62
|
records.compact!
|
|
@@ -74,12 +69,13 @@ module Bullet
|
|
|
74
69
|
end
|
|
75
70
|
super
|
|
76
71
|
end
|
|
77
|
-
|
|
72
|
+
end)
|
|
78
73
|
|
|
79
|
-
::ActiveRecord::FinderMethods.prepend(Module.new
|
|
74
|
+
::ActiveRecord::FinderMethods.prepend(Module.new do
|
|
80
75
|
# add includes in scope
|
|
81
76
|
def find_with_associations
|
|
82
77
|
return super { |r| yield r } if block_given?
|
|
78
|
+
|
|
83
79
|
records = super
|
|
84
80
|
if Bullet.start?
|
|
85
81
|
associations = (eager_load_values + includes_values).uniq
|
|
@@ -90,20 +86,37 @@ module Bullet
|
|
|
90
86
|
end
|
|
91
87
|
records
|
|
92
88
|
end
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
::ActiveRecord::Associations::JoinDependency.prepend(Module.new
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
89
|
+
end)
|
|
90
|
+
|
|
91
|
+
::ActiveRecord::Associations::JoinDependency.prepend(Module.new do
|
|
92
|
+
if ::ActiveRecord::Associations::JoinDependency.instance_method(:instantiate).parameters.last[0] == :block
|
|
93
|
+
# ActiveRecord >= 5.1.5
|
|
94
|
+
def instantiate(result_set, &block)
|
|
95
|
+
@bullet_eager_loadings = {}
|
|
96
|
+
records = super
|
|
97
|
+
|
|
98
|
+
if Bullet.start?
|
|
99
|
+
@bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
|
|
100
|
+
objects = eager_loadings_hash.keys
|
|
101
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
|
|
102
|
+
end
|
|
104
103
|
end
|
|
104
|
+
records
|
|
105
|
+
end
|
|
106
|
+
else
|
|
107
|
+
# ActiveRecord <= 5.1.4
|
|
108
|
+
def instantiate(result_set, aliases)
|
|
109
|
+
@bullet_eager_loadings = {}
|
|
110
|
+
records = super
|
|
111
|
+
|
|
112
|
+
if Bullet.start?
|
|
113
|
+
@bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
|
|
114
|
+
objects = eager_loadings_hash.keys
|
|
115
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
records
|
|
105
119
|
end
|
|
106
|
-
records
|
|
107
120
|
end
|
|
108
121
|
|
|
109
122
|
def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
|
|
@@ -112,14 +125,14 @@ module Bullet
|
|
|
112
125
|
parent.children.each do |node|
|
|
113
126
|
key = aliases.column_alias(node, node.primary_key)
|
|
114
127
|
id = row[key]
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
128
|
+
next unless id.nil?
|
|
129
|
+
|
|
130
|
+
associations = node.reflection.name
|
|
131
|
+
Bullet::Detector::Association.add_object_associations(ar_parent, associations)
|
|
132
|
+
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
|
|
133
|
+
@bullet_eager_loadings[ar_parent.class] ||= {}
|
|
134
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
|
|
135
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] << associations
|
|
123
136
|
end
|
|
124
137
|
end
|
|
125
138
|
end
|
|
@@ -142,19 +155,26 @@ module Bullet
|
|
|
142
155
|
|
|
143
156
|
result
|
|
144
157
|
end
|
|
145
|
-
|
|
158
|
+
end)
|
|
146
159
|
|
|
147
|
-
::ActiveRecord::Associations::CollectionAssociation.prepend(Module.new
|
|
160
|
+
::ActiveRecord::Associations::CollectionAssociation.prepend(Module.new do
|
|
148
161
|
def load_target
|
|
149
162
|
records = super
|
|
150
163
|
|
|
151
164
|
if Bullet.start?
|
|
152
|
-
if
|
|
153
|
-
|
|
154
|
-
|
|
165
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
|
166
|
+
refl = reflection.through_reflection
|
|
167
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
|
|
168
|
+
association = owner.association refl.name
|
|
155
169
|
Array(association.target).each do |through_record|
|
|
156
170
|
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
|
157
171
|
end
|
|
172
|
+
|
|
173
|
+
if refl.through_reflection?
|
|
174
|
+
refl = refl.through_reflection while refl.through_reflection?
|
|
175
|
+
|
|
176
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
|
|
177
|
+
end
|
|
158
178
|
end
|
|
159
179
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
|
|
160
180
|
if records.first.class.name !~ /^HABTM_/
|
|
@@ -183,9 +203,9 @@ module Bullet
|
|
|
183
203
|
end
|
|
184
204
|
super
|
|
185
205
|
end
|
|
186
|
-
|
|
206
|
+
end)
|
|
187
207
|
|
|
188
|
-
::ActiveRecord::Associations::SingularAssociation.prepend(Module.new
|
|
208
|
+
::ActiveRecord::Associations::SingularAssociation.prepend(Module.new do
|
|
189
209
|
# call has_one and belongs_to associations
|
|
190
210
|
def target
|
|
191
211
|
result = super()
|
|
@@ -201,9 +221,9 @@ module Bullet
|
|
|
201
221
|
end
|
|
202
222
|
result
|
|
203
223
|
end
|
|
204
|
-
|
|
224
|
+
end)
|
|
205
225
|
|
|
206
|
-
::ActiveRecord::Associations::HasManyAssociation.prepend(Module.new
|
|
226
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(Module.new do
|
|
207
227
|
def empty?
|
|
208
228
|
result = super
|
|
209
229
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
@@ -214,12 +234,12 @@ module Bullet
|
|
|
214
234
|
|
|
215
235
|
def count_records
|
|
216
236
|
result = reflection.has_cached_counter?
|
|
217
|
-
if Bullet.start? && !result && !
|
|
237
|
+
if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
|
|
218
238
|
Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
|
|
219
239
|
end
|
|
220
240
|
super
|
|
221
241
|
end
|
|
222
|
-
|
|
242
|
+
end)
|
|
223
243
|
end
|
|
224
244
|
end
|
|
225
245
|
end
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module SaveWithBulletSupport
|
|
3
|
-
def
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
end
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def save!(*args)
|
|
11
|
-
was_new_record = new_record?
|
|
12
|
-
super(*args).tap do |result|
|
|
13
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
|
|
5
|
+
def _create_record(*)
|
|
6
|
+
super do
|
|
7
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
|
8
|
+
yield(self) if block_given?
|
|
14
9
|
end
|
|
15
10
|
end
|
|
16
11
|
end
|
|
@@ -18,7 +13,7 @@ module Bullet
|
|
|
18
13
|
module ActiveRecord
|
|
19
14
|
def self.enable
|
|
20
15
|
require 'active_record'
|
|
21
|
-
::ActiveRecord::Base.extend(Module.new
|
|
16
|
+
::ActiveRecord::Base.extend(Module.new do
|
|
22
17
|
def find_by_sql(sql, binds = [], preparable: nil, &block)
|
|
23
18
|
result = super
|
|
24
19
|
if Bullet.start?
|
|
@@ -37,11 +32,11 @@ module Bullet
|
|
|
37
32
|
end
|
|
38
33
|
result
|
|
39
34
|
end
|
|
40
|
-
|
|
35
|
+
end)
|
|
41
36
|
|
|
42
37
|
::ActiveRecord::Base.prepend(SaveWithBulletSupport)
|
|
43
38
|
|
|
44
|
-
::ActiveRecord::Relation.prepend(Module.new
|
|
39
|
+
::ActiveRecord::Relation.prepend(Module.new do
|
|
45
40
|
# if select a collection of objects, then these objects have possible to cause N+1 query.
|
|
46
41
|
# if select only one object, then the only one object has impossible to cause N+1 query.
|
|
47
42
|
def records
|
|
@@ -59,9 +54,9 @@ module Bullet
|
|
|
59
54
|
end
|
|
60
55
|
result
|
|
61
56
|
end
|
|
62
|
-
|
|
57
|
+
end)
|
|
63
58
|
|
|
64
|
-
::ActiveRecord::Associations::Preloader.prepend(Module.new
|
|
59
|
+
::ActiveRecord::Associations::Preloader.prepend(Module.new do
|
|
65
60
|
def preloaders_for_one(association, records, scope)
|
|
66
61
|
if Bullet.start?
|
|
67
62
|
records.compact!
|
|
@@ -74,12 +69,13 @@ module Bullet
|
|
|
74
69
|
end
|
|
75
70
|
super
|
|
76
71
|
end
|
|
77
|
-
|
|
72
|
+
end)
|
|
78
73
|
|
|
79
|
-
::ActiveRecord::FinderMethods.prepend(Module.new
|
|
74
|
+
::ActiveRecord::FinderMethods.prepend(Module.new do
|
|
80
75
|
# add includes in scope
|
|
81
76
|
def find_with_associations
|
|
82
77
|
return super { |r| yield r } if block_given?
|
|
78
|
+
|
|
83
79
|
records = super
|
|
84
80
|
if Bullet.start?
|
|
85
81
|
associations = (eager_load_values + includes_values).uniq
|
|
@@ -90,15 +86,15 @@ module Bullet
|
|
|
90
86
|
end
|
|
91
87
|
records
|
|
92
88
|
end
|
|
93
|
-
|
|
89
|
+
end)
|
|
94
90
|
|
|
95
|
-
::ActiveRecord::Associations::JoinDependency.prepend(Module.new
|
|
91
|
+
::ActiveRecord::Associations::JoinDependency.prepend(Module.new do
|
|
96
92
|
def instantiate(result_set, &block)
|
|
97
93
|
@bullet_eager_loadings = {}
|
|
98
94
|
records = super
|
|
99
95
|
|
|
100
96
|
if Bullet.start?
|
|
101
|
-
@bullet_eager_loadings.each do |
|
|
97
|
+
@bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
|
|
102
98
|
objects = eager_loadings_hash.keys
|
|
103
99
|
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
|
|
104
100
|
end
|
|
@@ -112,14 +108,14 @@ module Bullet
|
|
|
112
108
|
parent.children.each do |node|
|
|
113
109
|
key = aliases.column_alias(node, node.primary_key)
|
|
114
110
|
id = row[key]
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
111
|
+
next unless id.nil?
|
|
112
|
+
|
|
113
|
+
associations = node.reflection.name
|
|
114
|
+
Bullet::Detector::Association.add_object_associations(ar_parent, associations)
|
|
115
|
+
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
|
|
116
|
+
@bullet_eager_loadings[ar_parent.class] ||= {}
|
|
117
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
|
|
118
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] << associations
|
|
123
119
|
end
|
|
124
120
|
end
|
|
125
121
|
end
|
|
@@ -142,19 +138,23 @@ module Bullet
|
|
|
142
138
|
|
|
143
139
|
result
|
|
144
140
|
end
|
|
145
|
-
|
|
141
|
+
end)
|
|
146
142
|
|
|
147
|
-
::ActiveRecord::Associations::CollectionAssociation.prepend(Module.new
|
|
143
|
+
::ActiveRecord::Associations::CollectionAssociation.prepend(Module.new do
|
|
148
144
|
def load_target
|
|
149
145
|
records = super
|
|
150
146
|
|
|
151
147
|
if Bullet.start?
|
|
152
|
-
if
|
|
153
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
|
154
|
-
association =
|
|
148
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
|
149
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
|
150
|
+
association = owner.association reflection.through_reflection.name
|
|
155
151
|
Array(association.target).each do |through_record|
|
|
156
152
|
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
|
157
153
|
end
|
|
154
|
+
|
|
155
|
+
if reflection.through_reflection != through_reflection
|
|
156
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
|
157
|
+
end
|
|
158
158
|
end
|
|
159
159
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
|
|
160
160
|
if records.first.class.name !~ /^HABTM_/
|
|
@@ -183,9 +183,9 @@ module Bullet
|
|
|
183
183
|
end
|
|
184
184
|
super
|
|
185
185
|
end
|
|
186
|
-
|
|
186
|
+
end)
|
|
187
187
|
|
|
188
|
-
::ActiveRecord::Associations::SingularAssociation.prepend(Module.new
|
|
188
|
+
::ActiveRecord::Associations::SingularAssociation.prepend(Module.new do
|
|
189
189
|
# call has_one and belongs_to associations
|
|
190
190
|
def target
|
|
191
191
|
result = super()
|
|
@@ -201,9 +201,9 @@ module Bullet
|
|
|
201
201
|
end
|
|
202
202
|
result
|
|
203
203
|
end
|
|
204
|
-
|
|
204
|
+
end)
|
|
205
205
|
|
|
206
|
-
::ActiveRecord::Associations::HasManyAssociation.prepend(Module.new
|
|
206
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(Module.new do
|
|
207
207
|
def empty?
|
|
208
208
|
result = super
|
|
209
209
|
if Bullet.start? && !reflection.has_cached_counter?
|
|
@@ -214,12 +214,12 @@ module Bullet
|
|
|
214
214
|
|
|
215
215
|
def count_records
|
|
216
216
|
result = reflection.has_cached_counter?
|
|
217
|
-
if Bullet.start? && !result && !
|
|
217
|
+
if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
|
|
218
218
|
Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
|
|
219
219
|
end
|
|
220
220
|
super
|
|
221
221
|
end
|
|
222
|
-
|
|
222
|
+
end)
|
|
223
223
|
end
|
|
224
224
|
end
|
|
225
225
|
end
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bullet
|
|
4
|
+
module SaveWithBulletSupport
|
|
5
|
+
def _create_record(*)
|
|
6
|
+
super do
|
|
7
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
|
8
|
+
yield(self) if block_given?
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module ActiveRecord
|
|
14
|
+
def self.enable
|
|
15
|
+
require 'active_record'
|
|
16
|
+
::ActiveRecord::Base.extend(Module.new do
|
|
17
|
+
def find_by_sql(sql, binds = [], preparable: nil, &block)
|
|
18
|
+
result = super
|
|
19
|
+
if Bullet.start?
|
|
20
|
+
if result.is_a? Array
|
|
21
|
+
if result.size > 1
|
|
22
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
|
23
|
+
Bullet::Detector::CounterCache.add_possible_objects(result)
|
|
24
|
+
elsif result.size == 1
|
|
25
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
|
|
26
|
+
Bullet::Detector::CounterCache.add_impossible_object(result.first)
|
|
27
|
+
end
|
|
28
|
+
elsif result.is_a? ::ActiveRecord::Base
|
|
29
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
|
|
30
|
+
Bullet::Detector::CounterCache.add_impossible_object(result)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
result
|
|
34
|
+
end
|
|
35
|
+
end)
|
|
36
|
+
|
|
37
|
+
::ActiveRecord::Base.prepend(SaveWithBulletSupport)
|
|
38
|
+
|
|
39
|
+
::ActiveRecord::Relation.prepend(Module.new do
|
|
40
|
+
# if select a collection of objects, then these objects have possible to cause N+1 query.
|
|
41
|
+
# if select only one object, then the only one object has impossible to cause N+1 query.
|
|
42
|
+
def records
|
|
43
|
+
result = super
|
|
44
|
+
if Bullet.start?
|
|
45
|
+
if result.first.class.name !~ /^HABTM_/
|
|
46
|
+
if result.size > 1
|
|
47
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
|
48
|
+
Bullet::Detector::CounterCache.add_possible_objects(result)
|
|
49
|
+
elsif result.size == 1
|
|
50
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
|
|
51
|
+
Bullet::Detector::CounterCache.add_impossible_object(result.first)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
result
|
|
56
|
+
end
|
|
57
|
+
end)
|
|
58
|
+
|
|
59
|
+
::ActiveRecord::Associations::Preloader.prepend(Module.new do
|
|
60
|
+
def preloaders_for_one(association, records, scope, polymorphic_parent)
|
|
61
|
+
if Bullet.start?
|
|
62
|
+
records.compact!
|
|
63
|
+
if records.first.class.name !~ /^HABTM_/
|
|
64
|
+
records.each do |record|
|
|
65
|
+
Bullet::Detector::Association.add_object_associations(record, association)
|
|
66
|
+
end
|
|
67
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
super
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def preloaders_for_reflection(reflection, records, scope)
|
|
74
|
+
if Bullet.start?
|
|
75
|
+
records.compact!
|
|
76
|
+
if records.first.class.name !~ /^HABTM_/
|
|
77
|
+
records.each do |record|
|
|
78
|
+
Bullet::Detector::Association.add_object_associations(record, reflection.name)
|
|
79
|
+
end
|
|
80
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, reflection.name)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
super
|
|
84
|
+
end
|
|
85
|
+
end)
|
|
86
|
+
|
|
87
|
+
::ActiveRecord::FinderMethods.prepend(Module.new do
|
|
88
|
+
# add includes in scope
|
|
89
|
+
def find_with_associations
|
|
90
|
+
return super { |r| yield r } if block_given?
|
|
91
|
+
|
|
92
|
+
records = super
|
|
93
|
+
if Bullet.start?
|
|
94
|
+
associations = (eager_load_values + includes_values).uniq
|
|
95
|
+
records.each do |record|
|
|
96
|
+
Bullet::Detector::Association.add_object_associations(record, associations)
|
|
97
|
+
end
|
|
98
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
|
|
99
|
+
end
|
|
100
|
+
records
|
|
101
|
+
end
|
|
102
|
+
end)
|
|
103
|
+
|
|
104
|
+
::ActiveRecord::Associations::JoinDependency.prepend(Module.new do
|
|
105
|
+
def instantiate(result_set, &block)
|
|
106
|
+
@bullet_eager_loadings = {}
|
|
107
|
+
records = super
|
|
108
|
+
|
|
109
|
+
if Bullet.start?
|
|
110
|
+
@bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
|
|
111
|
+
objects = eager_loadings_hash.keys
|
|
112
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
records
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def construct(ar_parent, parent, row, seen, model_cache)
|
|
119
|
+
if Bullet.start?
|
|
120
|
+
unless ar_parent.nil?
|
|
121
|
+
parent.children.each do |node|
|
|
122
|
+
key = aliases.column_alias(node, node.primary_key)
|
|
123
|
+
id = row[key]
|
|
124
|
+
next unless id.nil?
|
|
125
|
+
|
|
126
|
+
associations = node.reflection.name
|
|
127
|
+
Bullet::Detector::Association.add_object_associations(ar_parent, associations)
|
|
128
|
+
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
|
|
129
|
+
@bullet_eager_loadings[ar_parent.class] ||= {}
|
|
130
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
|
|
131
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] << associations
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
super
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# call join associations
|
|
140
|
+
def construct_model(record, node, row, model_cache, id)
|
|
141
|
+
result = super
|
|
142
|
+
|
|
143
|
+
if Bullet.start?
|
|
144
|
+
associations = node.reflection.name
|
|
145
|
+
Bullet::Detector::Association.add_object_associations(record, associations)
|
|
146
|
+
Bullet::Detector::NPlusOneQuery.call_association(record, associations)
|
|
147
|
+
@bullet_eager_loadings[record.class] ||= {}
|
|
148
|
+
@bullet_eager_loadings[record.class][record] ||= Set.new
|
|
149
|
+
@bullet_eager_loadings[record.class][record] << associations
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
result
|
|
153
|
+
end
|
|
154
|
+
end)
|
|
155
|
+
|
|
156
|
+
::ActiveRecord::Associations::CollectionAssociation.prepend(Module.new do
|
|
157
|
+
def load_target
|
|
158
|
+
records = super
|
|
159
|
+
|
|
160
|
+
if Bullet.start?
|
|
161
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
|
162
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
|
163
|
+
association = owner.association reflection.through_reflection.name
|
|
164
|
+
Array(association.target).each do |through_record|
|
|
165
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
if reflection.through_reflection != through_reflection
|
|
169
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
|
|
173
|
+
if records.first.class.name !~ /^HABTM_/
|
|
174
|
+
if records.size > 1
|
|
175
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
|
|
176
|
+
Bullet::Detector::CounterCache.add_possible_objects(records)
|
|
177
|
+
elsif records.size == 1
|
|
178
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
|
|
179
|
+
Bullet::Detector::CounterCache.add_impossible_object(records.first)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
records
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def empty?
|
|
187
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
|
188
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
189
|
+
end
|
|
190
|
+
super
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def include?(object)
|
|
194
|
+
if Bullet.start?
|
|
195
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
196
|
+
end
|
|
197
|
+
super
|
|
198
|
+
end
|
|
199
|
+
end)
|
|
200
|
+
|
|
201
|
+
::ActiveRecord::Associations::SingularAssociation.prepend(Module.new do
|
|
202
|
+
# call has_one and belongs_to associations
|
|
203
|
+
def target
|
|
204
|
+
result = super()
|
|
205
|
+
if Bullet.start?
|
|
206
|
+
if owner.class.name !~ /^HABTM_/ && !@inversed
|
|
207
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
208
|
+
if Bullet::Detector::NPlusOneQuery.impossible?(owner)
|
|
209
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
|
|
210
|
+
else
|
|
211
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
result
|
|
216
|
+
end
|
|
217
|
+
end)
|
|
218
|
+
|
|
219
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(Module.new do
|
|
220
|
+
def empty?
|
|
221
|
+
result = super
|
|
222
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
|
223
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
224
|
+
end
|
|
225
|
+
result
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def count_records
|
|
229
|
+
result = reflection.has_cached_counter?
|
|
230
|
+
if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
|
|
231
|
+
Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
|
|
232
|
+
end
|
|
233
|
+
super
|
|
234
|
+
end
|
|
235
|
+
end)
|
|
236
|
+
|
|
237
|
+
::ActiveRecord::Associations::BelongsToAssociation.prepend(Module.new do
|
|
238
|
+
def writer(record)
|
|
239
|
+
Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
|
|
240
|
+
super
|
|
241
|
+
end
|
|
242
|
+
end)
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|