bullet 2.0.1 → 2.1.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.
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.rvmrc +2 -0
- data/.rvmrc.example +2 -0
- data/.watchr +24 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +105 -0
- data/Hacking.textile +69 -0
- data/README.textile +37 -55
- data/README_for_rails2.textile +35 -52
- data/Rakefile +45 -0
- data/bullet.gemspec +24 -0
- data/lib/bullet.rb +5 -5
- data/lib/bullet/action_controller2.rb +5 -5
- data/lib/bullet/active_record2.rb +2 -1
- data/lib/bullet/active_record3.rb +2 -1
- data/lib/bullet/active_record31.rb +96 -0
- data/lib/bullet/detector/association.rb +18 -9
- data/lib/bullet/detector/base.rb +0 -7
- data/lib/bullet/detector/unused_eager_association.rb +7 -5
- data/lib/bullet/notification/base.rb +6 -2
- data/lib/bullet/rack.rb +1 -1
- data/lib/bullet/registry/association.rb +1 -2
- data/lib/bullet/registry/base.rb +6 -8
- data/lib/bullet/version.rb +1 -1
- data/perf/benchmark.rb +106 -0
- data/rails/init.rb +1 -0
- data/spec/bullet/association_for_chris_spec.rb +96 -0
- data/spec/bullet/association_for_peschkaj_spec.rb +86 -0
- data/spec/bullet/association_spec.rb +889 -0
- data/spec/bullet/counter_spec.rb +136 -0
- data/spec/spec_helper.rb +79 -0
- data/tasks/bullet_tasks.rake +9 -0
- metadata +59 -62
@@ -0,0 +1,136 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
4
|
+
|
5
|
+
describe Bullet::Detector::Counter do
|
6
|
+
def setup_db
|
7
|
+
ActiveRecord::Schema.define(:version => 1) do
|
8
|
+
create_table :countries do |t|
|
9
|
+
t.string :name
|
10
|
+
end
|
11
|
+
|
12
|
+
create_table :cities do |t|
|
13
|
+
t.string :name
|
14
|
+
t.integer :country_id
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown_db
|
20
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
21
|
+
ActiveRecord::Base.connection.drop_table(table)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Country < ActiveRecord::Base
|
26
|
+
has_many :cities
|
27
|
+
end
|
28
|
+
|
29
|
+
class City < ActiveRecord::Base
|
30
|
+
belongs_to :country
|
31
|
+
end
|
32
|
+
|
33
|
+
before(:all) do
|
34
|
+
setup_db
|
35
|
+
|
36
|
+
country1 = Country.create(:name => 'first')
|
37
|
+
country2 = Country.create(:name => 'second')
|
38
|
+
|
39
|
+
country1.cities.create(:name => 'first')
|
40
|
+
country1.cities.create(:name => 'second')
|
41
|
+
country2.cities.create(:name => 'third')
|
42
|
+
country2.cities.create(:name => 'fourth')
|
43
|
+
end
|
44
|
+
|
45
|
+
after(:all) do
|
46
|
+
teardown_db
|
47
|
+
end
|
48
|
+
|
49
|
+
before(:each) do
|
50
|
+
Bullet.start_request
|
51
|
+
end
|
52
|
+
|
53
|
+
after(:each) do
|
54
|
+
Bullet.end_request
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should need counter cache with all cities" do
|
58
|
+
Country.all.each do |country|
|
59
|
+
country.cities.size
|
60
|
+
end
|
61
|
+
Bullet.collected_counter_cache_notifications.should_not be_empty
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should not need coounter cache with only one object" do
|
65
|
+
Country.first.cities.size
|
66
|
+
Bullet.collected_counter_cache_notifications.should be_empty
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should not need counter cache with part of cities" do
|
70
|
+
Country.all.each do |country|
|
71
|
+
country.cities.where(:name => 'first').size
|
72
|
+
end
|
73
|
+
Bullet.collected_counter_cache_notifications.should be_empty
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe Bullet::Detector::Counter do
|
78
|
+
def setup_db
|
79
|
+
ActiveRecord::Schema.define(:version => 1) do
|
80
|
+
create_table :people do |t|
|
81
|
+
t.string :name
|
82
|
+
t.integer :pets_count
|
83
|
+
end
|
84
|
+
|
85
|
+
create_table :pets do |t|
|
86
|
+
t.string :name
|
87
|
+
t.integer :person_id
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def teardown_db
|
93
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
94
|
+
ActiveRecord::Base.connection.drop_table(table)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class Person < ActiveRecord::Base
|
99
|
+
has_many :pets
|
100
|
+
end
|
101
|
+
|
102
|
+
class Pet < ActiveRecord::Base
|
103
|
+
belongs_to :person, :counter_cache => true
|
104
|
+
end
|
105
|
+
|
106
|
+
before(:all) do
|
107
|
+
setup_db
|
108
|
+
|
109
|
+
person1 = Person.create(:name => 'first')
|
110
|
+
person2 = Person.create(:name => 'second')
|
111
|
+
|
112
|
+
person1.pets.create(:name => 'first')
|
113
|
+
person1.pets.create(:name => 'second')
|
114
|
+
person2.pets.create(:name => 'third')
|
115
|
+
person2.pets.create(:name => 'fourth')
|
116
|
+
end
|
117
|
+
|
118
|
+
after(:all) do
|
119
|
+
teardown_db
|
120
|
+
end
|
121
|
+
|
122
|
+
before(:each) do
|
123
|
+
Bullet.start_request
|
124
|
+
end
|
125
|
+
|
126
|
+
after(:each) do
|
127
|
+
Bullet.end_request
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should not need counter cache" do
|
131
|
+
Person.all.each do |person|
|
132
|
+
person.pets.size
|
133
|
+
end
|
134
|
+
Bullet.collected_counter_cache_notifications.should be_empty
|
135
|
+
end
|
136
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rspec'
|
3
|
+
require 'rspec/autorun'
|
4
|
+
require 'rails'
|
5
|
+
require 'active_record'
|
6
|
+
require 'action_controller'
|
7
|
+
|
8
|
+
module Rails
|
9
|
+
class <<self
|
10
|
+
def root
|
11
|
+
File.expand_path(__FILE__).split('/')[0..-3].join('/')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
|
17
|
+
require 'bullet'
|
18
|
+
Bullet.enable = true
|
19
|
+
ActiveRecord::Migration.verbose = false
|
20
|
+
|
21
|
+
module Bullet
|
22
|
+
def self.collected_notifications_of_class( notification_class )
|
23
|
+
Bullet.notification_collector.collection.select do |notification|
|
24
|
+
notification.is_a? notification_class
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.collected_counter_cache_notifications
|
29
|
+
collected_notifications_of_class Bullet::Notification::CounterCache
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.collected_n_plus_one_query_notifications
|
33
|
+
collected_notifications_of_class Bullet::Notification::NPlusOneQuery
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.collected_unused_eager_association_notifications
|
37
|
+
collected_notifications_of_class Bullet::Notification::UnusedEagerLoading
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Bullet
|
42
|
+
module Detector
|
43
|
+
class Association
|
44
|
+
class <<self
|
45
|
+
# returns true if all associations are preloaded
|
46
|
+
def completely_preloading_associations?
|
47
|
+
Bullet.collected_n_plus_one_query_notifications.empty?
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_unused_preload_associations?
|
51
|
+
Bullet.collected_unused_eager_association_notifications.present?
|
52
|
+
end
|
53
|
+
|
54
|
+
# returns true if a given object has a specific association
|
55
|
+
def creating_object_association_for?(object, association)
|
56
|
+
object_associations[object].present? && object_associations[object].include?(association)
|
57
|
+
end
|
58
|
+
|
59
|
+
# returns true if a given class includes the specific unpreloaded association
|
60
|
+
def detecting_unpreloaded_association_for?(klass, association)
|
61
|
+
for_class_and_assoc = Bullet.collected_n_plus_one_query_notifications.select do |notification|
|
62
|
+
notification.base_class == klass and
|
63
|
+
notification.associations.include?( association )
|
64
|
+
end
|
65
|
+
for_class_and_assoc.present?
|
66
|
+
end
|
67
|
+
|
68
|
+
# returns true if the given class includes the specific unused preloaded association
|
69
|
+
def unused_preload_associations_for?(klass, association)
|
70
|
+
for_class_and_assoc = Bullet.collected_unused_eager_association_notifications.select do |notification|
|
71
|
+
notification.base_class == klass and
|
72
|
+
notification.associations.include?( association )
|
73
|
+
end
|
74
|
+
for_class_and_assoc.present?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
metadata
CHANGED
@@ -1,111 +1,108 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 2
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
version: 2.0.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.1.0
|
5
|
+
prerelease:
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Richard Huang
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
version_requirements: &id001 !ruby/object:Gem::Requirement
|
12
|
+
date: 2011-12-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: uniform_notifier
|
16
|
+
requirement: &2156581180 !ruby/object:Gem::Requirement
|
23
17
|
none: false
|
24
|
-
requirements:
|
18
|
+
requirements:
|
25
19
|
- - ~>
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
hash: 23
|
28
|
-
segments:
|
29
|
-
- 1
|
30
|
-
- 0
|
31
|
-
- 0
|
20
|
+
- !ruby/object:Gem::Version
|
32
21
|
version: 1.0.0
|
33
|
-
requirement: *id001
|
34
|
-
name: uniform_notifier
|
35
|
-
prerelease: false
|
36
22
|
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2156581180
|
37
25
|
description: A rails plugin to kill N+1 queries and unused eager loading.
|
38
|
-
email:
|
26
|
+
email:
|
39
27
|
- flyerhzm@gmail.com
|
40
28
|
executables: []
|
41
|
-
|
42
29
|
extensions: []
|
43
|
-
|
44
|
-
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- .rspec
|
34
|
+
- .rvmrc
|
35
|
+
- .rvmrc.example
|
36
|
+
- .watchr
|
37
|
+
- Gemfile
|
38
|
+
- Gemfile.lock
|
39
|
+
- Hacking.textile
|
45
40
|
- MIT-LICENSE
|
46
41
|
- README.textile
|
47
42
|
- README_for_rails2.textile
|
48
|
-
|
43
|
+
- Rakefile
|
44
|
+
- bullet.gemspec
|
45
|
+
- lib/bullet.rb
|
49
46
|
- lib/bullet/action_controller2.rb
|
50
47
|
- lib/bullet/active_record2.rb
|
51
48
|
- lib/bullet/active_record3.rb
|
49
|
+
- lib/bullet/active_record31.rb
|
50
|
+
- lib/bullet/detector.rb
|
52
51
|
- lib/bullet/detector/association.rb
|
53
52
|
- lib/bullet/detector/base.rb
|
54
53
|
- lib/bullet/detector/counter.rb
|
55
54
|
- lib/bullet/detector/n_plus_one_query.rb
|
56
55
|
- lib/bullet/detector/unused_eager_association.rb
|
57
|
-
- lib/bullet/
|
56
|
+
- lib/bullet/notification.rb
|
58
57
|
- lib/bullet/notification/base.rb
|
59
58
|
- lib/bullet/notification/counter_cache.rb
|
60
59
|
- lib/bullet/notification/n_plus_one_query.rb
|
61
60
|
- lib/bullet/notification/unused_eager_loading.rb
|
62
|
-
- lib/bullet/notification.rb
|
63
61
|
- lib/bullet/notification_collector.rb
|
64
62
|
- lib/bullet/rack.rb
|
63
|
+
- lib/bullet/registry.rb
|
65
64
|
- lib/bullet/registry/association.rb
|
66
65
|
- lib/bullet/registry/base.rb
|
67
66
|
- lib/bullet/registry/object.rb
|
68
|
-
- lib/bullet/registry.rb
|
69
67
|
- lib/bullet/version.rb
|
70
|
-
-
|
71
|
-
-
|
72
|
-
-
|
73
|
-
-
|
74
|
-
|
68
|
+
- perf/benchmark.rb
|
69
|
+
- rails/init.rb
|
70
|
+
- spec/bullet/association_for_chris_spec.rb
|
71
|
+
- spec/bullet/association_for_peschkaj_spec.rb
|
72
|
+
- spec/bullet/association_spec.rb
|
73
|
+
- spec/bullet/counter_spec.rb
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
- tasks/bullet_tasks.rake
|
75
76
|
homepage: http://github.com/flyerhzm/bullet
|
76
77
|
licenses: []
|
77
|
-
|
78
78
|
post_install_message:
|
79
79
|
rdoc_options: []
|
80
|
-
|
81
|
-
require_paths:
|
80
|
+
require_paths:
|
82
81
|
- lib
|
83
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
83
|
none: false
|
85
|
-
requirements:
|
86
|
-
- -
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
|
89
|
-
segments:
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
segments:
|
90
89
|
- 0
|
91
|
-
|
92
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
hash: -1237939251235315374
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
92
|
none: false
|
94
|
-
requirements:
|
95
|
-
- -
|
96
|
-
- !ruby/object:Gem::Version
|
97
|
-
hash: 23
|
98
|
-
segments:
|
99
|
-
- 1
|
100
|
-
- 3
|
101
|
-
- 6
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
102
96
|
version: 1.3.6
|
103
97
|
requirements: []
|
104
|
-
|
105
98
|
rubyforge_project:
|
106
|
-
rubygems_version: 1.
|
99
|
+
rubygems_version: 1.8.10
|
107
100
|
signing_key:
|
108
101
|
specification_version: 3
|
109
102
|
summary: A rails plugin to kill N+1 queries and unused eager loading.
|
110
|
-
test_files:
|
111
|
-
|
103
|
+
test_files:
|
104
|
+
- spec/bullet/association_for_chris_spec.rb
|
105
|
+
- spec/bullet/association_for_peschkaj_spec.rb
|
106
|
+
- spec/bullet/association_spec.rb
|
107
|
+
- spec/bullet/counter_spec.rb
|
108
|
+
- spec/spec_helper.rb
|