bullet 8.0.8 → 8.2.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 +4 -4
- data/CHANGELOG.md +31 -1
- data/README.md +29 -11
- data/lib/bullet/active_record70.rb +20 -6
- data/lib/bullet/active_record71.rb +20 -6
- data/lib/bullet/active_record72.rb +20 -6
- data/lib/bullet/active_record80.rb +20 -6
- data/lib/bullet/{active_record60.rb → active_record81.rb} +67 -35
- data/lib/bullet/dependency.rb +10 -58
- data/lib/bullet/detector/association.rb +2 -2
- data/lib/bullet/detector/n_plus_one_query.rb +22 -3
- data/lib/bullet/detector/unused_eager_loading.rb +1 -1
- data/lib/bullet/mongoid4x.rb +2 -0
- data/lib/bullet/mongoid5x.rb +2 -0
- data/lib/bullet/mongoid6x.rb +2 -0
- data/lib/bullet/mongoid7x.rb +2 -0
- data/lib/bullet/mongoid8x.rb +2 -0
- data/lib/bullet/mongoid9x.rb +2 -0
- data/lib/bullet/rack.rb +35 -2
- data/lib/bullet/registry/call_stack.rb +7 -2
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +26 -1
- metadata +31 -9
- data/lib/bullet/active_record4.rb +0 -199
- data/lib/bullet/active_record41.rb +0 -191
- data/lib/bullet/active_record42.rb +0 -261
- data/lib/bullet/active_record5.rb +0 -294
- data/lib/bullet/active_record52.rb +0 -276
- data/lib/bullet/active_record61.rb +0 -303
data/lib/bullet/dependency.rb
CHANGED
|
@@ -13,22 +13,8 @@ module Bullet
|
|
|
13
13
|
def active_record_version
|
|
14
14
|
@active_record_version ||=
|
|
15
15
|
begin
|
|
16
|
-
if
|
|
17
|
-
|
|
18
|
-
elsif active_record41?
|
|
19
|
-
'active_record41'
|
|
20
|
-
elsif active_record42?
|
|
21
|
-
'active_record42'
|
|
22
|
-
elsif active_record50?
|
|
23
|
-
'active_record5'
|
|
24
|
-
elsif active_record51?
|
|
25
|
-
'active_record5'
|
|
26
|
-
elsif active_record52?
|
|
27
|
-
'active_record52'
|
|
28
|
-
elsif active_record60?
|
|
29
|
-
'active_record60'
|
|
30
|
-
elsif active_record61?
|
|
31
|
-
'active_record61'
|
|
16
|
+
if active_record6_or_older?
|
|
17
|
+
raise "Bullet no longer supports active_record #{::ActiveRecord::VERSION::STRING}"
|
|
32
18
|
elsif active_record70?
|
|
33
19
|
'active_record70'
|
|
34
20
|
elsif active_record71?
|
|
@@ -37,6 +23,8 @@ module Bullet
|
|
|
37
23
|
'active_record72'
|
|
38
24
|
elsif active_record80?
|
|
39
25
|
'active_record80'
|
|
26
|
+
elsif active_record81?
|
|
27
|
+
'active_record81'
|
|
40
28
|
else
|
|
41
29
|
raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
|
|
42
30
|
end
|
|
@@ -64,16 +52,8 @@ module Bullet
|
|
|
64
52
|
end
|
|
65
53
|
end
|
|
66
54
|
|
|
67
|
-
def
|
|
68
|
-
active_record? && ::ActiveRecord::VERSION::MAJOR
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def active_record5?
|
|
72
|
-
active_record? && ::ActiveRecord::VERSION::MAJOR == 5
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def active_record6?
|
|
76
|
-
active_record? && ::ActiveRecord::VERSION::MAJOR == 6
|
|
55
|
+
def active_record6_or_older?
|
|
56
|
+
active_record? && ::ActiveRecord::VERSION::MAJOR < 7
|
|
77
57
|
end
|
|
78
58
|
|
|
79
59
|
def active_record7?
|
|
@@ -84,38 +64,6 @@ module Bullet
|
|
|
84
64
|
active_record? && ::ActiveRecord::VERSION::MAJOR == 8
|
|
85
65
|
end
|
|
86
66
|
|
|
87
|
-
def active_record40?
|
|
88
|
-
active_record4? && ::ActiveRecord::VERSION::MINOR == 0
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def active_record41?
|
|
92
|
-
active_record4? && ::ActiveRecord::VERSION::MINOR == 1
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def active_record42?
|
|
96
|
-
active_record4? && ::ActiveRecord::VERSION::MINOR == 2
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def active_record50?
|
|
100
|
-
active_record5? && ::ActiveRecord::VERSION::MINOR == 0
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def active_record51?
|
|
104
|
-
active_record5? && ::ActiveRecord::VERSION::MINOR == 1
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def active_record52?
|
|
108
|
-
active_record5? && ::ActiveRecord::VERSION::MINOR == 2
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def active_record60?
|
|
112
|
-
active_record6? && ::ActiveRecord::VERSION::MINOR == 0
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def active_record61?
|
|
116
|
-
active_record6? && ::ActiveRecord::VERSION::MINOR == 1
|
|
117
|
-
end
|
|
118
|
-
|
|
119
67
|
def active_record70?
|
|
120
68
|
active_record7? && ::ActiveRecord::VERSION::MINOR == 0
|
|
121
69
|
end
|
|
@@ -132,6 +80,10 @@ module Bullet
|
|
|
132
80
|
active_record8? && ::ActiveRecord::VERSION::MINOR == 0
|
|
133
81
|
end
|
|
134
82
|
|
|
83
|
+
def active_record81?
|
|
84
|
+
active_record8? && ::ActiveRecord::VERSION::MINOR == 1
|
|
85
|
+
end
|
|
86
|
+
|
|
135
87
|
def mongoid4x?
|
|
136
88
|
mongoid? && ::Mongoid::VERSION =~ /\A4/
|
|
137
89
|
end
|
|
@@ -8,7 +8,7 @@ module Bullet
|
|
|
8
8
|
class << self
|
|
9
9
|
def add_object_associations(object, associations)
|
|
10
10
|
return unless Bullet.start?
|
|
11
|
-
return
|
|
11
|
+
return unless Bullet.n_plus_one_query_enable? || Bullet.unused_eager_loading_enable?
|
|
12
12
|
return unless object.bullet_primary_key_value
|
|
13
13
|
|
|
14
14
|
Bullet.debug(
|
|
@@ -21,7 +21,7 @@ module Bullet
|
|
|
21
21
|
|
|
22
22
|
def add_call_object_associations(object, associations)
|
|
23
23
|
return unless Bullet.start?
|
|
24
|
-
return
|
|
24
|
+
return unless Bullet.n_plus_one_query_enable? || Bullet.unused_eager_loading_enable?
|
|
25
25
|
return unless object.bullet_primary_key_value
|
|
26
26
|
|
|
27
27
|
Bullet.debug(
|
|
@@ -13,13 +13,19 @@ module Bullet
|
|
|
13
13
|
# first, it keeps this method call for object.association.
|
|
14
14
|
# then, it checks if this associations call is unpreload.
|
|
15
15
|
# if it is, keeps this unpreload associations and caller.
|
|
16
|
-
def call_association(object, associations)
|
|
16
|
+
def call_association(object, associations, caller_stack = nil, inversed: false)
|
|
17
17
|
return unless Bullet.start?
|
|
18
|
-
return unless Bullet.n_plus_one_query_enable?
|
|
18
|
+
return unless Bullet.n_plus_one_query_enable? || Bullet.unused_eager_loading_enable?
|
|
19
19
|
return unless object.bullet_primary_key_value
|
|
20
|
-
return if inversed_objects.include?(object.bullet_key, associations)
|
|
21
20
|
|
|
21
|
+
# Record before early-returns so legitimate reads that bypass SQL
|
|
22
|
+
# (inversed, nil-polymorphic) aren't flagged as unused preloads.
|
|
22
23
|
add_call_object_associations(object, associations)
|
|
24
|
+
call_stacks.add(object.bullet_key, caller_stack) if caller_stack
|
|
25
|
+
|
|
26
|
+
return if inversed
|
|
27
|
+
return if inversed_objects.include?(object.bullet_key, associations)
|
|
28
|
+
return if optional_polymorphic_belongs_to_with_nil_type?(object, associations)
|
|
23
29
|
|
|
24
30
|
Bullet.debug(
|
|
25
31
|
'Detector::NPlusOneQuery#call_association',
|
|
@@ -115,6 +121,19 @@ module Bullet
|
|
|
115
121
|
|
|
116
122
|
private
|
|
117
123
|
|
|
124
|
+
def optional_polymorphic_belongs_to_with_nil_type?(object, associations)
|
|
125
|
+
return false unless associations.is_a?(Symbol) || associations.is_a?(String)
|
|
126
|
+
return false unless object.class.respond_to?(:reflect_on_association)
|
|
127
|
+
|
|
128
|
+
reflection = object.class.reflect_on_association(associations.to_sym)
|
|
129
|
+
return false unless reflection
|
|
130
|
+
return false unless reflection.respond_to?(:polymorphic?) && reflection.polymorphic?
|
|
131
|
+
return false unless reflection.respond_to?(:foreign_type)
|
|
132
|
+
|
|
133
|
+
foreign_type = reflection.foreign_type
|
|
134
|
+
foreign_type && object.respond_to?(:[]) && object[foreign_type].nil?
|
|
135
|
+
end
|
|
136
|
+
|
|
118
137
|
def create_notification(callers, klazz, associations)
|
|
119
138
|
notify_associations = Array.wrap(associations) - Bullet.get_safelist_associations(:n_plus_one_query, klazz)
|
|
120
139
|
|
|
@@ -50,7 +50,7 @@ module Bullet
|
|
|
50
50
|
if key_objects_overlap == k
|
|
51
51
|
to_add << [k, associations]
|
|
52
52
|
else
|
|
53
|
-
to_merge << [key_objects_overlap,
|
|
53
|
+
to_merge << [key_objects_overlap, eager_loadings[k].dup.merge(Array.wrap(associations))]
|
|
54
54
|
|
|
55
55
|
keys_without_objects = k - key_objects_overlap
|
|
56
56
|
to_merge << [keys_without_objects, eager_loadings[k]]
|
data/lib/bullet/mongoid4x.rb
CHANGED
|
@@ -46,6 +46,8 @@ module Bullet
|
|
|
46
46
|
::Mongoid::Relations::Accessors.class_eval do
|
|
47
47
|
alias_method :origin_get_relation, :get_relation
|
|
48
48
|
|
|
49
|
+
private
|
|
50
|
+
|
|
49
51
|
def get_relation(name, metadata, object, reload = false)
|
|
50
52
|
result = origin_get_relation(name, metadata, object, reload)
|
|
51
53
|
Bullet::Detector::NPlusOneQuery.call_association(self, name) if metadata.macro !~ /embed/
|
data/lib/bullet/mongoid5x.rb
CHANGED
|
@@ -46,6 +46,8 @@ module Bullet
|
|
|
46
46
|
::Mongoid::Relations::Accessors.class_eval do
|
|
47
47
|
alias_method :origin_get_relation, :get_relation
|
|
48
48
|
|
|
49
|
+
private
|
|
50
|
+
|
|
49
51
|
def get_relation(name, metadata, object, reload = false)
|
|
50
52
|
result = origin_get_relation(name, metadata, object, reload)
|
|
51
53
|
Bullet::Detector::NPlusOneQuery.call_association(self, name) if metadata.macro !~ /embed/
|
data/lib/bullet/mongoid6x.rb
CHANGED
|
@@ -46,6 +46,8 @@ module Bullet
|
|
|
46
46
|
::Mongoid::Relations::Accessors.class_eval do
|
|
47
47
|
alias_method :origin_get_relation, :get_relation
|
|
48
48
|
|
|
49
|
+
private
|
|
50
|
+
|
|
49
51
|
def get_relation(name, metadata, object, reload = false)
|
|
50
52
|
result = origin_get_relation(name, metadata, object, reload)
|
|
51
53
|
Bullet::Detector::NPlusOneQuery.call_association(self, name) if metadata.macro !~ /embed/
|
data/lib/bullet/mongoid7x.rb
CHANGED
|
@@ -61,6 +61,8 @@ module Bullet
|
|
|
61
61
|
::Mongoid::Association::Accessors.class_eval do
|
|
62
62
|
alias_method :origin_get_relation, :get_relation
|
|
63
63
|
|
|
64
|
+
private
|
|
65
|
+
|
|
64
66
|
def get_relation(name, association, object, reload = false)
|
|
65
67
|
result = origin_get_relation(name, association, object, reload)
|
|
66
68
|
Bullet::Detector::NPlusOneQuery.call_association(self, name) unless association.embedded?
|
data/lib/bullet/mongoid8x.rb
CHANGED
|
@@ -46,6 +46,8 @@ module Bullet
|
|
|
46
46
|
::Mongoid::Association::Accessors.class_eval do
|
|
47
47
|
alias_method :origin_get_relation, :get_relation
|
|
48
48
|
|
|
49
|
+
private
|
|
50
|
+
|
|
49
51
|
def get_relation(name, association, object, reload = false)
|
|
50
52
|
result = origin_get_relation(name, association, object, reload)
|
|
51
53
|
unless association.embedded?
|
data/lib/bullet/mongoid9x.rb
CHANGED
|
@@ -61,6 +61,8 @@ module Bullet
|
|
|
61
61
|
::Mongoid::Association::Accessors.class_eval do
|
|
62
62
|
alias_method :origin_get_relation, :get_relation
|
|
63
63
|
|
|
64
|
+
private
|
|
65
|
+
|
|
64
66
|
def get_relation(name, association, object, reload = false)
|
|
65
67
|
result = origin_get_relation(name, association, object, reload)
|
|
66
68
|
Bullet::Detector::NPlusOneQuery.call_association(self, name) unless association.embedded?
|
data/lib/bullet/rack.rb
CHANGED
|
@@ -76,8 +76,9 @@ module Bullet
|
|
|
76
76
|
|
|
77
77
|
# Make footer styles work with ContentSecurityPolicy style-src as self
|
|
78
78
|
def footer_style(nonce = nil)
|
|
79
|
+
position_css = footer_position_css
|
|
79
80
|
css = <<~CSS
|
|
80
|
-
details#bullet-footer {cursor: pointer; position: fixed;
|
|
81
|
+
details#bullet-footer {cursor: pointer; position: fixed; #{position_css}; z-index: 9999; background: #fdf2f2; color: #9b1c1c; font-size: 12px; #{footer_border_radius}; border: 1px solid #9b1c1c;}
|
|
81
82
|
details#bullet-footer summary {font-weight: 600; padding: 2px 8px;}
|
|
82
83
|
details#bullet-footer div {padding: 8px; border-top: 1px solid #9b1c1c;}
|
|
83
84
|
CSS
|
|
@@ -88,6 +89,38 @@ module Bullet
|
|
|
88
89
|
end
|
|
89
90
|
end
|
|
90
91
|
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def footer_position_css
|
|
95
|
+
case Bullet.footer_position
|
|
96
|
+
when 'bottom_left'
|
|
97
|
+
'left: 0px; bottom: 0px'
|
|
98
|
+
when 'bottom_right'
|
|
99
|
+
'right: 0px; bottom: 0px'
|
|
100
|
+
when 'top_left'
|
|
101
|
+
'left: 0px; top: 0px'
|
|
102
|
+
when 'top_right'
|
|
103
|
+
'right: 0px; top: 0px'
|
|
104
|
+
else
|
|
105
|
+
'left: 0px; bottom: 0px'
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def footer_border_radius
|
|
110
|
+
case Bullet.footer_position
|
|
111
|
+
when 'bottom_left'
|
|
112
|
+
'border-radius: 0px 8px 0px 0px'
|
|
113
|
+
when 'bottom_right'
|
|
114
|
+
'border-radius: 8px 0px 0px 0px'
|
|
115
|
+
when 'top_left'
|
|
116
|
+
'border-radius: 0px 0px 8px 0px'
|
|
117
|
+
when 'top_right'
|
|
118
|
+
'border-radius: 0px 0px 0px 8px'
|
|
119
|
+
else
|
|
120
|
+
'border-radius: 0px 8px 0px 0px'
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
91
124
|
def set_header(headers, header_name, header_array)
|
|
92
125
|
# Many proxy applications such as Nginx and AWS ELB limit
|
|
93
126
|
# the size a header to 8KB, so truncate the list of reports to
|
|
@@ -123,7 +156,7 @@ module Bullet
|
|
|
123
156
|
end
|
|
124
157
|
|
|
125
158
|
def html_request?(headers, response)
|
|
126
|
-
headers['Content-Type']&.include?('text/html')
|
|
159
|
+
headers['Content-Type']&.include?('text/html') || false
|
|
127
160
|
end
|
|
128
161
|
|
|
129
162
|
def response_body(response)
|
|
@@ -4,8 +4,13 @@ module Bullet
|
|
|
4
4
|
module Registry
|
|
5
5
|
class CallStack < Base
|
|
6
6
|
# remembers found association backtrace
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
# if backtrace is provided, it will be used and override any existing value
|
|
8
|
+
def add(key, backtrace = nil)
|
|
9
|
+
if backtrace
|
|
10
|
+
@registry[key] = backtrace
|
|
11
|
+
else
|
|
12
|
+
@registry[key] ||= Thread.current.backtrace
|
|
13
|
+
end
|
|
9
14
|
end
|
|
10
15
|
end
|
|
11
16
|
end
|
data/lib/bullet/version.rb
CHANGED
data/lib/bullet.rb
CHANGED
|
@@ -42,6 +42,7 @@ module Bullet
|
|
|
42
42
|
:skip_html_injection
|
|
43
43
|
attr_reader :safelist
|
|
44
44
|
attr_accessor :add_footer,
|
|
45
|
+
:footer_position,
|
|
45
46
|
:orm_patches_applied,
|
|
46
47
|
:skip_http_headers,
|
|
47
48
|
:always_append_html_body,
|
|
@@ -123,7 +124,7 @@ module Bullet
|
|
|
123
124
|
end
|
|
124
125
|
|
|
125
126
|
def get_safelist_associations(type, class_name)
|
|
126
|
-
Array.wrap(@safelist[type][class_name])
|
|
127
|
+
Array.wrap(@safelist[type][class_name]).flat_map { |a| [a, a.to_s] }
|
|
127
128
|
end
|
|
128
129
|
|
|
129
130
|
def reset_safelist
|
|
@@ -188,6 +189,26 @@ module Bullet
|
|
|
188
189
|
enable? && Thread.current.thread_variable_get(:bullet_start)
|
|
189
190
|
end
|
|
190
191
|
|
|
192
|
+
def pause
|
|
193
|
+
Thread.current.thread_variable_set(:bullet_start, false)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def resume
|
|
197
|
+
Thread.current.thread_variable_set(:bullet_start, true)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def paused?
|
|
201
|
+
enable? && !Thread.current.thread_variable_get(:bullet_start)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def skip
|
|
205
|
+
bullet_was_started = start?
|
|
206
|
+
pause if bullet_was_started
|
|
207
|
+
yield
|
|
208
|
+
ensure
|
|
209
|
+
resume if bullet_was_started
|
|
210
|
+
end
|
|
211
|
+
|
|
191
212
|
def notification_collector
|
|
192
213
|
Thread.current.thread_variable_get(:bullet_notification_collector)
|
|
193
214
|
end
|
|
@@ -259,6 +280,10 @@ module Bullet
|
|
|
259
280
|
UniformNotifier.active_notifiers.include?(UniformNotifier::JavascriptConsole)
|
|
260
281
|
end
|
|
261
282
|
|
|
283
|
+
def footer_position
|
|
284
|
+
@footer_position || 'bottom_left'
|
|
285
|
+
end
|
|
286
|
+
|
|
262
287
|
def inject_into_page?
|
|
263
288
|
return false if defined?(@skip_html_injection) && @skip_html_injection
|
|
264
289
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bullet
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.0
|
|
4
|
+
version: 8.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Richard Huang
|
|
@@ -37,6 +37,34 @@ dependencies:
|
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '1.11'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: ostruct
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: logger
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
40
68
|
description: help to kill N+1 queries and unused eager loading.
|
|
41
69
|
email:
|
|
42
70
|
- flyerhzm@gmail.com
|
|
@@ -49,17 +77,11 @@ files:
|
|
|
49
77
|
- README.md
|
|
50
78
|
- lib/bullet.rb
|
|
51
79
|
- lib/bullet/active_job.rb
|
|
52
|
-
- lib/bullet/active_record4.rb
|
|
53
|
-
- lib/bullet/active_record41.rb
|
|
54
|
-
- lib/bullet/active_record42.rb
|
|
55
|
-
- lib/bullet/active_record5.rb
|
|
56
|
-
- lib/bullet/active_record52.rb
|
|
57
|
-
- lib/bullet/active_record60.rb
|
|
58
|
-
- lib/bullet/active_record61.rb
|
|
59
80
|
- lib/bullet/active_record70.rb
|
|
60
81
|
- lib/bullet/active_record71.rb
|
|
61
82
|
- lib/bullet/active_record72.rb
|
|
62
83
|
- lib/bullet/active_record80.rb
|
|
84
|
+
- lib/bullet/active_record81.rb
|
|
63
85
|
- lib/bullet/bullet_xhr.js
|
|
64
86
|
- lib/bullet/dependency.rb
|
|
65
87
|
- lib/bullet/detector.rb
|
|
@@ -112,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
112
134
|
- !ruby/object:Gem::Version
|
|
113
135
|
version: 1.3.6
|
|
114
136
|
requirements: []
|
|
115
|
-
rubygems_version:
|
|
137
|
+
rubygems_version: 4.0.6
|
|
116
138
|
specification_version: 4
|
|
117
139
|
summary: help to kill N+1 queries and unused eager loading.
|
|
118
140
|
test_files: []
|
|
@@ -1,199 +0,0 @@
|
|
|
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
|
-
unless @inversed
|
|
170
|
-
Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
|
|
171
|
-
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
result
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
::ActiveRecord::Associations::HasManyAssociation.class_eval do
|
|
179
|
-
alias_method :origin_has_cached_counter?, :has_cached_counter?
|
|
180
|
-
|
|
181
|
-
def has_cached_counter?(reflection = reflection())
|
|
182
|
-
result = origin_has_cached_counter?(reflection)
|
|
183
|
-
Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) if Bullet.start? && !result
|
|
184
|
-
result
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
::ActiveRecord::Associations::CollectionProxy.class_eval do
|
|
189
|
-
def count(column_name = nil, options = {})
|
|
190
|
-
if Bullet.start?
|
|
191
|
-
Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
|
|
192
|
-
Bullet::Detector::NPlusOneQuery.call_association(proxy_association.owner, proxy_association.reflection.name)
|
|
193
|
-
end
|
|
194
|
-
super(column_name, options)
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
end
|