bullet 5.7.0 → 5.8.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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -1
  3. data/Gemfile.rails-5.2 +1 -1
  4. data/Guardfile +1 -1
  5. data/README.md +9 -4
  6. data/Rakefile +5 -5
  7. data/bullet.gemspec +11 -6
  8. data/lib/bullet/active_record4.rb +18 -14
  9. data/lib/bullet/active_record41.rb +16 -14
  10. data/lib/bullet/active_record42.rb +24 -22
  11. data/lib/bullet/active_record5.rb +78 -49
  12. data/lib/bullet/active_record52.rb +47 -40
  13. data/lib/bullet/dependency.rb +3 -1
  14. data/lib/bullet/detector/association.rb +16 -14
  15. data/lib/bullet/detector/base.rb +2 -0
  16. data/lib/bullet/detector/counter_cache.rb +10 -7
  17. data/lib/bullet/detector/n_plus_one_query.rb +17 -15
  18. data/lib/bullet/detector/unused_eager_loading.rb +26 -21
  19. data/lib/bullet/detector.rb +2 -0
  20. data/lib/bullet/ext/object.rb +6 -4
  21. data/lib/bullet/ext/string.rb +3 -1
  22. data/lib/bullet/mongoid4x.rb +7 -2
  23. data/lib/bullet/mongoid5x.rb +7 -2
  24. data/lib/bullet/mongoid6x.rb +11 -6
  25. data/lib/bullet/notification/base.rb +21 -15
  26. data/lib/bullet/notification/counter_cache.rb +2 -0
  27. data/lib/bullet/notification/n_plus_one_query.rb +6 -4
  28. data/lib/bullet/notification/unused_eager_loading.rb +6 -4
  29. data/lib/bullet/notification.rb +2 -0
  30. data/lib/bullet/notification_collector.rb +2 -1
  31. data/lib/bullet/rack.rb +19 -15
  32. data/lib/bullet/registry/association.rb +2 -0
  33. data/lib/bullet/registry/base.rb +2 -0
  34. data/lib/bullet/registry/object.rb +2 -0
  35. data/lib/bullet/registry.rb +2 -0
  36. data/lib/bullet/stack_trace_filter.rb +56 -19
  37. data/lib/bullet/version.rb +2 -1
  38. data/lib/bullet.rb +31 -29
  39. data/lib/generators/bullet/install_generator.rb +5 -3
  40. data/perf/benchmark.rb +9 -7
  41. data/rails/init.rb +2 -0
  42. data/spec/bullet/detector/association_spec.rb +2 -0
  43. data/spec/bullet/detector/base_spec.rb +2 -0
  44. data/spec/bullet/detector/counter_cache_spec.rb +2 -0
  45. data/spec/bullet/detector/n_plus_one_query_spec.rb +33 -8
  46. data/spec/bullet/detector/unused_eager_loading_spec.rb +2 -0
  47. data/spec/bullet/ext/object_spec.rb +3 -1
  48. data/spec/bullet/ext/string_spec.rb +2 -0
  49. data/spec/bullet/notification/base_spec.rb +8 -6
  50. data/spec/bullet/notification/counter_cache_spec.rb +3 -1
  51. data/spec/bullet/notification/n_plus_one_query_spec.rb +3 -1
  52. data/spec/bullet/notification/unused_eager_loading_spec.rb +3 -1
  53. data/spec/bullet/notification_collector_spec.rb +2 -0
  54. data/spec/bullet/rack_spec.rb +10 -9
  55. data/spec/bullet/registry/association_spec.rb +4 -2
  56. data/spec/bullet/registry/base_spec.rb +5 -3
  57. data/spec/bullet/registry/object_spec.rb +2 -0
  58. data/spec/bullet_spec.rb +9 -7
  59. data/spec/integration/active_record/association_spec.rb +79 -17
  60. data/spec/integration/counter_cache_spec.rb +4 -2
  61. data/spec/integration/mongoid/association_spec.rb +2 -0
  62. data/spec/models/address.rb +2 -0
  63. data/spec/models/author.rb +2 -0
  64. data/spec/models/base_user.rb +2 -0
  65. data/spec/models/category.rb +2 -0
  66. data/spec/models/city.rb +2 -0
  67. data/spec/models/client.rb +4 -0
  68. data/spec/models/comment.rb +2 -0
  69. data/spec/models/company.rb +2 -0
  70. data/spec/models/country.rb +2 -0
  71. data/spec/models/document.rb +2 -0
  72. data/spec/models/entry.rb +2 -0
  73. data/spec/models/firm.rb +3 -0
  74. data/spec/models/folder.rb +2 -0
  75. data/spec/models/group.rb +4 -0
  76. data/spec/models/mongoid/address.rb +3 -1
  77. data/spec/models/mongoid/category.rb +4 -2
  78. data/spec/models/mongoid/comment.rb +3 -1
  79. data/spec/models/mongoid/company.rb +3 -1
  80. data/spec/models/mongoid/entry.rb +3 -1
  81. data/spec/models/mongoid/post.rb +6 -4
  82. data/spec/models/mongoid/user.rb +2 -0
  83. data/spec/models/newspaper.rb +2 -0
  84. data/spec/models/page.rb +2 -0
  85. data/spec/models/person.rb +2 -0
  86. data/spec/models/pet.rb +2 -0
  87. data/spec/models/post.rb +17 -0
  88. data/spec/models/relationship.rb +2 -0
  89. data/spec/models/reply.rb +2 -0
  90. data/spec/models/student.rb +2 -0
  91. data/spec/models/submission.rb +2 -0
  92. data/spec/models/teacher.rb +2 -0
  93. data/spec/models/user.rb +2 -0
  94. data/spec/models/writer.rb +2 -0
  95. data/spec/spec_helper.rb +3 -1
  96. data/spec/support/bullet_ext.rb +2 -0
  97. data/spec/support/mongo_seed.rb +32 -30
  98. data/spec/support/rack_double.rb +9 -16
  99. data/spec/support/sqlite_seed.rb +84 -75
  100. data/tasks/bullet_tasks.rake +2 -0
  101. metadata +11 -7
