bullet 2.2.1 → 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/lib/bullet.rb +13 -8
- 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 +6 -8
- 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/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
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -5,11 +5,12 @@ source "http://rubygems.org"
|
|
5
5
|
gemspec
|
6
6
|
|
7
7
|
gem 'rails'
|
8
|
-
gem 'sqlite3
|
8
|
+
gem 'sqlite3'
|
9
9
|
gem 'mysql'
|
10
10
|
gem 'activerecord-import'
|
11
11
|
|
12
12
|
gem "rspec"
|
13
|
-
gem "
|
13
|
+
gem "guard"
|
14
|
+
gem "guard-rspec"
|
14
15
|
|
15
16
|
gem "perftools.rb"
|
data/Gemfile.lock
CHANGED
@@ -1,95 +1,110 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
bullet (2.
|
4
|
+
bullet (2.3.0)
|
5
5
|
uniform_notifier (~> 1.0.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
rack (~> 1.
|
21
|
-
rack-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
10
|
+
actionmailer (3.2.2)
|
11
|
+
actionpack (= 3.2.2)
|
12
|
+
mail (~> 2.4.0)
|
13
|
+
actionpack (3.2.2)
|
14
|
+
activemodel (= 3.2.2)
|
15
|
+
activesupport (= 3.2.2)
|
16
|
+
builder (~> 3.0.0)
|
17
|
+
erubis (~> 2.7.0)
|
18
|
+
journey (~> 1.0.1)
|
19
|
+
rack (~> 1.4.0)
|
20
|
+
rack-cache (~> 1.1)
|
21
|
+
rack-test (~> 0.6.1)
|
22
|
+
sprockets (~> 2.1.2)
|
23
|
+
activemodel (3.2.2)
|
24
|
+
activesupport (= 3.2.2)
|
25
|
+
builder (~> 3.0.0)
|
26
|
+
activerecord (3.2.2)
|
27
|
+
activemodel (= 3.2.2)
|
28
|
+
activesupport (= 3.2.2)
|
29
|
+
arel (~> 3.0.2)
|
30
|
+
tzinfo (~> 0.3.29)
|
31
|
+
activerecord-import (0.2.9)
|
32
|
+
activerecord (~> 3.0)
|
33
|
+
activerecord (~> 3.0)
|
34
|
+
activeresource (3.2.2)
|
35
|
+
activemodel (= 3.2.2)
|
36
|
+
activesupport (= 3.2.2)
|
37
|
+
activesupport (3.2.2)
|
38
|
+
i18n (~> 0.6)
|
39
|
+
multi_json (~> 1.0)
|
40
|
+
arel (3.0.2)
|
41
|
+
builder (3.0.0)
|
41
42
|
diff-lcs (1.1.3)
|
42
|
-
erubis (2.
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
erubis (2.7.0)
|
44
|
+
ffi (1.0.11)
|
45
|
+
guard (1.0.1)
|
46
|
+
ffi (>= 0.5.0)
|
47
|
+
thor (~> 0.14.6)
|
48
|
+
guard-rspec (0.6.0)
|
49
|
+
guard (>= 0.10.0)
|
50
|
+
hike (1.2.1)
|
51
|
+
i18n (0.6.0)
|
52
|
+
journey (1.0.3)
|
53
|
+
json (1.6.5)
|
54
|
+
mail (2.4.4)
|
48
55
|
i18n (>= 0.4.0)
|
49
56
|
mime-types (~> 1.16)
|
50
57
|
treetop (~> 1.4.8)
|
51
|
-
mime-types (1.
|
58
|
+
mime-types (1.18)
|
59
|
+
multi_json (1.1.0)
|
52
60
|
mysql (2.8.1)
|
53
|
-
perftools.rb (0.
|
61
|
+
perftools.rb (2.0.0)
|
54
62
|
polyglot (0.3.3)
|
55
|
-
rack (1.
|
56
|
-
rack-
|
57
|
-
rack (>=
|
58
|
-
rack-
|
63
|
+
rack (1.4.1)
|
64
|
+
rack-cache (1.2)
|
65
|
+
rack (>= 0.4)
|
66
|
+
rack-ssl (1.3.2)
|
67
|
+
rack
|
68
|
+
rack-test (0.6.1)
|
59
69
|
rack (>= 1.0)
|
60
|
-
rails (3.
|
61
|
-
actionmailer (= 3.
|
62
|
-
actionpack (= 3.
|
63
|
-
activerecord (= 3.
|
64
|
-
activeresource (= 3.
|
65
|
-
activesupport (= 3.
|
70
|
+
rails (3.2.2)
|
71
|
+
actionmailer (= 3.2.2)
|
72
|
+
actionpack (= 3.2.2)
|
73
|
+
activerecord (= 3.2.2)
|
74
|
+
activeresource (= 3.2.2)
|
75
|
+
activesupport (= 3.2.2)
|
66
76
|
bundler (~> 1.0)
|
67
|
-
railties (= 3.
|
68
|
-
railties (3.
|
69
|
-
actionpack (= 3.
|
70
|
-
activesupport (= 3.
|
77
|
+
railties (= 3.2.2)
|
78
|
+
railties (3.2.2)
|
79
|
+
actionpack (= 3.2.2)
|
80
|
+
activesupport (= 3.2.2)
|
81
|
+
rack-ssl (~> 1.3.2)
|
71
82
|
rake (>= 0.8.7)
|
72
83
|
rdoc (~> 3.4)
|
73
|
-
thor (~> 0.14.
|
84
|
+
thor (~> 0.14.6)
|
74
85
|
rake (0.9.2.2)
|
75
|
-
rdoc (3.
|
86
|
+
rdoc (3.12)
|
76
87
|
json (~> 1.4)
|
77
|
-
rspec (2.
|
78
|
-
rspec-core (~> 2.
|
79
|
-
rspec-expectations (~> 2.
|
80
|
-
rspec-mocks (~> 2.
|
81
|
-
rspec-core (2.
|
82
|
-
rspec-expectations (2.
|
83
|
-
diff-lcs (~> 1.1.
|
84
|
-
rspec-mocks (2.
|
85
|
-
|
88
|
+
rspec (2.9.0)
|
89
|
+
rspec-core (~> 2.9.0)
|
90
|
+
rspec-expectations (~> 2.9.0)
|
91
|
+
rspec-mocks (~> 2.9.0)
|
92
|
+
rspec-core (2.9.0)
|
93
|
+
rspec-expectations (2.9.0)
|
94
|
+
diff-lcs (~> 1.1.3)
|
95
|
+
rspec-mocks (2.9.0)
|
96
|
+
sprockets (2.1.2)
|
97
|
+
hike (~> 1.2)
|
98
|
+
rack (~> 1.0)
|
99
|
+
tilt (~> 1.1, != 1.3.0)
|
100
|
+
sqlite3 (1.3.5)
|
86
101
|
thor (0.14.6)
|
102
|
+
tilt (1.3.3)
|
87
103
|
treetop (1.4.10)
|
88
104
|
polyglot
|
89
105
|
polyglot (>= 0.3.1)
|
90
|
-
tzinfo (0.3.
|
106
|
+
tzinfo (0.3.32)
|
91
107
|
uniform_notifier (1.0.1)
|
92
|
-
watchr (0.7)
|
93
108
|
|
94
109
|
PLATFORMS
|
95
110
|
ruby
|
@@ -97,9 +112,10 @@ PLATFORMS
|
|
97
112
|
DEPENDENCIES
|
98
113
|
activerecord-import
|
99
114
|
bullet!
|
115
|
+
guard
|
116
|
+
guard-rspec
|
100
117
|
mysql
|
101
118
|
perftools.rb
|
102
119
|
rails
|
103
120
|
rspec
|
104
|
-
sqlite3
|
105
|
-
watchr
|
121
|
+
sqlite3
|
data/Guardfile
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :version => 2, :all_after_pass => false, :all_on_start => false, :cli => "--color --format nested --fail-fast" do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
end
|
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
|
@@ -2,8 +2,7 @@ module Bullet
|
|
2
2
|
class ActionController
|
3
3
|
def self.enable
|
4
4
|
require 'action_controller'
|
5
|
-
|
6
|
-
when /^2.3/
|
5
|
+
if Rails.version =~ /\A2.3/
|
7
6
|
::ActionController::Dispatcher.middleware.use Bullet::Rack
|
8
7
|
::ActionController::Dispatcher.class_eval do
|
9
8
|
class <<self
|
@@ -14,7 +13,7 @@ module Bullet
|
|
14
13
|
end
|
15
14
|
end
|
16
15
|
end
|
17
|
-
|
16
|
+
elsif Rails.version =~ /\A2.[12]/
|
18
17
|
::ActionController::Dispatcher.class_eval do
|
19
18
|
alias_method :origin_reload_application, :reload_application
|
20
19
|
def reload_application
|
@@ -30,7 +29,8 @@ module Bullet
|
|
30
29
|
response = origin_process(request, response, method = :perform_action, *arguments)
|
31
30
|
|
32
31
|
if Bullet.notification?
|
33
|
-
if response.headers["type"]
|
32
|
+
if response.headers["type"] && response.headers["type"].include?('text/html') &&
|
33
|
+
response.body.include?("<html>") && response.body.include?("</html>")
|
34
34
|
response.body <<= Bullet.gather_inline_notifications
|
35
35
|
response.headers["Content-Length"] = response.body.length.to_s
|
36
36
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Bullet
|
2
|
-
LOAD_TARGET_RGX = /load_target/
|
3
2
|
module ActiveRecord
|
4
3
|
def self.enable
|
5
4
|
require 'active_record'
|
@@ -11,7 +10,7 @@ module Bullet
|
|
11
10
|
def find_every(options)
|
12
11
|
records = origin_find_every(options)
|
13
12
|
|
14
|
-
if records
|
13
|
+
if records
|
15
14
|
if records.size > 1
|
16
15
|
Bullet::Detector::Association.add_possible_objects(records)
|
17
16
|
Bullet::Detector::Counter.add_possible_objects(records)
|
@@ -41,7 +40,7 @@ module Bullet
|
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
44
|
-
::ActiveRecord::Associations::ClassMethods.class_eval do
|
43
|
+
::ActiveRecord::Associations::ClassMethods.class_eval do
|
45
44
|
# add include in named_scope
|
46
45
|
alias_method :origin_find_with_associations, :find_with_associations
|
47
46
|
def find_with_associations(options)
|
@@ -75,19 +74,19 @@ module Bullet
|
|
75
74
|
origin_load_target
|
76
75
|
end
|
77
76
|
end
|
78
|
-
|
77
|
+
|
79
78
|
::ActiveRecord::Associations::AssociationProxy.class_eval do
|
80
79
|
# call has_one and belong_to association
|
81
80
|
alias_method :origin_load_target, :load_target
|
82
81
|
def load_target
|
83
82
|
# avoid stack level too deep
|
84
83
|
result = origin_load_target
|
85
|
-
Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.
|
84
|
+
Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.any? {|c| c.include?("load_target") }
|
86
85
|
Bullet::Detector::Association.add_possible_objects(result)
|
87
86
|
result
|
88
87
|
end
|
89
88
|
end
|
90
|
-
|
89
|
+
|
91
90
|
::ActiveRecord::Associations::HasManyAssociation.class_eval do
|
92
91
|
alias_method :origin_has_cached_counter?, :has_cached_counter?
|
93
92
|
def has_cached_counter?
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Bullet
|
2
|
-
LOAD_TARGET_RGX = /load_target/
|
3
2
|
module ActiveRecord
|
4
3
|
def self.enable
|
5
4
|
require 'active_record'
|
@@ -69,14 +68,14 @@ module Bullet
|
|
69
68
|
origin_load_target
|
70
69
|
end
|
71
70
|
end
|
72
|
-
|
71
|
+
|
73
72
|
::ActiveRecord::Associations::AssociationProxy.class_eval do
|
74
73
|
# call has_one and belong_to association
|
75
74
|
alias_method :origin_load_target, :load_target
|
76
75
|
def load_target
|
77
76
|
# avoid stack level too deep
|
78
77
|
result = origin_load_target
|
79
|
-
Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.
|
78
|
+
Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.any? { |c| c.include?("load_target") }
|
80
79
|
Bullet::Detector::Association.add_possible_objects(result)
|
81
80
|
result
|
82
81
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Bullet
|
2
|
-
LOAD_TARGET_RGX = /load_target/
|
3
2
|
module ActiveRecord
|
4
3
|
def self.enable
|
5
4
|
require 'active_record'
|
@@ -70,13 +69,12 @@ module Bullet
|
|
70
69
|
end
|
71
70
|
end
|
72
71
|
|
73
|
-
::ActiveRecord::Associations::
|
74
|
-
# call has_one and
|
75
|
-
alias_method :
|
76
|
-
def
|
77
|
-
|
78
|
-
|
79
|
-
Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.find {|c| c =~ LOAD_TARGET_RGX }
|
72
|
+
::ActiveRecord::Associations::SingularAssociation.class_eval do
|
73
|
+
# call has_one and belongs_to associations
|
74
|
+
alias_method :origin_reader, :reader
|
75
|
+
def reader(force_reload = false)
|
76
|
+
result = origin_reader(force_reload)
|
77
|
+
Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
|
80
78
|
Bullet::Detector::Association.add_possible_objects(result)
|
81
79
|
result
|
82
80
|
end
|
@@ -13,7 +13,6 @@ module Bullet
|
|
13
13
|
# derive from Bullet::Detector::Association - changing the variable
|
14
14
|
# in one subclass will make the change visible to all subclasses!
|
15
15
|
@@object_associations = nil
|
16
|
-
@@callers = nil
|
17
16
|
@@possible_objects = nil
|
18
17
|
@@impossible_objects = nil
|
19
18
|
@@call_object_associations = nil
|
@@ -21,83 +20,62 @@ module Bullet
|
|
21
20
|
end
|
22
21
|
|
23
22
|
def add_object_associations(object, associations)
|
24
|
-
object_associations.add(
|
23
|
+
object_associations.add(object.ar_key, associations)
|
25
24
|
end
|
26
25
|
|
27
26
|
def add_call_object_associations(object, associations)
|
28
|
-
|
27
|
+
if object.id
|
28
|
+
call_object_associations.add(object.ar_key, associations)
|
29
|
+
end
|
29
30
|
end
|
30
31
|
|
31
|
-
def add_possible_objects(
|
32
|
-
|
32
|
+
def add_possible_objects(object_or_objects)
|
33
|
+
if object_or_objects.is_a? Array
|
34
|
+
object_or_objects.each { |object| possible_objects.add object.ar_key }
|
35
|
+
else
|
36
|
+
possible_objects.add object_or_objects.ar_key
|
37
|
+
end
|
33
38
|
end
|
34
39
|
|
35
40
|
def add_impossible_object(object)
|
36
|
-
impossible_objects.add object
|
41
|
+
impossible_objects.add object.ar_key
|
37
42
|
end
|
38
43
|
|
39
44
|
def add_eager_loadings(objects, associations)
|
40
|
-
|
45
|
+
object_ar_keys = Array(objects).map(&:ar_key)
|
41
46
|
|
42
47
|
to_add = nil
|
43
48
|
to_merge, to_delete = [], []
|
44
49
|
eager_loadings.each do |k, v|
|
45
|
-
key_objects_overlap = k &
|
50
|
+
key_objects_overlap = k & object_ar_keys
|
46
51
|
|
47
52
|
next if key_objects_overlap.empty?
|
48
53
|
|
49
54
|
if key_objects_overlap == k
|
50
55
|
to_add = [k, associations]
|
51
56
|
break
|
52
|
-
|
53
57
|
else
|
54
58
|
to_merge << [key_objects_overlap, ( eager_loadings[k].dup << associations )]
|
55
59
|
|
56
|
-
keys_without_objects = k -
|
60
|
+
keys_without_objects = k - object_ar_keys
|
57
61
|
to_merge << [keys_without_objects, eager_loadings[k]]
|
58
62
|
to_delete << k
|
59
|
-
|
63
|
+
object_ar_keys = object_ar_keys - k
|
60
64
|
end
|
61
65
|
end
|
62
|
-
if to_add
|
63
|
-
eager_loadings.add *to_add
|
64
|
-
end
|
65
|
-
to_merge.each do |k,val|
|
66
|
-
eager_loadings.merge k, val
|
67
|
-
end
|
68
|
-
to_delete.each do |k|
|
69
|
-
eager_loadings.delete k
|
70
|
-
end
|
71
66
|
|
72
|
-
eager_loadings.add
|
67
|
+
eager_loadings.add *to_add if to_add
|
68
|
+
to_merge.each { |k,val| eager_loadings.merge k, val }
|
69
|
+
to_delete.each { |k| eager_loadings.delete k }
|
70
|
+
|
71
|
+
eager_loadings.add object_ar_keys, associations unless object_ar_keys.empty?
|
73
72
|
end
|
74
73
|
|
75
74
|
private
|
76
|
-
|
77
|
-
possible_objects.contains? object
|
78
|
-
end
|
79
|
-
|
80
|
-
def impossible?(object)
|
81
|
-
impossible_objects.contains? object
|
82
|
-
end
|
83
|
-
|
84
|
-
# check if object => associations already exists in object_associations.
|
85
|
-
def association?(object, associations)
|
86
|
-
value = object_associations[object]
|
87
|
-
if value
|
88
|
-
value.each do |v|
|
89
|
-
result = v.is_a?(Hash) ? v.has_key?(associations) : v == associations
|
90
|
-
return true if result
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
return false
|
95
|
-
end
|
96
|
-
|
97
|
-
# object_associations keep the object relationships
|
75
|
+
# object_associations keep the object relationships
|
98
76
|
# that the object has many associations.
|
99
|
-
# e.g. {
|
100
|
-
# the object_associations keep all associations that may be or may no be
|
77
|
+
# e.g. { "Post:1" => [:comments] }
|
78
|
+
# the object_associations keep all associations that may be or may no be
|
101
79
|
# unpreload associations or unused preload associations.
|
102
80
|
def object_associations
|
103
81
|
@@object_associations ||= Bullet::Registry::Base.new
|
@@ -105,7 +83,7 @@ module Bullet
|
|
105
83
|
|
106
84
|
# call_object_assciations keep the object relationships
|
107
85
|
# that object.associations is called.
|
108
|
-
# e.g. {
|
86
|
+
# e.g. { "Post:1" => [:comments] }
|
109
87
|
# they are used to detect unused preload associations.
|
110
88
|
def call_object_associations
|
111
89
|
@@call_object_associations ||= Bullet::Registry::Base.new
|
@@ -113,14 +91,14 @@ module Bullet
|
|
113
91
|
|
114
92
|
# possible_objects keep the class to object relationships
|
115
93
|
# that the objects may cause N+1 query.
|
116
|
-
# e.g. { Post => [
|
94
|
+
# e.g. { Post => ["Post:1", "Post:2"] }
|
117
95
|
def possible_objects
|
118
96
|
@@possible_objects ||= Bullet::Registry::Object.new
|
119
97
|
end
|
120
98
|
|
121
99
|
# impossible_objects keep the class to objects relationships
|
122
100
|
# that the objects may not cause N+1 query.
|
123
|
-
# e.g. { Post => [
|
101
|
+
# e.g. { Post => ["Post:1", "Post:2"] }
|
124
102
|
# Notice: impossible_objects are not accurate,
|
125
103
|
# if find collection returns only one object, then the object is impossible object,
|
126
104
|
# impossible_objects are used to avoid treating 1+1 query to N+1 query.
|
@@ -130,14 +108,10 @@ module Bullet
|
|
130
108
|
|
131
109
|
# eager_loadings keep the object relationships
|
132
110
|
# that the associations are preloaded by find :include.
|
133
|
-
# e.g. { [
|
111
|
+
# e.g. { ["Post:1", "Post:2"] => [:comments, :user] }
|
134
112
|
def eager_loadings
|
135
113
|
@@eager_loadings ||= Bullet::Registry::Association.new
|
136
114
|
end
|
137
|
-
|
138
|
-
def callers
|
139
|
-
@@callers ||= []
|
140
|
-
end
|
141
115
|
end
|
142
116
|
end
|
143
117
|
end
|