bullet 2.2.0 → 2.3.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 +1 -0
- data/.travis.yml +4 -1
- data/Gemfile +3 -2
- data/Gemfile.lock +85 -69
- data/Guardfile +8 -0
- data/README.textile +2 -2
- data/lib/bullet/action_controller2.rb +4 -4
- data/lib/bullet/active_record2.rb +5 -6
- data/lib/bullet/active_record3.rb +2 -3
- data/lib/bullet/active_record31.rb +10 -12
- data/lib/bullet/detector/association.rb +27 -53
- data/lib/bullet/detector/counter.rb +34 -29
- data/lib/bullet/detector/n_plus_one_query.rb +47 -28
- data/lib/bullet/detector/unused_eager_association.rb +31 -30
- data/lib/bullet/notification/base.rb +14 -12
- data/lib/bullet/notification/n_plus_one_query.rb +6 -10
- data/lib/bullet/notification/unused_eager_loading.rb +1 -2
- data/lib/bullet/notification_collector.rb +1 -2
- data/lib/bullet/rack.rb +6 -3
- data/lib/bullet/registry/association.rb +4 -6
- data/lib/bullet/registry/base.rb +10 -7
- data/lib/bullet/registry/object.rb +6 -6
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +13 -8
- data/perf/benchmark.rb +30 -12
- data/spec/bullet/detector/association_spec.rb +90 -0
- data/spec/bullet/detector/base_spec.rb +14 -0
- data/spec/bullet/detector/counter_spec.rb +65 -0
- data/spec/bullet/detector/n_plus_one_query_spec.rb +94 -0
- data/spec/bullet/detector/unused_eager_association_spec.rb +62 -0
- data/spec/bullet/notification/base_spec.rb +67 -0
- data/spec/bullet/notification/counter_cache_spec.rb +12 -0
- data/spec/bullet/notification/n_plus_one_query_spec.rb +13 -0
- data/spec/bullet/notification/unused_eager_loading_spec.rb +12 -0
- data/spec/bullet/notification_collector_spec.rb +32 -0
- data/spec/bullet/rack_spec.rb +80 -24
- data/spec/bullet/registry/association_spec.rb +26 -0
- data/spec/bullet/registry/base_spec.rb +44 -0
- data/spec/bullet/registry/object_spec.rb +25 -0
- data/spec/integration/association_for_chris_spec.rb +37 -0
- data/spec/integration/association_for_peschkaj_spec.rb +26 -0
- data/spec/{bullet → integration}/association_spec.rb +1 -359
- data/spec/integration/counter_spec.rb +37 -0
- data/spec/models/address.rb +3 -0
- data/spec/models/author.rb +3 -0
- data/spec/models/base_user.rb +5 -0
- data/spec/models/category.rb +7 -0
- data/spec/models/city.rb +3 -0
- data/spec/models/client.rb +4 -0
- data/spec/models/comment.rb +4 -0
- data/spec/models/company.rb +3 -0
- data/spec/models/contact.rb +3 -0
- data/spec/models/country.rb +3 -0
- data/spec/models/deal.rb +4 -0
- data/spec/models/document.rb +5 -0
- data/spec/models/email.rb +3 -0
- data/spec/models/entry.rb +3 -0
- data/spec/models/firm.rb +4 -0
- data/spec/models/folder.rb +2 -0
- data/spec/models/hotel.rb +4 -0
- data/spec/models/location.rb +3 -0
- data/spec/models/newspaper.rb +3 -0
- data/spec/models/page.rb +2 -0
- data/spec/models/person.rb +3 -0
- data/spec/models/pet.rb +3 -0
- data/spec/models/post.rb +11 -0
- data/spec/models/relationship.rb +4 -0
- data/spec/models/student.rb +3 -0
- data/spec/models/submission.rb +4 -0
- data/spec/models/teacher.rb +3 -0
- data/spec/models/user.rb +4 -0
- data/spec/models/writer.rb +2 -0
- data/spec/spec_helper.rb +16 -106
- data/spec/support/bullet_ext.rb +55 -0
- data/spec/support/rack_double.rb +55 -0
- data/spec/support/seed.rb +256 -0
- metadata +104 -14
- data/.watchr +0 -24
- data/spec/bullet/association_for_chris_spec.rb +0 -96
- data/spec/bullet/association_for_peschkaj_spec.rb +0 -86
- data/spec/bullet/counter_spec.rb +0 -136
|
@@ -1,38 +1,57 @@
|
|
|
1
1
|
module Bullet
|
|
2
2
|
module Detector
|
|
3
3
|
class NPlusOneQuery < Association
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
class <<self
|
|
5
|
+
# executed when object.assocations is called.
|
|
6
|
+
# first, it keeps this method call for object.association.
|
|
7
|
+
# then, it checks if this associations call is unpreload.
|
|
8
|
+
# if it is, keeps this unpreload associations and caller.
|
|
9
|
+
def call_association(object, associations)
|
|
10
|
+
@@checked = true
|
|
11
|
+
add_call_object_associations(object, associations)
|
|
12
|
+
|
|
13
|
+
if conditions_met?(object.ar_key, associations)
|
|
14
|
+
create_notification caller_in_project, object.class.to_s, associations
|
|
15
|
+
end
|
|
15
16
|
end
|
|
16
|
-
end
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
private
|
|
19
|
+
def create_notification(callers, klazz, associations)
|
|
20
|
+
notice = Bullet::Notification::NPlusOneQuery.new(callers, klazz, associations)
|
|
21
|
+
Bullet.notification_collector.add(notice)
|
|
22
|
+
end
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
# decide whether the object.associations is unpreloaded or not.
|
|
25
|
+
def conditions_met?(object_ar_key, associations)
|
|
26
|
+
possible?(object_ar_key) && !impossible?(object_ar_key) && !association?(object_ar_key, associations)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def caller_in_project
|
|
30
|
+
rails_root = Rails.root.to_s
|
|
31
|
+
vendor_root = rails_root + "/vendor"
|
|
32
|
+
caller.select { |c| c.include?(rails_root) && !c.include?(vendor_root) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def possible?(object_ar_key)
|
|
36
|
+
possible_objects.include? object_ar_key
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def impossible?(object_ar_key)
|
|
40
|
+
impossible_objects.include? object_ar_key
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# check if object => associations already exists in object_associations.
|
|
44
|
+
def association?(object_ar_key, associations)
|
|
45
|
+
value = object_associations[object_ar_key]
|
|
46
|
+
if value
|
|
47
|
+
value.each do |v|
|
|
48
|
+
result = v.is_a?(Hash) ? v.has_key?(associations) : v == associations
|
|
49
|
+
return true if result
|
|
50
|
+
end
|
|
51
|
+
end
|
|
30
52
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
callers << caller.select { |c| c =~ /#{Rails.root}/ }.
|
|
34
|
-
reject { |c| c =~ /#{vender_root}/ }
|
|
35
|
-
callers.uniq!
|
|
53
|
+
return false
|
|
54
|
+
end
|
|
36
55
|
end
|
|
37
56
|
end
|
|
38
57
|
end
|
|
@@ -1,40 +1,41 @@
|
|
|
1
1
|
module Bullet
|
|
2
2
|
module Detector
|
|
3
3
|
class UnusedEagerAssociation < Association
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
class <<self
|
|
5
|
+
# check if there are unused preload associations.
|
|
6
|
+
# get related_objects from eager_loadings associated with object and associations
|
|
7
|
+
# get call_object_association from associations of call_object_associations whose object is in related_objects
|
|
8
|
+
# if association not in call_object_association, then the object => association - call_object_association is ununsed preload assocations
|
|
9
|
+
def check_unused_preload_associations
|
|
10
|
+
@@checked = true
|
|
11
|
+
object_associations.each do |object_ar_key, association|
|
|
12
|
+
object_association_diff = diff_object_association object_ar_key, association
|
|
13
|
+
next if object_association_diff.empty?
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
create_notification object_ar_key.split(":").first, object_association_diff
|
|
16
|
+
end
|
|
16
17
|
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
protected
|
|
20
|
-
def self.create_notification(klazz, associations)
|
|
21
|
-
notice = Bullet::Notification::UnusedEagerLoading.new( klazz, associations )
|
|
22
|
-
Bullet.notification_collector.add( notice )
|
|
23
|
-
end
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
19
|
+
private
|
|
20
|
+
def create_notification(klazz, associations)
|
|
21
|
+
notice = Bullet::Notification::UnusedEagerLoading.new(klazz, associations)
|
|
22
|
+
Bullet.notification_collector.add(notice)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def call_associations(object_ar_key, association)
|
|
26
|
+
all = Set.new
|
|
27
|
+
eager_loadings.similarly_associated(object_ar_key, association).each do |related_object_ar_key|
|
|
28
|
+
coa = call_object_associations[related_object_ar_key]
|
|
29
|
+
next if coa.nil?
|
|
30
|
+
all.merge coa
|
|
31
|
+
end
|
|
32
|
+
all.to_a
|
|
33
|
+
end
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
def diff_object_association(object_ar_key, association)
|
|
36
|
+
potential_objects = association - call_associations(object_ar_key, association)
|
|
37
|
+
potential_objects.reject { |a| a.is_a?(Hash) }
|
|
38
|
+
end
|
|
38
39
|
end
|
|
39
40
|
end
|
|
40
41
|
end
|
|
@@ -4,18 +4,20 @@ module Bullet
|
|
|
4
4
|
attr_accessor :notifier, :url
|
|
5
5
|
attr_reader :base_class, :associations, :path
|
|
6
6
|
|
|
7
|
-
def initialize(
|
|
7
|
+
def initialize(base_class, association_or_associations, path = nil)
|
|
8
8
|
@base_class = base_class
|
|
9
|
-
@associations =
|
|
9
|
+
@associations = association_or_associations.is_a?(Array) ? association_or_associations : [association_or_associations]
|
|
10
10
|
@path = path
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def title
|
|
14
|
+
raise NoMethodError.new("no method title defined")
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def body
|
|
18
|
+
raise NoMethodError.new("no method body defined")
|
|
17
19
|
end
|
|
18
|
-
|
|
20
|
+
|
|
19
21
|
def whoami
|
|
20
22
|
"user: " << `whoami`.chomp
|
|
21
23
|
end
|
|
@@ -33,14 +35,14 @@ module Bullet
|
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def notify_inline
|
|
36
|
-
self.notifier.inline_notify(
|
|
38
|
+
self.notifier.inline_notify(self.full_notice)
|
|
37
39
|
end
|
|
38
40
|
|
|
39
41
|
def notify_out_of_channel
|
|
40
|
-
self.notifier.out_of_channel_notify(
|
|
42
|
+
self.notifier.out_of_channel_notify(self.full_notice)
|
|
41
43
|
end
|
|
42
44
|
|
|
43
|
-
def eql?(
|
|
45
|
+
def eql?(other)
|
|
44
46
|
klazz_associations_str == other.klazz_associations_str
|
|
45
47
|
end
|
|
46
48
|
|
|
@@ -49,13 +51,13 @@ module Bullet
|
|
|
49
51
|
end
|
|
50
52
|
|
|
51
53
|
protected
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
def klazz_associations_str
|
|
55
|
+
" #{@base_class} => [#{@associations.map(&:inspect).join(', ')}]"
|
|
56
|
+
end
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
def associations_str
|
|
59
|
+
":include => #{@associations.map{ |a| a.to_s.to_sym unless a.is_a? Hash }.inspect}"
|
|
60
|
+
end
|
|
59
61
|
end
|
|
60
62
|
end
|
|
61
63
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module Bullet
|
|
2
2
|
module Notification
|
|
3
3
|
class NPlusOneQuery < Base
|
|
4
|
-
def initialize(
|
|
5
|
-
super(
|
|
4
|
+
def initialize(callers, base_class, associations, path = nil)
|
|
5
|
+
super(base_class, associations, path)
|
|
6
6
|
|
|
7
7
|
@callers = callers
|
|
8
8
|
end
|
|
@@ -10,7 +10,7 @@ module Bullet
|
|
|
10
10
|
def body_with_caller
|
|
11
11
|
"#{body}\n#{call_stack_messages}"
|
|
12
12
|
end
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
def body
|
|
15
15
|
"#{klazz_associations_str}\n Add to your finder: #{associations_str}"
|
|
16
16
|
end
|
|
@@ -20,13 +20,9 @@ module Bullet
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
protected
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
c.collect {|line| " #{line}"} ].flatten
|
|
27
|
-
end.join( "\n" )
|
|
28
|
-
end
|
|
29
|
-
|
|
23
|
+
def call_stack_messages
|
|
24
|
+
@callers.unshift('N+1 Query method call stack').join( "\n " )
|
|
25
|
+
end
|
|
30
26
|
end
|
|
31
27
|
end
|
|
32
28
|
end
|
data/lib/bullet/rack.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Bullet
|
|
|
13
13
|
|
|
14
14
|
response_body = nil
|
|
15
15
|
if Bullet.notification?
|
|
16
|
-
if status == 200
|
|
16
|
+
if status == 200 && !response.body.frozen? && html_request?(headers, response)
|
|
17
17
|
response_body = response.body << Bullet.gather_inline_notifications
|
|
18
18
|
headers['Content-Length'] = response_body.length.to_s
|
|
19
19
|
end
|
|
@@ -31,8 +31,11 @@ module Bullet
|
|
|
31
31
|
!response.body.is_a?(String) || response.body.empty?
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def
|
|
35
|
-
headers['Content-Type']
|
|
34
|
+
def html_request?(headers, response)
|
|
35
|
+
headers['Content-Type'] &&
|
|
36
|
+
headers['Content-Type'].include?('text/html') &&
|
|
37
|
+
response.body.include?("<html>") &&
|
|
38
|
+
response.body.include?("</html>")
|
|
36
39
|
end
|
|
37
40
|
|
|
38
41
|
def no_browser_cache(headers)
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
module Bullet
|
|
2
2
|
module Registry
|
|
3
3
|
class Association < Base
|
|
4
|
-
def merge(
|
|
5
|
-
@registry.merge!(
|
|
4
|
+
def merge(base, associations)
|
|
5
|
+
@registry.merge!(base => associations)
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
-
def similarly_associated(
|
|
9
|
-
@registry.select
|
|
10
|
-
key.include?( base ) and value == associations
|
|
11
|
-
end.collect( &:first ).flatten
|
|
8
|
+
def similarly_associated(base, associations)
|
|
9
|
+
@registry.select { |key, value| key.include?(base) && value == associations }.collect(&:first).flatten
|
|
12
10
|
end
|
|
13
11
|
end
|
|
14
12
|
end
|
data/lib/bullet/registry/base.rb
CHANGED
|
@@ -11,19 +11,19 @@ module Bullet
|
|
|
11
11
|
@registry[key]
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def each(
|
|
15
|
-
@registry.each(
|
|
14
|
+
def each(&block)
|
|
15
|
+
@registry.each(&block)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def delete(
|
|
19
|
-
@registry.delete(
|
|
18
|
+
def delete(base)
|
|
19
|
+
@registry.delete(base)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def select(
|
|
23
|
-
@registry.select(
|
|
22
|
+
def select(*args, &block)
|
|
23
|
+
@registry.select(*args, &block)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def add(
|
|
26
|
+
def add(key, value)
|
|
27
27
|
@registry[key] ||= Set.new
|
|
28
28
|
if value.is_a? Array
|
|
29
29
|
@registry[key] += value
|
|
@@ -32,6 +32,9 @@ module Bullet
|
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
def include?(key, value)
|
|
36
|
+
@registry[key] && @registry[key].include?(value)
|
|
37
|
+
end
|
|
35
38
|
end
|
|
36
39
|
end
|
|
37
40
|
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module Bullet
|
|
2
2
|
module Registry
|
|
3
3
|
class Object < Base
|
|
4
|
-
def add(
|
|
5
|
-
klazz =
|
|
6
|
-
|
|
7
|
-
super( klazz, object_or_objects )
|
|
4
|
+
def add(object_ar_key)
|
|
5
|
+
klazz = object_ar_key.split(":").first
|
|
6
|
+
super(klazz, object_ar_key)
|
|
8
7
|
end
|
|
9
8
|
|
|
10
|
-
def
|
|
11
|
-
|
|
9
|
+
def include?(object_ar_key)
|
|
10
|
+
klazz = object_ar_key.split(":").first
|
|
11
|
+
super(klazz, object_ar_key)
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
end
|
data/lib/bullet/version.rb
CHANGED
data/lib/bullet.rb
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
require 'set'
|
|
2
2
|
require 'uniform_notifier'
|
|
3
3
|
|
|
4
|
+
class Object
|
|
5
|
+
def ar_key
|
|
6
|
+
"#{self.class}:#{self.id}"
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
4
10
|
module Bullet
|
|
5
|
-
if Rails.version =~
|
|
11
|
+
if Rails.version =~ /\A3\.0/
|
|
6
12
|
autoload :ActiveRecord, 'bullet/active_record3'
|
|
7
|
-
elsif Rails.version =~
|
|
13
|
+
elsif Rails.version =~ /\A3\.[12]/
|
|
8
14
|
autoload :ActiveRecord, 'bullet/active_record31'
|
|
9
15
|
else
|
|
10
16
|
autoload :ActiveRecord, 'bullet/active_record2'
|
|
@@ -39,7 +45,7 @@ module Bullet
|
|
|
39
45
|
@enable = enable
|
|
40
46
|
if enable?
|
|
41
47
|
Bullet::ActiveRecord.enable
|
|
42
|
-
if Rails.version =~
|
|
48
|
+
if Rails.version =~ /\A2./
|
|
43
49
|
Bullet::ActionController.enable
|
|
44
50
|
end
|
|
45
51
|
end
|
|
@@ -51,7 +57,7 @@ module Bullet
|
|
|
51
57
|
|
|
52
58
|
def bullet_logger=(active)
|
|
53
59
|
if active
|
|
54
|
-
bullet_log_file = File.open(
|
|
60
|
+
bullet_log_file = File.open('log/bullet.log', 'a+')
|
|
55
61
|
bullet_log_file.sync
|
|
56
62
|
UniformNotifier.customized_logger = bullet_log_file
|
|
57
63
|
end
|
|
@@ -59,15 +65,15 @@ module Bullet
|
|
|
59
65
|
|
|
60
66
|
def start_request
|
|
61
67
|
notification_collector.reset
|
|
62
|
-
DETECTORS.each {|bullet| bullet.start_request}
|
|
68
|
+
DETECTORS.each { |bullet| bullet.start_request }
|
|
63
69
|
end
|
|
64
70
|
|
|
65
71
|
def end_request
|
|
66
|
-
DETECTORS.each {|bullet| bullet.end_request}
|
|
72
|
+
DETECTORS.each { |bullet| bullet.end_request }
|
|
67
73
|
end
|
|
68
74
|
|
|
69
75
|
def clear
|
|
70
|
-
DETECTORS.each {|bullet| bullet.clear}
|
|
76
|
+
DETECTORS.each { |bullet| bullet.clear }
|
|
71
77
|
end
|
|
72
78
|
|
|
73
79
|
def notification_collector
|
|
@@ -104,5 +110,4 @@ module Bullet
|
|
|
104
110
|
end
|
|
105
111
|
end
|
|
106
112
|
end
|
|
107
|
-
|
|
108
113
|
end
|
data/perf/benchmark.rb
CHANGED
|
@@ -83,16 +83,18 @@ PerfTools::CpuProfiler.start(ARGV[0]|| "benchmark_profile") if defined? PerfTool
|
|
|
83
83
|
|
|
84
84
|
Benchmark.bm(70) do |bm|
|
|
85
85
|
bm.report("Querying & Iterating #{posts_size} Posts with #{comments_size} Comments and #{users_size} Users") do
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
p
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
c
|
|
92
|
-
|
|
86
|
+
10.times do
|
|
87
|
+
Bullet.start_request
|
|
88
|
+
Post.select("SQL_NO_CACHE *").includes(:user, :comments => :user).each do |p|
|
|
89
|
+
p.title
|
|
90
|
+
p.user.name
|
|
91
|
+
p.comments.each do |c|
|
|
92
|
+
c.body
|
|
93
|
+
c.user.name
|
|
94
|
+
end
|
|
93
95
|
end
|
|
96
|
+
Bullet.end_request
|
|
94
97
|
end
|
|
95
|
-
Bullet.end_request
|
|
96
98
|
end
|
|
97
99
|
end
|
|
98
100
|
|
|
@@ -100,7 +102,23 @@ PerfTools::CpuProfiler.stop if defined? PerfTools
|
|
|
100
102
|
puts "End benchmarking..."
|
|
101
103
|
|
|
102
104
|
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
#
|
|
106
|
-
|
|
105
|
+
# Run benchmark with bundler
|
|
106
|
+
#
|
|
107
|
+
# bundle exec ruby perf/benchmark.rb
|
|
108
|
+
#
|
|
109
|
+
# bullet 2.3.0 with rails 3.2.2
|
|
110
|
+
# user system total real
|
|
111
|
+
# Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 16.460000 0.190000 16.650000 ( 16.968246)
|
|
112
|
+
#
|
|
113
|
+
# bullet 2.3.0 with rails 3.1.4
|
|
114
|
+
# user system total real
|
|
115
|
+
# Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 14.600000 0.130000 14.730000 ( 14.937590)
|
|
116
|
+
#
|
|
117
|
+
# bullet 2.3.0 with rails 3.0.12
|
|
118
|
+
# user system total real
|
|
119
|
+
# Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 26.120000 0.430000 26.550000 ( 27.179304)
|
|
120
|
+
#
|
|
121
|
+
#
|
|
122
|
+
# bullet 2.2.1 with rails 3.0.12
|
|
123
|
+
# user system total real
|
|
124
|
+
# Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 29.970000 0.270000 30.240000 ( 30.452083)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Bullet
|
|
4
|
+
module Detector
|
|
5
|
+
describe Association do
|
|
6
|
+
before :all do
|
|
7
|
+
@post1 = Post.first
|
|
8
|
+
@post2 = Post.last
|
|
9
|
+
end
|
|
10
|
+
before(:each) { Association.clear }
|
|
11
|
+
|
|
12
|
+
context ".start_request" do
|
|
13
|
+
it "should set @@checked to false" do
|
|
14
|
+
Association.start_request
|
|
15
|
+
Association.class_variable_get(:@@checked).should be_false
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
context ".clear" do
|
|
20
|
+
it "should clear all class variables" do
|
|
21
|
+
Association.clear
|
|
22
|
+
Association.class_variable_get(:@@object_associations).should be_nil
|
|
23
|
+
Association.class_variable_get(:@@possible_objects).should be_nil
|
|
24
|
+
Association.class_variable_get(:@@impossible_objects).should be_nil
|
|
25
|
+
Association.class_variable_get(:@@call_object_associations).should be_nil
|
|
26
|
+
Association.class_variable_get(:@@eager_loadings).should be_nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context ".add_object_association" do
|
|
31
|
+
it "should add object, associations pair" do
|
|
32
|
+
Association.add_object_associations(@post1, :associations)
|
|
33
|
+
Association.send(:object_associations).should be_include(@post1.ar_key, :associations)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context ".add_call_object_associations" do
|
|
38
|
+
it "should add call object, associations pair" do
|
|
39
|
+
Association.add_call_object_associations(@post1, :associations)
|
|
40
|
+
Association.send(:call_object_associations).should be_include(@post1.ar_key, :associations)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context ".add_possible_objects" do
|
|
45
|
+
it "should add possible objects" do
|
|
46
|
+
Association.add_possible_objects([@post1, @post2])
|
|
47
|
+
Association.send(:possible_objects).should be_include(@post1.ar_key)
|
|
48
|
+
Association.send(:possible_objects).should be_include(@post2.ar_key)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context ".add_impossible_object" do
|
|
53
|
+
it "should add impossible object" do
|
|
54
|
+
Association.add_impossible_object(@post1)
|
|
55
|
+
Association.send(:impossible_objects).should be_include(@post1.ar_key)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context ".add_eager_loadings" do
|
|
60
|
+
it "should add objects, associations pair when eager_loadings are empty" do
|
|
61
|
+
Association.add_eager_loadings([@post1, @post2], :associations)
|
|
62
|
+
Association.send(:eager_loadings).should be_include([@post1.ar_key, @post2.ar_key], :associations)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should add objects, associations pair for existing eager_loadings" do
|
|
66
|
+
Association.add_eager_loadings([@post1, @post2], :association1)
|
|
67
|
+
Association.add_eager_loadings([@post1, @post2], :association2)
|
|
68
|
+
Association.send(:eager_loadings).should be_include([@post1.ar_key, @post2.ar_key], :association1)
|
|
69
|
+
Association.send(:eager_loadings).should be_include([@post1.ar_key, @post2.ar_key], :association2)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "should merge objects, associations pair for existing eager_loadings" do
|
|
73
|
+
Association.add_eager_loadings(@post1, :association1)
|
|
74
|
+
Association.add_eager_loadings([@post1, @post2], :association2)
|
|
75
|
+
Association.send(:eager_loadings).should be_include([@post1.ar_key], :association1)
|
|
76
|
+
Association.send(:eager_loadings).should be_include([@post1.ar_key], :association2)
|
|
77
|
+
Association.send(:eager_loadings).should be_include([@post1.ar_key, @post2.ar_key], :association2)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should delete objects, associations pair for existing eager_loadings" do
|
|
81
|
+
Association.add_eager_loadings([@post1, @post2], :association1)
|
|
82
|
+
Association.add_eager_loadings(@post1, :association2)
|
|
83
|
+
Association.send(:eager_loadings).should be_include([@post1.ar_key], :association1)
|
|
84
|
+
Association.send(:eager_loadings).should be_include([@post1.ar_key], :association2)
|
|
85
|
+
Association.send(:eager_loadings).should be_include([@post2.ar_key], :association1)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|