bullet 6.1.0 → 7.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +101 -2
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +48 -30
  5. data/lib/bullet/active_job.rb +5 -1
  6. data/lib/bullet/active_record4.rb +21 -6
  7. data/lib/bullet/active_record41.rb +22 -6
  8. data/lib/bullet/active_record42.rb +33 -12
  9. data/lib/bullet/active_record5.rb +50 -20
  10. data/lib/bullet/active_record52.rb +71 -36
  11. data/lib/bullet/active_record60.rb +70 -35
  12. data/lib/bullet/active_record61.rb +302 -0
  13. data/lib/bullet/active_record70.rb +318 -0
  14. data/lib/bullet/active_record71.rb +318 -0
  15. data/lib/bullet/bullet_xhr.js +18 -17
  16. data/lib/bullet/dependency.rb +28 -0
  17. data/lib/bullet/detector/association.rb +8 -0
  18. data/lib/bullet/detector/base.rb +2 -1
  19. data/lib/bullet/detector/counter_cache.rb +2 -2
  20. data/lib/bullet/detector/n_plus_one_query.rb +21 -13
  21. data/lib/bullet/detector/unused_eager_loading.rb +6 -3
  22. data/lib/bullet/ext/object.rb +14 -3
  23. data/lib/bullet/mongoid4x.rb +1 -1
  24. data/lib/bullet/mongoid5x.rb +1 -1
  25. data/lib/bullet/mongoid6x.rb +1 -1
  26. data/lib/bullet/mongoid7x.rb +32 -17
  27. data/lib/bullet/mongoid8x.rb +59 -0
  28. data/lib/bullet/notification/base.rb +22 -10
  29. data/lib/bullet/notification/counter_cache.rb +1 -1
  30. data/lib/bullet/notification.rb +2 -1
  31. data/lib/bullet/rack.rb +67 -24
  32. data/lib/bullet/registry/association.rb +2 -1
  33. data/lib/bullet/registry/call_stack.rb +12 -0
  34. data/lib/bullet/registry.rb +1 -0
  35. data/lib/bullet/stack_trace_filter.rb +16 -15
  36. data/lib/bullet/version.rb +1 -1
  37. data/lib/bullet.rb +45 -30
  38. data/lib/generators/bullet/install_generator.rb +22 -25
  39. metadata +13 -148
  40. data/.gitignore +0 -15
  41. data/.rspec +0 -2
  42. data/.travis.yml +0 -33
  43. data/Gemfile +0 -24
  44. data/Gemfile.mongoid +0 -12
  45. data/Gemfile.mongoid-4.0 +0 -15
  46. data/Gemfile.mongoid-5.0 +0 -15
  47. data/Gemfile.mongoid-6.0 +0 -15
  48. data/Gemfile.mongoid-7.0 +0 -15
  49. data/Gemfile.rails-4.0 +0 -16
  50. data/Gemfile.rails-4.1 +0 -16
  51. data/Gemfile.rails-4.2 +0 -16
  52. data/Gemfile.rails-5.0 +0 -15
  53. data/Gemfile.rails-5.1 +0 -15
  54. data/Gemfile.rails-5.2 +0 -15
  55. data/Gemfile.rails-6.0 +0 -15
  56. data/Guardfile +0 -8
  57. data/Hacking.md +0 -75
  58. data/Rakefile +0 -51
  59. data/bullet.gemspec +0 -33
  60. data/perf/benchmark.rb +0 -115
  61. data/rails/init.rb +0 -3
  62. data/spec/bullet/detector/association_spec.rb +0 -28
  63. data/spec/bullet/detector/base_spec.rb +0 -10
  64. data/spec/bullet/detector/counter_cache_spec.rb +0 -58
  65. data/spec/bullet/detector/n_plus_one_query_spec.rb +0 -182
  66. data/spec/bullet/detector/unused_eager_loading_spec.rb +0 -121
  67. data/spec/bullet/ext/object_spec.rb +0 -44
  68. data/spec/bullet/ext/string_spec.rb +0 -15
  69. data/spec/bullet/notification/base_spec.rb +0 -94
  70. data/spec/bullet/notification/counter_cache_spec.rb +0 -14
  71. data/spec/bullet/notification/n_plus_one_query_spec.rb +0 -31
  72. data/spec/bullet/notification/unused_eager_loading_spec.rb +0 -18
  73. data/spec/bullet/notification_collector_spec.rb +0 -34
  74. data/spec/bullet/rack_spec.rb +0 -153
  75. data/spec/bullet/registry/association_spec.rb +0 -28
  76. data/spec/bullet/registry/base_spec.rb +0 -46
  77. data/spec/bullet/registry/object_spec.rb +0 -26
  78. data/spec/bullet_spec.rb +0 -136
  79. data/spec/integration/active_record/association_spec.rb +0 -739
  80. data/spec/integration/counter_cache_spec.rb +0 -68
  81. data/spec/integration/mongoid/association_spec.rb +0 -246
  82. data/spec/models/address.rb +0 -5
  83. data/spec/models/author.rb +0 -5
  84. data/spec/models/base_user.rb +0 -7
  85. data/spec/models/category.rb +0 -12
  86. data/spec/models/city.rb +0 -5
  87. data/spec/models/client.rb +0 -8
  88. data/spec/models/comment.rb +0 -8
  89. data/spec/models/company.rb +0 -5
  90. data/spec/models/country.rb +0 -5
  91. data/spec/models/document.rb +0 -7
  92. data/spec/models/entry.rb +0 -5
  93. data/spec/models/firm.rb +0 -7
  94. data/spec/models/folder.rb +0 -3
  95. data/spec/models/group.rb +0 -3
  96. data/spec/models/mongoid/address.rb +0 -9
  97. data/spec/models/mongoid/category.rb +0 -10
  98. data/spec/models/mongoid/comment.rb +0 -9
  99. data/spec/models/mongoid/company.rb +0 -9
  100. data/spec/models/mongoid/entry.rb +0 -9
  101. data/spec/models/mongoid/post.rb +0 -14
  102. data/spec/models/mongoid/user.rb +0 -7
  103. data/spec/models/newspaper.rb +0 -5
  104. data/spec/models/page.rb +0 -3
  105. data/spec/models/person.rb +0 -5
  106. data/spec/models/pet.rb +0 -5
  107. data/spec/models/post.rb +0 -32
  108. data/spec/models/relationship.rb +0 -6
  109. data/spec/models/reply.rb +0 -5
  110. data/spec/models/student.rb +0 -5
  111. data/spec/models/submission.rb +0 -6
  112. data/spec/models/teacher.rb +0 -5
  113. data/spec/models/user.rb +0 -6
  114. data/spec/models/writer.rb +0 -3
  115. data/spec/spec_helper.rb +0 -99
  116. data/spec/support/bullet_ext.rb +0 -56
  117. data/spec/support/mongo_seed.rb +0 -58
  118. data/spec/support/rack_double.rb +0 -49
  119. data/spec/support/sqlite_seed.rb +0 -246
  120. data/test.sh +0 -13
  121. data/update.sh +0 -10