@@ -1,16 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module SaveWithBulletSupport
3
- def save(*args)
4
- was_new_record = new_record?
5
- super(*args).tap do |result|
6
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
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 |klazz, eager_loadings_hash|
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
- if id.nil?
116
- associations = node.reflection.name
117
- Bullet::Detector::Association.add_object_associations(ar_parent, associations)
118
- Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
119
- @bullet_eager_loadings[ar_parent.class] ||= {}
120
- @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
121
- @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
122
- end
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 self.is_a? ::ActiveRecord::Associations::ThroughAssociation
153
- Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
154
- association = self.owner.association self.through_reflection.name
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,19 @@ module Bullet
214
214
 
215
215
  def count_records
216
216
  result = reflection.has_cached_counter?
217
- if Bullet.start? && !result && !self.is_a?(::ActiveRecord::Associations::ThroughAssociation)
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
+
224
+ ::ActiveRecord::Associations::BelongsToAssociation.prepend(Module.new do
225
+ def writer(record)
226
+ Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
227
+ super
228
+ end
229
+ end)
223
230
  end
224
231
  end
225
232
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Dependency
3
5
  def mongoid?
@@ -27,7 +29,7 @@ module Bullet
27
29
  elsif active_record52?
28
30
  'active_record52'
29
31
  else
30
- raise "Bullet does not support active_record #{::ActiveRecord::VERSION} yet"
32
+ raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
31
33
  end
32
34
  end
33
35
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  class Association < Base
@@ -7,7 +9,7 @@ module Bullet
7
9
  return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
8
10
  return unless object.primary_key_value
9
11
 
10
- Bullet.debug('Detector::Association#add_object_associations'.freeze, "object: #{object.bullet_key}, associations: #{associations}")
12
+ Bullet.debug('Detector::Association#add_object_associations', "object: #{object.bullet_key}, associations: #{associations}")
11
13
  object_associations.add(object.bullet_key, associations)
12
14
  end
13
15
 
@@ -16,7 +18,7 @@ module Bullet
16
18
  return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
17
19
  return unless object.primary_key_value
18
20
 
19
- Bullet.debug('Detector::Association#add_call_object_associations'.freeze, "object: #{object.bullet_key}, associations: #{associations}")
21
+ Bullet.debug('Detector::Association#add_call_object_associations', "object: #{object.bullet_key}, associations: #{associations}")
20
22
  call_object_associations.add(object.bullet_key, associations)
21
23
  end
22
24
 
@@ -43,31 +45,31 @@ module Bullet
43
45
  # e.g. { "Post:1" => [:comments] }
44
46
  # the object_associations keep all associations that may be or may no be
45
47
  # unpreload associations or unused preload associations.
46
- def object_associations
47
- Thread.current[:bullet_object_associations]
48
- end
48
+ def object_associations
49
+ Thread.current[:bullet_object_associations]
50
+ end
49
51
 
