flyerhzm-bullet 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +5 -1
- data/VERSION +1 -1
- data/bullet.gemspec +4 -4
- data/lib/bullet/active_record.rb +12 -11
- data/lib/bullet/association.rb +20 -5
- data/spec/bullet_association_spec.rb +24 -2
- metadata +4 -5
data/README.textile
CHANGED
@@ -150,7 +150,11 @@ $ script/plugin install git://github.com/flyerhzm/bullet.git
|
|
150
150
|
6. enable the bullet plugin in development, add a line to <code>config/environments/development.rb</code>
|
151
151
|
|
152
152
|
<pre><code>
|
153
|
-
|
153
|
+
config.after_initialize do
|
154
|
+
Bullet.enable = true
|
155
|
+
Bullet::Association.alert = true
|
156
|
+
Bullet::Association.bullet_logger = true
|
157
|
+
end
|
154
158
|
</code></pre>
|
155
159
|
|
156
160
|
7. start server
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
data/bullet.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{bullet}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Richard Huang"]
|
12
|
-
s.date = %q{2009-08-
|
12
|
+
s.date = %q{2009-08-31}
|
13
13
|
s.description = %q{The Bullet plugin is designed to help you increase your application's performance by reducing the number of queries it makes. It will watch your queries while you develop your application and notify you when you should add eager loading (N+1 queries) or when you're using eager loading that isn't necessary.}
|
14
14
|
s.email = %q{flyerhzm@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -38,8 +38,8 @@ Gem::Specification.new do |s|
|
|
38
38
|
s.rubygems_version = %q{1.3.5}
|
39
39
|
s.summary = %q{A plugin to kill N+1 queries and unused eager loading}
|
40
40
|
s.test_files = [
|
41
|
-
"spec/
|
42
|
-
"spec/
|
41
|
+
"spec/bullet_association_spec.rb",
|
42
|
+
"spec/spec_helper.rb"
|
43
43
|
]
|
44
44
|
|
45
45
|
if s.respond_to? :specification_version then
|
data/lib/bullet/active_record.rb
CHANGED
@@ -3,11 +3,11 @@ module Bullet
|
|
3
3
|
def self.enable
|
4
4
|
::ActiveRecord::Base.class_eval do
|
5
5
|
class << self
|
6
|
-
alias_method :
|
6
|
+
alias_method :origin_find_every, :find_every
|
7
7
|
# if select a collection of objects, then these objects have possible to cause N+1 query
|
8
8
|
# if select only one object, then the only one object has impossible to cause N+1 query
|
9
9
|
def find_every(options)
|
10
|
-
records =
|
10
|
+
records = origin_find_every(options)
|
11
11
|
|
12
12
|
if records
|
13
13
|
if records.size > 1
|
@@ -23,7 +23,7 @@ module Bullet
|
|
23
23
|
end
|
24
24
|
|
25
25
|
::ActiveRecord::AssociationPreload::ClassMethods.class_eval do
|
26
|
-
alias_method :
|
26
|
+
alias_method :origin_preload_associations, :preload_associations
|
27
27
|
# add include for one to many associations query
|
28
28
|
def preload_associations(records, associations, preload_options={})
|
29
29
|
records = [records].flatten.compact.uniq
|
@@ -31,34 +31,35 @@ module Bullet
|
|
31
31
|
records.each do |record|
|
32
32
|
Bullet::Association.add_association(record, associations)
|
33
33
|
end
|
34
|
-
|
34
|
+
Bullet::Association.add_eager_loadings(records, associations)
|
35
|
+
origin_preload_associations(records, associations, preload_options={})
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
39
|
::ActiveRecord::Associations::ClassMethods.class_eval do
|
39
40
|
# define one to many associations
|
40
|
-
alias_method :
|
41
|
+
alias_method :origin_collection_reader_method, :collection_reader_method
|
41
42
|
def collection_reader_method(reflection, association_proxy_class)
|
42
43
|
Bullet::Association.define_association(self, reflection.name)
|
43
|
-
|
44
|
+
origin_collection_reader_method(reflection, association_proxy_class)
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
48
|
::ActiveRecord::Associations::AssociationCollection.class_eval do
|
48
49
|
# call one to many associations
|
49
|
-
alias_method :
|
50
|
+
alias_method :origin_load_target, :load_target
|
50
51
|
def load_target
|
51
52
|
Bullet::Association.call_association(@owner, @reflection.name)
|
52
|
-
|
53
|
+
origin_load_target
|
53
54
|
end
|
54
55
|
end
|
55
56
|
|
56
57
|
::ActiveRecord::Associations::AssociationProxy.class_eval do
|
57
|
-
# call has_one association
|
58
|
-
alias_method :
|
58
|
+
# call has_one and belong_to association
|
59
|
+
alias_method :origin_load_target, :load_target
|
59
60
|
def load_target
|
60
61
|
Bullet::Association.call_association(@owner, @reflection.name)
|
61
|
-
|
62
|
+
origin_load_target
|
62
63
|
end
|
63
64
|
end
|
64
65
|
end
|
data/lib/bullet/association.rb
CHANGED
@@ -24,6 +24,7 @@ module Bullet
|
|
24
24
|
@@possible_objects = nil
|
25
25
|
@@impossible_objects = nil
|
26
26
|
@@call_object_associations = nil
|
27
|
+
@@eager_loadings = nil
|
27
28
|
end
|
28
29
|
|
29
30
|
def alert=(alert)
|
@@ -64,8 +65,10 @@ module Bullet
|
|
64
65
|
|
65
66
|
def check_unused_preload_associations
|
66
67
|
object_associations.each do |object, association|
|
67
|
-
|
68
|
-
|
68
|
+
related_objects = eager_loadings.select {|key, value| key.include?(object) and value == association}.collect(&:first).flatten
|
69
|
+
call_object_association = related_objects.collect { |related_object| call_object_associations[related_object] }.compact.flatten.uniq
|
70
|
+
diff_object_association = (association - call_object_association).reject {|a| a.is_a? Hash}
|
71
|
+
add_unused_preload_associations(object.class, diff_object_association) unless diff_object_association.empty?
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
@@ -88,11 +91,11 @@ module Bullet
|
|
88
91
|
response = []
|
89
92
|
if has_unused_preload_associations?
|
90
93
|
response.push("Unused eager loadings detected:\n")
|
91
|
-
response.push(*@@unused_preload_associations.to_a.collect{|klazz, associations| klazz_associations_str(klazz, associations)}.join(
|
94
|
+
response.push(*@@unused_preload_associations.to_a.collect{|klazz, associations| klazz_associations_str(klazz, associations)}.join("\n"))
|
92
95
|
end
|
93
96
|
if has_unpreload_associations?
|
94
97
|
response.push("#{"\n" unless response.empty?}N+1 queries detected:\n")
|
95
|
-
response.push(*@@unpreload_associations.to_a.collect{|klazz, associations| " #{klazz} => [#{associations.map(&:inspect).join(', ')}]"}.join(
|
98
|
+
response.push(*@@unpreload_associations.to_a.collect{|klazz, associations| " #{klazz} => [#{associations.map(&:inspect).join(', ')}]"}.join("\n"))
|
96
99
|
end
|
97
100
|
end
|
98
101
|
if @@alert
|
@@ -143,7 +146,7 @@ module Bullet
|
|
143
146
|
|
144
147
|
def bad_associations_str(bad_associations)
|
145
148
|
# puts bad_associations.inspect
|
146
|
-
bad_associations.to_a.collect{|klazz, associations| klazz_associations_str(klazz, associations)}.join(
|
149
|
+
bad_associations.to_a.collect{|klazz, associations| klazz_associations_str(klazz, associations)}.join("\n")
|
147
150
|
end
|
148
151
|
|
149
152
|
def klazz_associations_str(klazz, associations)
|
@@ -229,6 +232,14 @@ module Bullet
|
|
229
232
|
klazz_associations[klazz] << associations
|
230
233
|
unique(klazz_associations[klazz])
|
231
234
|
end
|
235
|
+
|
236
|
+
def add_eager_loadings(objects, associations)
|
237
|
+
# puts "add eager loadings, #{objects.inspect} => #{associations.inspect}"
|
238
|
+
objects = Array(objects)
|
239
|
+
eager_loadings[objects] ||= []
|
240
|
+
eager_loadings[objects] << associations
|
241
|
+
unique(eager_loadings[objects])
|
242
|
+
end
|
232
243
|
|
233
244
|
def unique(array)
|
234
245
|
array.flatten!
|
@@ -262,6 +273,10 @@ module Bullet
|
|
262
273
|
def klazz_associations
|
263
274
|
@@klazz_associations ||= {}
|
264
275
|
end
|
276
|
+
|
277
|
+
def eager_loadings
|
278
|
+
@@eager_loadings ||= {}
|
279
|
+
end
|
265
280
|
|
266
281
|
VENDOR_ROOT = File.join(RAILS_ROOT, 'vendor')
|
267
282
|
def caller_in_project
|
@@ -56,8 +56,6 @@ describe Bullet::Association, 'has_many' do
|
|
56
56
|
|
57
57
|
post1 = category1.posts.create(:name => 'first')
|
58
58
|
post2 = category1.posts.create(:name => 'second')
|
59
|
-
post3 = category2.posts.create(:name => 'third')
|
60
|
-
post4 = category2.posts.create(:name => 'fourth')
|
61
59
|
|
62
60
|
comment1 = post1.comments.create(:name => 'first')
|
63
61
|
comment2 = post1.comments.create(:name => 'second')
|
@@ -228,12 +226,36 @@ describe Bullet::Association, 'has_many' do
|
|
228
226
|
end
|
229
227
|
|
230
228
|
context "no preload" do
|
229
|
+
it "should no preload only display only one post => comment" do
|
230
|
+
Post.find(:all, :include => :comments).each do |post|
|
231
|
+
post.comments.first.name
|
232
|
+
end
|
233
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
234
|
+
end
|
235
|
+
|
231
236
|
it "should no preload only one post => commnets" do
|
232
237
|
Post.first.comments.collect(&:name)
|
233
238
|
Bullet::Association.should_not be_has_unpreload_associations
|
234
239
|
end
|
235
240
|
end
|
236
241
|
|
242
|
+
context "no unused" do
|
243
|
+
it "should no unused only display only one post => comment" do
|
244
|
+
Post.find(:all, :include => :comments).each do |post|
|
245
|
+
i = 0
|
246
|
+
post.comments.each do |comment|
|
247
|
+
if i == 0
|
248
|
+
comment.name
|
249
|
+
else
|
250
|
+
i += 1
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
Bullet::Association.check_unused_preload_associations
|
255
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
237
259
|
context "belongs_to" do
|
238
260
|
it "should preload comments => post" do
|
239
261
|
Comment.find(:all).each do |comment|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flyerhzm-bullet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Huang
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-31 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -39,7 +39,6 @@ files:
|
|
39
39
|
- tasks/bullet_tasks.rake
|
40
40
|
has_rdoc: false
|
41
41
|
homepage: http://github.com/flyerhzm/bullet
|
42
|
-
licenses:
|
43
42
|
post_install_message:
|
44
43
|
rdoc_options:
|
45
44
|
- --charset=UTF-8
|
@@ -60,10 +59,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
59
|
requirements: []
|
61
60
|
|
62
61
|
rubyforge_project:
|
63
|
-
rubygems_version: 1.
|
62
|
+
rubygems_version: 1.2.0
|
64
63
|
signing_key:
|
65
64
|
specification_version: 3
|
66
65
|
summary: A plugin to kill N+1 queries and unused eager loading
|
67
66
|
test_files:
|
68
|
-
- spec/spec_helper.rb
|
69
67
|
- spec/bullet_association_spec.rb
|
68
|
+
- spec/spec_helper.rb
|