@@ -75,23 +75,6 @@ module Bullet
75
75
  end
76
76
  )
77
77
 
78
- ::ActiveRecord::FinderMethods.prepend(
79
- Module.new do
80
- # add includes in scope
81
- def find_with_associations
82
- return super { |r| yield r } if block_given?
83
-
84
- records = super
85
- if Bullet.start?
86
- associations = (eager_load_values + includes_values).uniq
87
- records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
88
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
89
- end
90
- records
91
- end
92
- end
93
- )
94
-
95
78
  ::ActiveRecord::Associations::JoinDependency.prepend(
96
79
  Module.new do
97
80
  def instantiate(result_set, &block)
@@ -118,12 +101,17 @@ module Bullet
118
101
  id = row[key]
119
102
  next unless id.nil?
120
103
 
121
- associations = node.reflection.name
122
- Bullet::Detector::Association.add_object_associations(ar_parent, associations)
123
- Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
124
- @bullet_eager_loadings[ar_parent.class] ||= {}
125
- @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
126
- @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
104
+ associations = [node.reflection.name]
105
+ if node.reflection.through_reflection?
106
+ associations << node.reflection.through_reflection.name
107
+ end
108
+ associations.each do |association|
109
+ Bullet::Detector::Association.add_object_associations(ar_parent, association)
110
+ Bullet::Detector::NPlusOneQuery.call_association(ar_parent, association)
111
+ @bullet_eager_loadings[ar_parent.class] ||= {}
112
+ @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
113
+ @bullet_eager_loadings[ar_parent.class][ar_parent] << association
114
+ end
127
115
  end
128
116
  end
129
117
  end
@@ -136,12 +124,17 @@ module Bullet
136
124
  result = super
137
125
 
138
126
  if Bullet.start?
139
- associations = node.reflection.name
140
- Bullet::Detector::Association.add_object_associations(record, associations)
141
- Bullet::Detector::NPlusOneQuery.call_association(record, associations)
142
- @bullet_eager_loadings[record.class] ||= {}
143
- @bullet_eager_loadings[record.class][record] ||= Set.new
144
- @bullet_eager_loadings[record.class][record] << associations
127
+ associations = [node.reflection.name]
128
+ if node.reflection.through_reflection?
129
+ associations << node.reflection.through_reflection.name
130
+ end
131
+ associations.each do |association|
132
+ Bullet::Detector::Association.add_object_associations(record, association)
133
+ Bullet::Detector::NPlusOneQuery.call_association(record, association)
134
+ @bullet_eager_loadings[record.class] ||= {}
135
+ @bullet_eager_loadings[record.class][record] ||= Set.new
136
+ @bullet_eager_loadings[record.class][record] << association
137
+ end
145
138
  end
146
139
 
147
140
  result
@@ -149,6 +142,17 @@ module Bullet
149
142
  end
150
143
  )