50
52
  # call_object_associations keep the object relationships
51
53
  # that object.associations is called.
52
54
  # e.g. { "Post:1" => [:comments] }
53
55
  # they are used to detect unused preload associations.
54
- def call_object_associations
55
- Thread.current[:bullet_call_object_associations]
56
- end
56
+ def call_object_associations
57
+ Thread.current[:bullet_call_object_associations]
58
+ end
57
59
 
58
60
  # inversed_objects keeps object relationships
59
61
  # that association is inversed.
60
62
  # e.g. { "Comment:1" => ["post"] }
61
- def inversed_objects
62
- Thread.current[:bullet_inversed_objects]
63
- end
63
+ def inversed_objects
64
+ Thread.current[:bullet_inversed_objects]
65
+ end
64
66
 
65
67
  # eager_loadings keep the object relationships
66
68
  # that the associations are preloaded by find :include.
67
69
  # e.g. { ["Post:1", "Post:2"] => [:comments, :user] }
68
- def eager_loadings
69
- Thread.current[:bullet_eager_loadings]
70
- end
70
+ def eager_loadings
71
+ Thread.current[:bullet_eager_loadings]
72
+ end
71
73
  end
72
74
  end
73
75
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  class Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  class CounterCache < Base
@@ -16,6 +18,7 @@ module Bullet
16
18
  def add_possible_objects(object_or_objects)
17
19
  return unless Bullet.start?
18
20
  return unless Bullet.counter_cache_enable?
21
+
19
22
  objects = Array(object_or_objects)
20
23
  return if objects.map(&:primary_key_value).compact.empty?
21
24
 
@@ -32,7 +35,7 @@ module Bullet
32
35
  impossible_objects.add object.bullet_key
33
36
  end
34
37
 
35
- def conditions_met?(object, associations)
38
+ def conditions_met?(object, _associations)
36
39
  possible_objects.include?(object.bullet_key) && !impossible_objects.include?(object.bullet_key)
37
40
  end
38
41
 
@@ -46,14 +49,14 @@ module Bullet
46
49
 
47
50
  private
48
51
 
49
- def create_notification(klazz, associations)
50
- notify_associations = Array(associations) - Bullet.get_whitelist_associations(:counter_cache, klazz)
52
+ def create_notification(klazz, associations)
53
+ notify_associations = Array(associations) - Bullet.get_whitelist_associations(:counter_cache, klazz)
51
54
 
52
- if notify_associations.present?
53
- notice = Bullet::Notification::CounterCache.new klazz, notify_associations
54
- Bullet.notification_collector.add notice
55
- end
55
+ if notify_associations.present?
56
+ notice = Bullet::Notification::CounterCache.new klazz, notify_associations
57
+ Bullet.notification_collector.add notice
56
58
  end
59
+ end
57
60
  end
58
61
  end
59
62
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  class NPlusOneQuery < Association
@@ -14,9 +16,10 @@ module Bullet
14
16
  return unless Bullet.n_plus_one_query_enable?
15
17
  return unless object.primary_key_value
16
18
  return if inversed_objects.include?(object.bullet_key, associations)
19
+
17
20
  add_call_object_associations(object, associations)
18
21
 
19
- Bullet.debug('Detector::NPlusOneQuery#call_association'.freeze, "object: #{object.bullet_key}, associations: #{associations}")
22
+ Bullet.debug('Detector::NPlusOneQuery#call_association', "object: #{object.bullet_key}, associations: #{associations}")
20
23
  if !excluded_stacktrace_path? && conditions_met?(object, associations)
21
24
  Bullet.debug('detect n + 1 query', "object: #{object.bullet_key}, associations: #{associations}")
22
25
  create_notification caller_in_project, object.class.to_s, associations
@@ -26,10 +29,11 @@ module Bullet
26
29
  def add_possible_objects(object_or_objects)
27
30
  return unless Bullet.start?
28
31
  return unless Bullet.n_plus_one_query_enable?
32
+
29
33
  objects = Array(object_or_objects)
30
34
  return if objects.map(&:primary_key_value).compact.empty?
31
35
 
32
- Bullet.debug('Detector::NPlusOneQuery#add_possible_objects'.freeze, "objects: #{objects.map(&:bullet_key).join(', '.freeze)}")
36
+ Bullet.debug('Detector::NPlusOneQuery#add_possible_objects', "objects: #{objects.map(&:bullet_key).join(', ')}")
33
37
  objects.each { |object| possible_objects.add object.bullet_key }
