hyper-pure-sys 0.0.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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/bullet-8.1.3/CHANGELOG.md +374 -0
  3. data/bullet-8.1.3/MIT-LICENSE +20 -0
  4. data/bullet-8.1.3/README.md +525 -0
  5. data/bullet-8.1.3/lib/bullet/active_job.rb +13 -0
  6. data/bullet-8.1.3/lib/bullet/active_record4.rb +197 -0
  7. data/bullet-8.1.3/lib/bullet/active_record41.rb +191 -0
  8. data/bullet-8.1.3/lib/bullet/active_record42.rb +262 -0
  9. data/bullet-8.1.3/lib/bullet/active_record5.rb +294 -0
  10. data/bullet-8.1.3/lib/bullet/active_record52.rb +278 -0
  11. data/bullet-8.1.3/lib/bullet/active_record60.rb +310 -0
  12. data/bullet-8.1.3/lib/bullet/active_record61.rb +310 -0
  13. data/bullet-8.1.3/lib/bullet/active_record70.rb +319 -0
  14. data/bullet-8.1.3/lib/bullet/active_record71.rb +319 -0
  15. data/bullet-8.1.3/lib/bullet/active_record72.rb +319 -0
  16. data/bullet-8.1.3/lib/bullet/active_record80.rb +319 -0
  17. data/bullet-8.1.3/lib/bullet/active_record81.rb +321 -0
  18. data/bullet-8.1.3/lib/bullet/bullet_xhr.js +64 -0
  19. data/bullet-8.1.3/lib/bullet/dependency.rb +165 -0
  20. data/bullet-8.1.3/lib/bullet/detector/association.rb +92 -0
  21. data/bullet-8.1.3/lib/bullet/detector/base.rb +8 -0
  22. data/bullet-8.1.3/lib/bullet/detector/counter_cache.rb +69 -0
  23. data/bullet-8.1.3/lib/bullet/detector/n_plus_one_query.rb +148 -0
  24. data/bullet-8.1.3/lib/bullet/detector/unused_eager_loading.rb +100 -0
  25. data/bullet-8.1.3/lib/bullet/detector.rb +11 -0
  26. data/bullet-8.1.3/lib/bullet/ext/object.rb +37 -0
  27. data/bullet-8.1.3/lib/bullet/ext/string.rb +14 -0
  28. data/bullet-8.1.3/lib/bullet/mongoid4x.rb +59 -0
  29. data/bullet-8.1.3/lib/bullet/mongoid5x.rb +59 -0
  30. data/bullet-8.1.3/lib/bullet/mongoid6x.rb +59 -0
  31. data/bullet-8.1.3/lib/bullet/mongoid7x.rb +74 -0
  32. data/bullet-8.1.3/lib/bullet/mongoid8x.rb +61 -0
  33. data/bullet-8.1.3/lib/bullet/mongoid9x.rb +74 -0
  34. data/bullet-8.1.3/lib/bullet/notification/base.rb +92 -0
  35. data/bullet-8.1.3/lib/bullet/notification/counter_cache.rb +15 -0
  36. data/bullet-8.1.3/lib/bullet/notification/n_plus_one_query.rb +31 -0
  37. data/bullet-8.1.3/lib/bullet/notification/unused_eager_loading.rb +31 -0
  38. data/bullet-8.1.3/lib/bullet/notification.rb +13 -0
  39. data/bullet-8.1.3/lib/bullet/notification_collector.rb +25 -0
  40. data/bullet-8.1.3/lib/bullet/rack.rb +186 -0
  41. data/bullet-8.1.3/lib/bullet/registry/association.rb +16 -0
  42. data/bullet-8.1.3/lib/bullet/registry/base.rb +46 -0
  43. data/bullet-8.1.3/lib/bullet/registry/call_stack.rb +17 -0
  44. data/bullet-8.1.3/lib/bullet/registry/object.rb +18 -0
  45. data/bullet-8.1.3/lib/bullet/registry.rb +10 -0
  46. data/bullet-8.1.3/lib/bullet/stack_trace_filter.rb +67 -0
  47. data/bullet-8.1.3/lib/bullet/version.rb +5 -0
  48. data/bullet-8.1.3/lib/bullet.rb +289 -0
  49. data/bullet-8.1.3/lib/generators/bullet/install_generator.rb +47 -0
  50. data/bullet-8.1.3/tasks/bullet_tasks.rake +11 -0
  51. data/hyper-pure-sys.gemspec +12 -0
  52. metadata +91 -0
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bullet
4
+ module ActiveRecord
5
+ def self.enable
6
+ require 'active_record'
7
+ ::ActiveRecord::Base.class_eval do
8
+ class << self
9
+ alias_method :origin_find_by_sql, :find_by_sql
10
+ def find_by_sql(sql, binds = [])
11
+ result = origin_find_by_sql(sql, binds)
12
+ if Bullet.start?
13
+ if result.is_a? Array
14
+ if result.size > 1
15
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
16
+ Bullet::Detector::CounterCache.add_possible_objects(result)
17
+ elsif result.size == 1
18
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
19
+ Bullet::Detector::CounterCache.add_impossible_object(result.first)
20
+ end
21
+ elsif result.is_a? ::ActiveRecord::Base
22
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
23
+ Bullet::Detector::CounterCache.add_impossible_object(result)
24
+ end
25
+ end
26
+ result
27
+ end
28
+ end
29
+ end
30
+
31
+ ::ActiveRecord::Relation.class_eval do
32
+ alias_method :origin_to_a, :to_a
33
+ # if select a collection of objects, then these objects have possible to cause N+1 query.
34
+ # if select only one object, then the only one object has impossible to cause N+1 query.
35
+ def to_a
36
+ records = origin_to_a
37
+ if Bullet.start?
38
+ if records.size > 1
39
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
40
+ Bullet::Detector::CounterCache.add_possible_objects(records)
41
+ elsif records.size == 1
42
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
43
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
44
+ end
45
+ end
46
+ records
47
+ end
48
+ end
49
+
50
+ ::ActiveRecord::Persistence.class_eval do
51
+ def _create_record_with_bullet(*args)
52
+ _create_record_without_bullet(*args).tap do
53
+ Bullet::Detector::NPlusOneQuery.update_inversed_object(self)
54
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
55
+ end
56
+ end
57
+ alias_method_chain :_create_record, :bullet
58
+ end
59
+
60
+ ::ActiveRecord::Associations::Preloader.class_eval do
61
+ # include query for one to many associations.
62
+ # keep this eager loadings.
63
+ alias_method :origin_initialize, :initialize
64
+ def initialize(records, associations, preload_scope = nil)
65
+ origin_initialize(records, associations, preload_scope)
66
+
67
+ if Bullet.start?
68
+ records = [records].flatten.compact.uniq
69
+ return if records.empty?
70
+
71
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
72
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
73
+ end
74
+ end
75
+ end
76
+
77
+ ::ActiveRecord::FinderMethods.class_eval do
78
+ # add includes in scope
79
+ alias_method :origin_find_with_associations, :find_with_associations
80
+ def find_with_associations
81
+ records = origin_find_with_associations
82
+ if Bullet.start?
83
+ associations = (eager_load_values + includes_values).uniq
84
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
85
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
86
+ end
87
+ records
88
+ end
89
+ end
90
+
91
+ ::ActiveRecord::Associations::JoinDependency.class_eval do
92
+ alias_method :origin_instantiate, :instantiate
93
+ alias_method :origin_construct_association, :construct_association
94
+
95
+ def instantiate(rows)
96
+ @bullet_eager_loadings = {}
97
+ records = origin_instantiate(rows)
98
+
99
+ if Bullet.start?
100
+ @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
101
+ objects = eager_loadings_hash.keys
102
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
103
+ end
104
+ end
105
+ records
106
+ end
107
+
108
+ # call join associations
109
+ def construct_association(record, join, row)
110
+ result = origin_construct_association(record, join, row)
111
+
112
+ if Bullet.start?
113
+ associations = [join.reflection.name]
114
+ if join.reflection.nested?
115
+ associations << join.reflection.through_reflection.name
116
+ end
117
+ associations.each do |association|
118
+ Bullet::Detector::Association.add_object_associations(record, association)
119
+ Bullet::Detector::NPlusOneQuery.call_association(record, association)
120
+ @bullet_eager_loadings[record.class] ||= {}
121
+ @bullet_eager_loadings[record.class][record] ||= Set.new
122
+ @bullet_eager_loadings[record.class][record] << association
123
+ end
124
+ end
125
+
126
+ result
127
+ end
128
+ end
129
+
130
+ ::ActiveRecord::Associations::CollectionAssociation.class_eval do
131
+ # call one to many associations
132
+ alias_method :origin_load_target, :load_target
133
+ def load_target
134
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start?
135
+ origin_load_target
136
+ end
137
+
138
+ alias_method :origin_include?, :include?
139
+ def include?(object)
140
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start?
141
+ origin_include?(object)
142
+ end
143
+ end
144
+
145
+ ::ActiveRecord::Associations::HasManyAssociation.class_eval do
146
+ alias_method :origin_empty?, :empty?
147
+ def empty?
148
+ if Bullet.start? && !loaded? && !has_cached_counter?(@reflection)
149
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
150
+ end
151
+ origin_empty?
152
+ end
153
+ end
154
+
155
+ ::ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
156
+ alias_method :origin_empty?, :empty?
157
+ def empty?
158
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start? && !loaded?
159
+ origin_empty?
160
+ end
161
+ end
162
+
163
+ ::ActiveRecord::Associations::SingularAssociation.class_eval do
164
+ # call has_one and belongs_to associations
165
+ alias_method :origin_reader, :reader
166
+ def reader(force_reload = false)
167
+ result = origin_reader(force_reload)
168
+ if Bullet.start?
169
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name, inversed: @inversed)
170
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result) unless @inversed
171
+ end
172
+ result
173
+ end
174
+ end
175
+
176
+ ::ActiveRecord::Associations::HasManyAssociation.class_eval do
177
+ alias_method :origin_has_cached_counter?, :has_cached_counter?
178
+
179
+ def has_cached_counter?(reflection = reflection())
180
+ result = origin_has_cached_counter?(reflection)
181
+ Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) if Bullet.start? && !result
182
+ result
183
+ end
184
+ end
185
+
186
+ ::ActiveRecord::Associations::CollectionProxy.class_eval do
187
+ def count(column_name = nil, options = {})
188
+ if Bullet.start?
189
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
190
+ Bullet::Detector::NPlusOneQuery.call_association(proxy_association.owner, proxy_association.reflection.name)
191
+ end
192
+ super(column_name, options)
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bullet
4
+ module ActiveRecord
5
+ def self.enable
6
+ require 'active_record'
7
+ ::ActiveRecord::Base.class_eval do
8
+ class << self
9
+ alias_method :origin_find_by_sql, :find_by_sql
10
+ def find_by_sql(sql, binds = [])
11
+ result = origin_find_by_sql(sql, binds)
12
+ if Bullet.start?
13
+ if result.is_a? Array
14
+ if result.size > 1
15
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
16
+ Bullet::Detector::CounterCache.add_possible_objects(result)
17
+ elsif result.size == 1
18
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
19
+ Bullet::Detector::CounterCache.add_impossible_object(result.first)
20
+ end
21
+ elsif result.is_a? ::ActiveRecord::Base
22
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
23
+ Bullet::Detector::CounterCache.add_impossible_object(result)
24
+ end
25
+ end
26
+ result
27
+ end
28
+ end
29
+ end
30
+
31
+ ::ActiveRecord::Relation.class_eval do
32
+ alias_method :origin_to_a, :to_a
33
+
34
+ # if select a collection of objects, then these objects have possible to cause N+1 query.
35
+ # if select only one object, then the only one object has impossible to cause N+1 query.
36
+ def to_a
37
+ records = origin_to_a
38
+ if Bullet.start?
39
+ if records.first.class.name !~ /^HABTM_/
40
+ if records.size > 1
41
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
42
+ Bullet::Detector::CounterCache.add_possible_objects(records)
43
+ elsif records.size == 1
44
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
45
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
46
+ end
47
+ end
48
+ end
49
+ records
50
+ end
51
+ end
52
+
53
+ ::ActiveRecord::Persistence.class_eval do
54
+ def _create_record_with_bullet(*args)
55
+ _create_record_without_bullet(*args).tap do
56
+ Bullet::Detector::NPlusOneQuery.update_inversed_object(self)
57
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
58
+ end
59
+ end
60
+ alias_method_chain :_create_record, :bullet
61
+ end
62
+
63
+ ::ActiveRecord::Associations::Preloader.class_eval do
64
+ alias_method :origin_preloaders_on, :preloaders_on
65
+
66
+ def preloaders_on(association, records, scope)
67
+ if Bullet.start?
68
+ records.compact!
69
+ if records.first.class.name !~ /^HABTM_/
70
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, association) }
71
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
72
+ end
73
+ end
74
+ origin_preloaders_on(association, records, scope)
75
+ end
76
+ end
77
+
78
+ ::ActiveRecord::FinderMethods.class_eval do
79
+ # add includes in scope
80
+ alias_method :origin_find_with_associations, :find_with_associations
81
+ def find_with_associations
82
+ return origin_find_with_associations { |r| yield r } if block_given?
83
+
84
+ records = origin_find_with_associations
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
+ ::ActiveRecord::Associations::JoinDependency.class_eval do
95
+ alias_method :origin_instantiate, :instantiate
96
+ alias_method :origin_construct_model, :construct_model
97
+
98
+ def instantiate(result_set, aliases)
99
+ @bullet_eager_loadings = {}
100
+ records = origin_instantiate(result_set, aliases)
101
+
102
+ if Bullet.start?
103
+ @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
104
+ objects = eager_loadings_hash.keys
105
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
106
+ end
107
+ end
108
+ records
109
+ end
110
+
111
+ # call join associations
112
+ def construct_model(record, node, row, model_cache, id, aliases)
113
+ result = origin_construct_model(record, node, row, model_cache, id, aliases)
114
+
115
+ if Bullet.start?
116
+ associations = [node.reflection.name]
117
+ if node.reflection.nested?
118
+ associations << node.reflection.through_reflection.name
119
+ end
120
+ associations.each do |association|
121
+ Bullet::Detector::Association.add_object_associations(record, association)
122
+ Bullet::Detector::NPlusOneQuery.call_association(record, association)
123
+ @bullet_eager_loadings[record.class] ||= {}
124
+ @bullet_eager_loadings[record.class][record] ||= Set.new
125
+ @bullet_eager_loadings[record.class][record] << association
126
+ end
127
+ end
128
+
129
+ result
130
+ end
131
+ end
132
+
133
+ ::ActiveRecord::Associations::CollectionAssociation.class_eval do
134
+ # call one to many associations
135
+ alias_method :origin_load_target, :load_target
136
+ def load_target
137
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name, inversed: @inversed) if Bullet.start?
138
+ origin_load_target
139
+ end
140
+
141
+ alias_method :origin_empty?, :empty?
142
+ def empty?
143
+ if Bullet.start? && !has_cached_counter?(@reflection)
144
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
145
+ end
146
+ origin_empty?
147
+ end
148
+
149
+ alias_method :origin_include?, :include?
150
+ def include?(object)
151
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start?
152
+ origin_include?(object)
153
+ end
154
+ end
155
+
156
+ ::ActiveRecord::Associations::SingularAssociation.class_eval do
157
+ # call has_one and belongs_to associations
158
+ alias_method :origin_reader, :reader
159
+ def reader(force_reload = false)
160
+ result = origin_reader(force_reload)
161
+ if Bullet.start?
162
+ if @owner.class.name !~ /^HABTM_/
163
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name, inversed: @inversed)
164
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result) unless @inversed
165
+ end
166
+ end
167
+ result
168
+ end
169
+ end
170
+
171
+ ::ActiveRecord::Associations::HasManyAssociation.class_eval do
172
+ alias_method :origin_count_records, :count_records
173
+ def count_records
174
+ result = has_cached_counter?
175
+ Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) if Bullet.start? && !result
176
+ origin_count_records
177
+ end
178
+ end
179
+
180
+ ::ActiveRecord::Associations::CollectionProxy.class_eval do
181
+ def count(column_name = nil, options = {})
182
+ if Bullet.start?
183
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
184
+ Bullet::Detector::NPlusOneQuery.call_association(proxy_association.owner, proxy_association.reflection.name)
185
+ end
186
+ super(column_name, options)
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,262 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bullet
4
+ module ActiveRecord
5
+ def self.enable
6
+ require 'active_record'
7
+ ::ActiveRecord::Base.class_eval do
8
+ class << self
9
+ alias_method :origin_find, :find
10
+ def find(*args)
11
+ result = origin_find(*args)
12
+ if Bullet.start?
13
+ if result.is_a? Array
14
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
15
+ Bullet::Detector::CounterCache.add_possible_objects(result)
16
+ elsif result.is_a? ::ActiveRecord::Base
17
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
18
+ Bullet::Detector::CounterCache.add_impossible_object(result)
19
+ end
20
+ end
21
+ result
22
+ end
23
+
24
+ alias_method :origin_find_by_sql, :find_by_sql
25
+ def find_by_sql(sql, binds = [])
26
+ result = origin_find_by_sql(sql, binds)
27
+ if Bullet.start?
28
+ if result.is_a? Array
29
+ if result.size > 1
30
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
31
+ Bullet::Detector::CounterCache.add_possible_objects(result)
32
+ elsif result.size == 1
33
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
34
+ Bullet::Detector::CounterCache.add_impossible_object(result.first)
35
+ end
36
+ elsif result.is_a? ::ActiveRecord::Base
37
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
38
+ Bullet::Detector::CounterCache.add_impossible_object(result)
39
+ end
40
+ end
41
+ result
42
+ end
43
+ end
44
+ end
45
+
46
+ ::ActiveRecord::Persistence.class_eval do
47
+ def _create_record_with_bullet(*args)
48
+ _create_record_without_bullet(*args).tap do
49
+ Bullet::Detector::NPlusOneQuery.update_inversed_object(self)
50
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
51
+ end
52
+ end
53
+ alias_method_chain :_create_record, :bullet
54
+ end
55
+
56
+ ::ActiveRecord::Relation.class_eval do
57
+ alias_method :origin_to_a, :to_a
58
+
59
+ # if select a collection of objects, then these objects have possible to cause N+1 query.
60
+ # if select only one object, then the only one object has impossible to cause N+1 query.
61
+ def to_a
62
+ records = origin_to_a
63
+ if Bullet.start?
64
+ if records.first.class.name !~ /^HABTM_/
65
+ if records.size > 1
66
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
67
+ Bullet::Detector::CounterCache.add_possible_objects(records)
68
+ elsif records.size == 1
69
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
70
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
71
+ end
72
+ end
73
+ end
74
+ records
75
+ end
76
+ end
77
+
78
+ ::ActiveRecord::Associations::Preloader.class_eval do
79
+ alias_method :origin_preloaders_on, :preloaders_on
80
+
81
+ def preloaders_on(association, records, scope)
82
+ if Bullet.start?
83
+ records.compact!
84
+ if records.first.class.name !~ /^HABTM_/
85
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, association) }
86
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
87
+ end
88
+ end
89
+ origin_preloaders_on(association, records, scope)
90
+ end
91
+ end
92
+
93
+ ::ActiveRecord::FinderMethods.class_eval do
94
+ # add includes in scope
95
+ alias_method :origin_find_with_associations, :find_with_associations
96
+ def find_with_associations
97
+ return origin_find_with_associations { |r| yield r } if block_given?
98
+
99
+ records = origin_find_with_associations
100
+ if Bullet.start?
101
+ associations = (eager_load_values + includes_values).uniq
102
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
103
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
104
+ end
105
+ records
106
+ end
107
+ end
108
+
109
+ ::ActiveRecord::Associations::JoinDependency.class_eval do
110
+ alias_method :origin_instantiate, :instantiate
111
+ alias_method :origin_construct, :construct
112
+ alias_method :origin_construct_model, :construct_model
113
+
114
+ def instantiate(result_set, aliases)
115
+ @bullet_eager_loadings = {}
116
+ records = origin_instantiate(result_set, aliases)
117
+
118
+ if Bullet.start?
119
+ @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
120
+ objects = eager_loadings_hash.keys
121
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
122
+ end
123
+ end
124
+ records
125
+ end
126
+
127
+ def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
128
+ if Bullet.start?
129
+ unless ar_parent.nil?
130
+ parent.children.each do |node|
131
+ key = aliases.column_alias(node, node.primary_key)
132
+ id = row[key]
133
+ next unless id.nil?
134
+
135
+ associations = [node.reflection.name]
136
+ if node.reflection.nested?
137
+ associations << node.reflection.through_reflection.name
138
+ end
139
+ associations.each do |association|
140
+ Bullet::Detector::Association.add_object_associations(ar_parent, association)
141
+ Bullet::Detector::NPlusOneQuery.call_association(ar_parent, association)
142
+ @bullet_eager_loadings[ar_parent.class] ||= {}
143
+ @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
144
+ @bullet_eager_loadings[ar_parent.class][ar_parent] << association
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ origin_construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
151
+ end
152
+
153
+ # call join associations
154
+ def construct_model(record, node, row, model_cache, id, aliases)
155
+ result = origin_construct_model(record, node, row, model_cache, id, aliases)
156
+
157
+ if Bullet.start?
158
+ associations = [node.reflection.name]
159
+ if node.reflection.nested?
160
+ associations << node.reflection.through_reflection.name
161
+ end
162
+ associations.each do |association|
163
+ Bullet::Detector::Association.add_object_associations(record, association)
164
+ Bullet::Detector::NPlusOneQuery.call_association(record, association)
165
+ @bullet_eager_loadings[record.class] ||= {}
166
+ @bullet_eager_loadings[record.class][record] ||= Set.new
167
+ @bullet_eager_loadings[record.class][record] << association
168
+ end
169
+ end
170
+
171
+ result
172
+ end
173
+ end
174
+
175
+ ::ActiveRecord::Associations::CollectionAssociation.class_eval do
176
+ # call one to many associations
177
+ alias_method :origin_load_target, :load_target
178
+ def load_target
179
+ records = origin_load_target
180
+
181
+ if Bullet.start?
182
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name, inversed: @inversed)
183
+ if records.first.class.name !~ /^HABTM_/
184
+ if records.size > 1
185
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
186
+ Bullet::Detector::CounterCache.add_possible_objects(records)
187
+ elsif records.size == 1
188
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
189
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
190
+ end
191
+ end
192
+ end
193
+ records
194
+ end
195
+
196
+ alias_method :origin_empty?, :empty?
197
+ def empty?
198
+ if Bullet.start? && !has_cached_counter?(@reflection)
199
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
200
+ end
201
+ origin_empty?
202
+ end
203
+
204
+ alias_method :origin_include?, :include?
205
+ def include?(object)
206
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start?
207
+ origin_include?(object)
208
+ end
209
+ end
210
+
211
+ ::ActiveRecord::Associations::SingularAssociation.class_eval do
212
+ # call has_one and belongs_to associations
213
+ alias_method :origin_reader, :reader
214
+ def reader(force_reload = false)
215
+ result = origin_reader(force_reload)
216
+
217
+ if Bullet.start?
218
+ if @owner.class.name !~ /^HABTM_/
219
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name, inversed: @inversed)
220
+ unless @inversed
221
+ if Bullet::Detector::NPlusOneQuery.impossible?(@owner)
222
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
223
+ else
224
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
225
+ end
226
+ end
227
+ end
228
+ end
229
+ result
230
+ end
231
+ end
232
+
233
+ ::ActiveRecord::Associations::HasManyAssociation.class_eval do
234
+ alias_method :origin_many_empty?, :empty?
235
+ def empty?
236
+ result = origin_many_empty?
237
+ if Bullet.start? && !has_cached_counter?(@reflection)
238
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
239
+ end
240
+ result
241
+ end
242
+
243
+ alias_method :origin_count_records, :count_records
244
+ def count_records
245
+ result = has_cached_counter?
246
+ Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) if Bullet.start? && !result
247
+ origin_count_records
248
+ end
249
+ end
250
+
251
+ ::ActiveRecord::Associations::CollectionProxy.class_eval do
252
+ def count(column_name = nil, options = {})
253
+ if Bullet.start?
254
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
255
+ Bullet::Detector::NPlusOneQuery.call_association(proxy_association.owner, proxy_association.reflection.name)
256
+ end
257
+ super(column_name, options)
258
+ end
259
+ end
260
+ end
261
+ end
262
+ end