151
144
 
145
+ ::ActiveRecord::Associations::Association.prepend(
146
+ Module.new do
147
+ def inversed_from(record)
148
+ if Bullet.start?
149
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
150
+ end
151
+ super
152
+ end
153
+ end
154
+ )
155
+
152
156
  ::ActiveRecord::Associations::CollectionAssociation.prepend(
153
157
  Module.new do
154
158
  def load_target
@@ -156,14 +160,16 @@ module Bullet
156
160
 
157
161
  if Bullet.start?
158
162
  if is_a? ::ActiveRecord::Associations::ThroughAssociation
159
- Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
160
- association = owner.association reflection.through_reflection.name
161
- Array(association.target).each do |through_record|
162
- Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
163
- end
163
+ association = owner.association(reflection.through_reflection.name)
164
+ if association.loaded?
165
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
166
+ Array.wrap(association.target).each do |through_record|
167
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
168
+ end
164
169
 
165
- if reflection.through_reflection != through_reflection
166
- Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
170
+ if reflection.through_reflection != through_reflection
171
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
172
+ end
167
173
  end
168
174
  end
169
175
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
@@ -202,6 +208,17 @@ module Bullet
202
208
 
203
209
  if Bullet.start?
204
210
  if owner.class.name !~ /^HABTM_/ && !@inversed
211
+ if is_a? ::ActiveRecord::Associations::ThroughAssociation
212
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
213
+ association = owner.association reflection.through_reflection.name
214
+ Array.wrap(association.target).each do |through_record|
215
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
216
+ end
217
+
218
+ if reflection.through_reflection != through_reflection
219
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
220
+ end
221
+ end
205
222
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
206
223
 
207
224
  if Bullet::Detector::NPlusOneQuery.impossible?(owner)
@@ -235,6 +252,24 @@ module Bullet
235
252
  end
236
253
  end
237
254
  )
255
+
256
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
257
+ Module.new do
258
+ def count(column_name = nil)
259
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
260
+ Bullet::Detector::CounterCache.add_counter_cache(
261
+ proxy_association.owner,
262
+ proxy_association.reflection.name
263
+ )
264
+ Bullet::Detector::NPlusOneQuery.call_association(
265
+ proxy_association.owner,
266
+ proxy_association.reflection.name
267
+ )
268
+ end
269
+ super(column_name)
270
+ end
271
+ end
272
+ )
238
273
  end
239
274
  end
240
275
  end
@@ -102,23 +102,6 @@ module Bullet
102
102
  end
103
103
  )
104
104
 