34
38
  end
35
39
 
@@ -38,7 +42,7 @@ module Bullet
38
42
  return unless Bullet.n_plus_one_query_enable?
39
43
  return unless object.primary_key_value
40
44
 
41
- Bullet.debug('Detector::NPlusOneQuery#add_impossible_object'.freeze, "object: #{object.bullet_key}")
45
+ Bullet.debug('Detector::NPlusOneQuery#add_impossible_object', "object: #{object.bullet_key}")
42
46
  impossible_objects.add object.bullet_key
43
47
  end
44
48
 
@@ -47,7 +51,7 @@ module Bullet
47
51
  return unless Bullet.n_plus_one_query_enable?
48
52
  return unless object.primary_key_value
49
53
 
50
- Bullet.debug('Detector::NPlusOneQuery#add_inversed_object'.freeze, "object: #{object.bullet_key}, association: #{association}")
54
+ Bullet.debug('Detector::NPlusOneQuery#add_inversed_object', "object: #{object.bullet_key}, association: #{association}")
51
55
  inversed_objects.add object.bullet_key, association
52
56
  end
53
57
 
@@ -67,14 +71,12 @@ module Bullet
67
71
  # check if object => associations already exists in object_associations.
68
72
  def association?(object, associations)
69
73
  value = object_associations[object.bullet_key]
70
- if value
71
- value.each do |v|
74
+ value&.each do |v|
72
75
  # associations == v comparison order is important here because
73
76
  # v variable might be a squeel node where :== method is redefined,
74
77
  # so it does not compare values at all and return unexpected results
75
- result = v.is_a?(Hash) ? v.key?(associations) : associations == v
76
- return true if result
77
- end
78
+ result = v.is_a?(Hash) ? v.key?(associations) : associations == v
79
+ return true if result
78
80
  end
79
81
 
80
82
  false
@@ -82,14 +84,14 @@ module Bullet
82
84
 
83
85
  private
84
86
 
85
- def create_notification(callers, klazz, associations)
86
- notify_associations = Array(associations) - Bullet.get_whitelist_associations(:n_plus_one_query, klazz)
87
+ def create_notification(callers, klazz, associations)
88
+ notify_associations = Array(associations) - Bullet.get_whitelist_associations(:n_plus_one_query, klazz)
87
89
 
88
- if notify_associations.present?
89
- notice = Bullet::Notification::NPlusOneQuery.new(callers, klazz, notify_associations)
90
- Bullet.notification_collector.add(notice)
91
- end
90
+ if notify_associations.present?
91
+ notice = Bullet::Notification::NPlusOneQuery.new(callers, klazz, notify_associations)
92
+ Bullet.notification_collector.add(notice)
92
93
  end
94
+ end
93
95
  end
94
96
  end
95
97
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  class UnusedEagerLoading < Association
@@ -30,13 +32,15 @@ module Bullet
30
32
  Bullet.debug('Detector::UnusedEagerLoading#add_eager_loadings', "objects: #{objects.map(&:bullet_key).join(', ')}, associations: #{associations}")
31
33
  bullet_keys = objects.map(&:bullet_key)
32
34
 
33
- to_add, to_merge, to_delete = [], [], []
34
- eager_loadings.each do |k, v|
35
+ to_add = []
36
+ to_merge = []
37
+ to_delete = []
38
+ eager_loadings.each do |k, _v|
35
39
  key_objects_overlap = k & bullet_keys
36
40
 
37
41
  next if key_objects_overlap.empty?
38
42
 
39
- bullet_keys = bullet_keys - k
43
+ bullet_keys -= k
40
44
  if key_objects_overlap == k
41
45
  to_add << [k, associations]
42
46
  else
@@ -57,29 +61,30 @@ module Bullet
57
61
 
58
62
  private
59
63
 
60
- def create_notification(callers, klazz, associations)
61
- notify_associations = Array(associations) - Bullet.get_whitelist_associations(:unused_eager_loading, klazz)
64
+ def create_notification(callers, klazz, associations)
65
+ notify_associations = Array(associations) - Bullet.get_whitelist_associations(:unused_eager_loading, klazz)
62
66
 
63
- if notify_associations.present?
64
- notice = Bullet::Notification::UnusedEagerLoading.new(callers, klazz, notify_associations)
65
- Bullet.notification_collector.add(notice)
66
- end
67
+ if notify_associations.present?
68
+ notice = Bullet::Notification::UnusedEagerLoading.new(callers, klazz, notify_associations)
69
+ Bullet.notification_collector.add(notice)
67
70
  end