105
- ::ActiveRecord::FinderMethods.prepend(
106
- Module.new do
107
- # add includes in scope
108
- def find_with_associations
109
- return super { |r| yield r } if block_given?
110
-
111
- records = super
112
- if Bullet.start?
113
- associations = (eager_load_values + includes_values).uniq
114
- records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
115
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
116
- end
117
- records
118
- end
119
- end
120
- )
121
-
122
105
  ::ActiveRecord::Associations::JoinDependency.prepend(
123
106
  Module.new do
124
107
  def instantiate(result_set, &block)
@@ -145,12 +128,17 @@ module Bullet
145
128
  id = row[key]
146
129
  next unless id.nil?
147
130
 
148
- associations = node.reflection.name
149
- Bullet::Detector::Association.add_object_associations(ar_parent, associations)
150
- Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
151
- @bullet_eager_loadings[ar_parent.class] ||= {}
152
- @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
153
- @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
131
+ associations = [node.reflection.name]
132
+ if node.reflection.through_reflection?
133
+ associations << node.reflection.through_reflection.name
134
+ end
135
+ associations.each do |association|
136
+ Bullet::Detector::Association.add_object_associations(ar_parent, association)
137
+ Bullet::Detector::NPlusOneQuery.call_association(ar_parent, association)
138
+ @bullet_eager_loadings[ar_parent.class] ||= {}
139
+ @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
140
+ @bullet_eager_loadings[ar_parent.class][ar_parent] << association
141
+ end
154
142
  end
155
143
  end
156
144
  end
@@ -163,12 +151,17 @@ module Bullet
163
151
  result = super
164
152
 
165
153
  if Bullet.start?
166
- associations = node.reflection.name
167
- Bullet::Detector::Association.add_object_associations(record, associations)
168
- Bullet::Detector::NPlusOneQuery.call_association(record, associations)
169
- @bullet_eager_loadings[record.class] ||= {}
170
- @bullet_eager_loadings[record.class][record] ||= Set.new
171
- @bullet_eager_loadings[record.class][record] << associations
154
+ associations = [node.reflection.name]
155
+ if node.reflection.through_reflection?
156
+ associations << node.reflection.through_reflection.name
157
+ end
158
+ associations.each do |association|
159
+ Bullet::Detector::Association.add_object_associations(record, association)
160
+ Bullet::Detector::NPlusOneQuery.call_association(record, association)
161
+ @bullet_eager_loadings[record.class] ||= {}
162
+ @bullet_eager_loadings[record.class][record] ||= Set.new
163
+ @bullet_eager_loadings[record.class][record] << association
164
+ end
172
165
  end
173
166
 
174
167
  result
@@ -176,6 +169,17 @@ module Bullet
176
169
  end
177
170
  )
178
171
 
172
+ ::ActiveRecord::Associations::Association.prepend(
173
+ Module.new do
174
+ def inversed_from(record)
175
+ if Bullet.start?
176
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
177
+ end
178
+ super
179
+ end
180
+ end
181
+ )
182
+
179
183
  ::ActiveRecord::Associations::CollectionAssociation.prepend(
180
184
  Module.new do
181
185
  def load_target
@@ -183,14 +187,16 @@ module Bullet
183
187
 
184
188
  if Bullet.start?
185
189
  if is_a? ::ActiveRecord::Associations::ThroughAssociation
186
- Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
187
190
  association = owner.association(reflection.through_reflection.name)
188
- Array(association.target).each do |through_record|
189
- Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
190
- end
191
+ if association.loaded?
192
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
193
+ Array.wrap(association.target).each do |through_record|
194
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
195
+ end
191
196
 
192
- if reflection.through_reflection != through_reflection
193
- Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
197
+ if reflection.through_reflection != through_reflection
198
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
199
+ end
194
200
  end
195
201
  end
196
202
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
@@ -229,6 +235,17 @@ module Bullet
229
235
 
230
236
  if Bullet.start?
231
237
  if owner.class.name !~ /^HABTM_/ && !@inversed
238
+ if is_a? ::ActiveRecord::Associations::ThroughAssociation
239
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
240
+ association = owner.association(reflection.through_reflection.name)
241
+ Array.wrap(association.target).each do |through_record|
242
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
243
+ end
244
+
245
+ if reflection.through_reflection != through_reflection
246
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
247
+ end
248
+ end
232
249
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
233
250
 
234
251
  if Bullet::Detector::NPlusOneQuery.impossible?(owner)
@@ -262,6 +279,24 @@ module Bullet
262
279
  end
263
280
  end
264
281
  )