71
+ end
68
72
 
69
- def call_associations(bullet_key, associations)
70
- all = Set.new
71
- eager_loadings.similarly_associated(bullet_key, associations).each do |related_bullet_key|
72
- coa = call_object_associations[related_bullet_key]
73
- next if coa.nil?
74
- all.merge coa
75
- end
76
- all.to_a
77
- end
73
+ def call_associations(bullet_key, associations)
74
+ all = Set.new
75
+ eager_loadings.similarly_associated(bullet_key, associations).each do |related_bullet_key|
76
+ coa = call_object_associations[related_bullet_key]
77
+ next if coa.nil?
78
78
 
79
- def diff_object_associations(bullet_key, associations)
80
- potential_associations = associations - call_associations(bullet_key, associations)
81
- potential_associations.reject { |a| a.is_a?(Hash) }
79
+ all.merge coa
82
80
  end
81
+ all.to_a
82
+ end
83
+
84
+ def diff_object_associations(bullet_key, associations)
85
+ potential_associations = associations - call_associations(bullet_key, associations)
86
+ potential_associations.reject { |a| a.is_a?(Hash) }
87
+ end
83
88
  end
84
89
  end
85
90
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  autoload :Base, 'bullet/detector/base'
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Object
2
4
  def bullet_key
3
- "#{self.class}:#{self.primary_key_value}"
5
+ "#{self.class}:#{primary_key_value}"
4
6
  end
5
7
 
6
8
  def primary_key_value
7
9
  if self.class.respond_to?(:primary_keys) && self.class.primary_keys
8
- self.class.primary_keys.map { |primary_key| self.send primary_key }.join(','.freeze)
10
+ self.class.primary_keys.map { |primary_key| send primary_key }.join(',')
9
11
  elsif self.class.respond_to?(:primary_key) && self.class.primary_key
10
- self.send self.class.primary_key
12
+ send self.class.primary_key
11
13
  else
12
- self.id
14
+ id
13
15
  end
14
16
  end
15
17
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  def bullet_class_name
3
- self.sub(/:[^:]*?$/, ''.freeze)
5
+ sub(/:[^:]*?$/, '')
4
6
  end
5
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Mongoid
3
5
  def self.enable
@@ -21,13 +23,16 @@ module Bullet
21
23
  end
22
24
 
23
25
  def each(&block)
24
- records = query.map { |doc| ::Mongoid::Factory.from_db(klass, doc) }
26
+ return to_enum unless block_given?
27
+
28
+ records = []
29
+ origin_each { |record| records << record }
25
30
  if records.length > 1
26
31
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
27
32
  elsif records.size == 1
28
33
  Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
29
34
  end
30
- origin_each(&block)
35
+ records.each(&block)
31
36
  end
32
37
 
33
38
  def eager_load(docs)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Mongoid
3
5
  def self.enable
@@ -21,13 +23,16 @@ module Bullet
21
23
  end
22
24
 
23
25
  def each(&block)
24
- records = view.map { |doc| ::Mongoid::Factory.from_db(klass, doc) }
26
+ return to_enum unless block_given?
27
+
28
+ records = []
29
+ origin_each { |record| records << record }
25
30
  if records.length > 1
26
31
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
27
32
  elsif records.size == 1
28
33
  Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
29
34
  end
30
- origin_each(&block)
35
+ records.each(&block)
31
36
  end
32
37
 
33
38
  def eager_load(docs)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Mongoid
3
5
  def self.enable
@@ -8,26 +10,29 @@ module Bullet
8
10
  alias_method :origin_each, :each
9
11
  alias_method :origin_eager_load, :eager_load
10
12
 
11
- def first
12
- result = origin_first
13
+ def first(opt = {})
14
+ result = origin_first(opt)
13
15
  Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
14
16
  result
15
17
  end
16
18
 
17
- def last
18
- result = origin_last
19
+ def last(opt = {})
20
+ result = origin_last(opt)
19
21
  Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
20
22
  result
21
23
  end
22
24
 
23
25
  def each(&block)
24
- records = view.map { |doc| ::Mongoid::Factory.from_db(klass, doc) }
26
+ return to_enum unless block_given?
27
+
28
+ records = []
29
+ origin_each { |record| records << record }
25
30
  if records.length > 1
26
31
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
27
32
  elsif records.size == 1
28
33
  Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
29
34
  end
30
- origin_each(&block)
35
+ records.each(&block)
31
36
  end
32
37
 
33
38
  def eager_load(docs)