282
+
283
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
284
+ Module.new do
285
+ def count
286
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
287
+ Bullet::Detector::CounterCache.add_counter_cache(
288
+ proxy_association.owner,
289
+ proxy_association.reflection.name
290
+ )
291
+ Bullet::Detector::NPlusOneQuery.call_association(
292
+ proxy_association.owner,
293
+ proxy_association.reflection.name
294
+ )
295
+ end
296
+ super
297
+ end
298
+ end
299
+ )
265
300
  end
266
301
  end
267
302
  end
@@ -0,0 +1,302 @@
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(
17
+ Module.new do
18
+ def find_by_sql(sql, binds = [], preparable: nil, &block)
19
+ result = super
20
+ if Bullet.start?
21
+ if result.is_a? Array
22
+ if result.size > 1
23
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
24
+ Bullet::Detector::CounterCache.add_possible_objects(result)
25
+ elsif result.size == 1
26
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
27
+ Bullet::Detector::CounterCache.add_impossible_object(result.first)
28
+ end
29
+ elsif result.is_a? ::ActiveRecord::Base
30
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
31
+ Bullet::Detector::CounterCache.add_impossible_object(result)
32
+ end
33
+ end
34
+ result
35
+ end
36
+ end
37
+ )
38
+
39
+ ::ActiveRecord::Base.prepend(SaveWithBulletSupport)
40
+
41
+ ::ActiveRecord::Relation.prepend(
42
+ Module.new do
43
+ # if select a collection of objects, then these objects have possible to cause N+1 query.
44
+ # if select only one object, then the only one object has impossible to cause N+1 query.
45
+ def records
46
+ result = super
47
+ if Bullet.start?
48
+ if result.first.class.name !~ /^HABTM_/
49
+ if result.size > 1
50
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
51
+ Bullet::Detector::CounterCache.add_possible_objects(result)
52
+ elsif result.size == 1
53
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
54
+ Bullet::Detector::CounterCache.add_impossible_object(result.first)
55
+ end
56
+ end
57
+ end
58
+ result
59
+ end
60
+ end
61
+ )
62
+
63
+ ::ActiveRecord::Associations::Preloader.prepend(
64
+ Module.new do
65
+ def preloaders_for_one(association, records, scope, polymorphic_parent)
66
+ if Bullet.start?
67
+ records.compact!
68
+ if records.first.class.name !~ /^HABTM_/
69
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, association) }
70
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
71
+ end
72
+ end
73
+ super
74
+ end
75
+
76
+ def preloaders_for_reflection(reflection, records, scope)
77
+ if Bullet.start?
78
+ records.compact!
79
+ if records.first.class.name !~ /^HABTM_/
80
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, reflection.name) }
81
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, reflection.name)
82
+ end
83
+ end
84
+ super
85
+ end
86
+ end
87
+ )
88
+
89
+ ::ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(
90
+ Module.new do
91
+ def preloaded_records
92
+ if Bullet.start? && !defined?(@preloaded_records)
93
+ source_preloaders.each do |source_preloader|
94
+ reflection_name = source_preloader.send(:reflection).name
95
+ source_preloader.send(:owners).each do |owner|
96
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
97
+ end
98
+ end
99
+ end
100
+ super
101
+ end
102
+ end
103
+ )
104
+
105
+ ::ActiveRecord::Associations::JoinDependency.prepend(
106
+ Module.new do
107
+ def instantiate(result_set, strict_loading_value, &block)
108
+ @bullet_eager_loadings = {}
109
+ records = super
110
+
111
+ if Bullet.start?
112
+ @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
113
+ objects = eager_loadings_hash.keys
114
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(
115
+ objects,
116
+ eager_loadings_hash[objects.first].to_a
117
+ )
118
+ end
119
+ end
120
+ records
121
+ end
122
+
123
+ def construct(ar_parent, parent, row, seen, model_cache, strict_loading_value)
124
+ if Bullet.start?
125
+ unless ar_parent.nil?
126
+ parent.children.each do |node|
127
+ key = aliases.column_alias(node, node.primary_key)
128
+ id = row[key]
129
+ next unless id.nil?
130
+
131
+ associations = [node.reflection.name]
132
+ if node.reflection.through_reflection?
133
+ associations << node.reflection.through_reflection.name
134
+ end
135
+ associations.each do |association|
136
+ Bullet::Detector::Association.add_object_associations(ar_parent, association)
137
+ Bullet::Detector::NPlusOneQuery.call_association(ar_parent, association)
138
+ @bullet_eager_loadings[ar_parent.class] ||= {}
139
+ @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
140
+ @bullet_eager_loadings[ar_parent.class][ar_parent] << association
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ super
147
+ end
148
+
149
+ # call join associations
150
+ def construct_model(record, node, row, model_cache, id, strict_loading_value)
151
+ result = super
152
+
153
+ if Bullet.start?
154
+ associations = [node.reflection.name]
155
+ if node.reflection.through_reflection?
156
+ associations << node.reflection.through_reflection.name
157
+ end
158
+ associations.each do |association|
159
+ Bullet::Detector::Association.add_object_associations(record, association)
160
+ Bullet::Detector::NPlusOneQuery.call_association(record, association)
161
+ @bullet_eager_loadings[record.class] ||= {}
162
+ @bullet_eager_loadings[record.class][record] ||= Set.new
163
+ @bullet_eager_loadings[record.class][record] << association
164
+ end
165
+ end
166
+
167
+ result
168
+ end
169
+ end
170
+ )
171
+
172
+ ::ActiveRecord::Associations::Association.prepend(
173
+ Module.new do
174
+ def inversed_from(record)
175
+ if Bullet.start?
176
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
177
+ end
178
+ super
179
+ end
180
+ end
181
+ )
182
+
183
+ ::ActiveRecord::Associations::CollectionAssociation.prepend(
184
+ Module.new do
185
+ def load_target
186
+ records = super
187
+
188
+ if Bullet.start?
189
+ if is_a? ::ActiveRecord::Associations::ThroughAssociation
190
+ association = owner.association(reflection.through_reflection.name)
191
+ if association.loaded?
192
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
193
+ Array.wrap(association.target).each do |through_record|
194
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
195
+ end
196
+
197
+ if reflection.through_reflection != through_reflection
198
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
199
+ end
200
+ end
201
+ end
202
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
203
+ if records.first.class.name !~ /^HABTM_/
204
+ if records.size > 1
205
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
206
+ Bullet::Detector::CounterCache.add_possible_objects(records)
207
+ elsif records.size == 1
208
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
209
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
210
+ end
211
+ end
212
+ end
213
+ records
214
+ end
215
+
216
+ def empty?
217
+ if Bullet.start? && !reflection.has_cached_counter?
218
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
219
+ end
220
+ super
221
+ end
222
+
223
+ def include?(object)
224
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
225
+ super
226
+ end
227
+ end
228
+ )
229
+
230
+ ::ActiveRecord::Associations::SingularAssociation.prepend(
231
+ Module.new do
232
+ # call has_one and belongs_to associations
233
+ def target
234
+ result = super()
235
+
236
+ if Bullet.start?
237
+ if owner.class.name !~ /^HABTM_/ && !@inversed
238
+ if is_a? ::ActiveRecord::Associations::ThroughAssociation
239
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
240
+ association = owner.association(reflection.through_reflection.name)
241
+ Array.wrap(association.target).each do |through_record|
242
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
243
+ end
244
+
245
+ if reflection.through_reflection != through_reflection
246
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
247
+ end
248
+ end
249
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
250
+
251
+ if Bullet::Detector::NPlusOneQuery.impossible?(owner)
252
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
253
+ else
254
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
255
+ end
256
+ end
257
+ end
258
+ result
259
+ end
260
+ end
261
+ )
262
+
263
+ ::ActiveRecord::Associations::HasManyAssociation.prepend(
264
+ Module.new do
265
+ def empty?
266
+ result = super
267
+ if Bullet.start? && !reflection.has_cached_counter?
268
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
269
+ end
270
+ result
271
+ end
272
+
273
+ def count_records
274
+ result = reflection.has_cached_counter?
275
+ if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
276
+ Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
277
+ end
278
+ super
279
+ end
280
+ end
281
+ )
282
+
283
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
284
+ Module.new do
285
+ def count(column_name = nil)
286
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
287
+ Bullet::Detector::CounterCache.add_counter_cache(
288
+ proxy_association.owner,
289
+ proxy_association.reflection.name
290
+ )
291
+ Bullet::Detector::NPlusOneQuery.call_association(
292
+ proxy_association.owner,
293
+ proxy_association.reflection.name
294
+ )
295
+ end
296
+ super(column_name)
297
+ end
298
+ end
299
+ )
300
+ end
301
+ end
302
+ end