bullet 4.14.5 → 4.14.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,7 +15,7 @@ module Bullet
15
15
  add_call_object_associations(object, associations)
16
16
 
17
17
  Bullet.debug("Detector::NPlusOneQuery#call_association", "object: #{object.bullet_key}, associations: #{associations}")
18
- if conditions_met?(object.bullet_key, associations)
18
+ if conditions_met?(object, associations)
19
19
  Bullet.debug("detect n + 1 query", "object: #{object.bullet_key}, associations: #{associations}")
20
20
  create_notification caller_in_project, object.class.to_s, associations
21
21
  end
@@ -49,6 +49,35 @@ module Bullet
49
49
  inversed_objects.add object.bullet_key, association
50
50
  end
51
51
 
52
+ # decide whether the object.associations is unpreloaded or not.
53
+ def conditions_met?(object, associations)
54
+ possible?(object) && !impossible?(object) && !association?(object, associations)
55
+ end
56
+
57
+ def possible?(object)
58
+ possible_objects.include? object.bullet_key
59
+ end
60
+
61
+ def impossible?(object)
62
+ impossible_objects.include? object.bullet_key
63
+ end
64
+
65
+ # check if object => associations already exists in object_associations.
66
+ def association?(object, associations)
67
+ value = object_associations[object.bullet_key]
68
+ if value
69
+ value.each do |v|
70
+ # associations == v comparision order is important here because
71
+ # v variable might be a squeel node where :== method is redefined,
72
+ # so it does not compare values at all and return unexpected results
73
+ result = v.is_a?(Hash) ? v.has_key?(associations) : associations == v
74
+ return true if result
75
+ end
76
+ end
77
+
78
+ false
79
+ end
80
+
52
81
  private
53
82
  def create_notification(callers, klazz, associations)
54
83
  notify_associations = Array(associations) - Bullet.get_whitelist_associations(:n_plus_one_query, klazz)
@@ -59,11 +88,6 @@ module Bullet
59
88
  end
60
89
  end
61
90
 
62
- # decide whether the object.associations is unpreloaded or not.
63
- def conditions_met?(bullet_key, associations)
64
- possible?(bullet_key) && !impossible?(bullet_key) && !association?(bullet_key, associations)
65
- end
66
-
67
91
  def caller_in_project
68
92
  app_root = rails? ? Rails.root.to_s : Dir.pwd
69
93
  vendor_root = app_root + "/vendor"
@@ -72,30 +96,6 @@ module Bullet
72
96
  Bullet.stacktrace_includes.any? { |include| c.include?(include) }
73
97
  end
74
98
  end
75
-
76
- def possible?(bullet_key)
77
- possible_objects.include? bullet_key
78
- end
79
-
80
- def impossible?(bullet_key)
81
- impossible_objects.include? bullet_key
82
- end
83
-
84
- # check if object => associations already exists in object_associations.
85
- def association?(bullet_key, associations)
86
- value = object_associations[bullet_key]
87
- if value
88
- value.each do |v|
89
- # associations == v comparision order is important here because
90
- # v variable might be a squeel node where :== method is redefined,
91
- # so it does not compare values at all and return unexpected results
92
- result = v.is_a?(Hash) ? v.has_key?(associations) : associations == v
93
- return true if result
94
- end
95
- end
96
-
97
- return false
98
- end
99
99
  end
100
100
  end
101
101
  end
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Bullet
3
- VERSION = "4.14.5"
3
+ VERSION = "4.14.6"
4
4
  end
@@ -10,13 +10,13 @@ module Bullet
10
10
 
11
11
  context ".add_counter_cache" do
12
12
  it "should create notification if conditions met" do
13
- expect(CounterCache).to receive(:conditions_met?).with(@post1.bullet_key, [:comments]).and_return(true)
13
+ expect(CounterCache).to receive(:conditions_met?).with(@post1, [:comments]).and_return(true)
14
14
  expect(CounterCache).to receive(:create_notification).with("Post", [:comments])
15
15
  CounterCache.add_counter_cache(@post1, [:comments])
16
16
  end
17
17
 
18
18
  it "should not create notification if conditions not met" do
19
- expect(CounterCache).to receive(:conditions_met?).with(@post1.bullet_key, [:comments]).and_return(false)
19
+ expect(CounterCache).to receive(:conditions_met?).with(@post1, [:comments]).and_return(false)
20
20
  expect(CounterCache).to receive(:create_notification).never
21
21
  CounterCache.add_counter_cache(@post1, [:comments])
22
22
  end
@@ -25,30 +25,30 @@ module Bullet
25
25
  context ".add_possible_objects" do
26
26
  it "should add possible objects" do
27
27
  CounterCache.add_possible_objects([@post1, @post2])
28
- expect(CounterCache.send(:possible_objects)).to be_include(@post1.bullet_key)
29
- expect(CounterCache.send(:possible_objects)).to be_include(@post2.bullet_key)
28
+ expect(CounterCache.possible_objects).to be_include(@post1.bullet_key)
29
+ expect(CounterCache.possible_objects).to be_include(@post2.bullet_key)
30
30
  end
31
31
 
32
32
  it "should add impossible object" do
33
33
  CounterCache.add_impossible_object(@post1)
34
- expect(CounterCache.send(:impossible_objects)).to be_include(@post1.bullet_key)
34
+ expect(CounterCache.impossible_objects).to be_include(@post1.bullet_key)
35
35
  end
36
36
  end
37
37
 
38
38
  context ".conditions_met?" do
39
39
  it "should be true when object is possible, not impossible" do
40
40
  CounterCache.add_possible_objects(@post1)
41
- expect(CounterCache.send(:conditions_met?, @post1.bullet_key, :associations)).to eq true
41
+ expect(CounterCache.conditions_met?(@post1, :associations)).to eq true
42
42
  end
43
43
 
44
44
  it "should be false when object is not possible" do
45
- expect(CounterCache.send(:conditions_met?, @post1.bullet_key, :associations)).to eq false
45
+ expect(CounterCache.conditions_met?(@post1, :associations)).to eq false
46
46
  end
47
47
 
48
48
  it "should be true when object is possible, and impossible" do
49
49
  CounterCache.add_possible_objects(@post1)
50
50
  CounterCache.add_impossible_object(@post1)
51
- expect(CounterCache.send(:conditions_met?, @post1.bullet_key, :associations)).to eq false
51
+ expect(CounterCache.conditions_met?(@post1, :associations)).to eq false
52
52
  end
53
53
  end
54
54
  end
@@ -18,69 +18,69 @@ module Bullet
18
18
  context ".possible?" do
19
19
  it "should be true if possible_objects contain" do
20
20
  NPlusOneQuery.add_possible_objects(@post)
21
- expect(NPlusOneQuery.send(:possible?, @post.bullet_key)).to eq true
21
+ expect(NPlusOneQuery.possible?(@post)).to eq true
22
22
  end
23
23
  end
24
24
 
25
25
  context ".impossible?" do
26
26
  it "should be true if impossible_objects contain" do
27
27
  NPlusOneQuery.add_impossible_object(@post)
28
- expect(NPlusOneQuery.send(:impossible?, @post.bullet_key)).to eq true
28
+ expect(NPlusOneQuery.impossible?(@post)).to eq true
29
29
  end
30
30
  end
31
31
 
32
32
  context ".association?" do
33
33
  it "should be true if object, associations pair is already existed" do
34
34
  NPlusOneQuery.add_object_associations(@post, :association)
35
- expect(NPlusOneQuery.send(:association?, @post.bullet_key, :association)).to eq true
35
+ expect(NPlusOneQuery.association?(@post, :association)).to eq true
36
36
  end
37
37
 
38
38
  it "should be false if object, association pair is not existed" do
39
39
  NPlusOneQuery.add_object_associations(@post, :association1)
40
- expect(NPlusOneQuery.send(:association?, @post.bullet_key, :associatio2)).to eq false
40
+ expect(NPlusOneQuery.association?(@post, :associatio2)).to eq false
41
41
  end
42
42
  end
43
43
 
44
44
  context ".conditions_met?" do
45
45
  it "should be true if object is possible, not impossible and object, associations pair is not already existed" do
46
- allow(NPlusOneQuery).to receive(:possible?).with(@post.bullet_key).and_return(true)
47
- allow(NPlusOneQuery).to receive(:impossible?).with(@post.bullet_key).and_return(false)
48
- allow(NPlusOneQuery).to receive(:association?).with(@post.bullet_key, :associations).and_return(false)
49
- expect(NPlusOneQuery.send(:conditions_met?, @post.bullet_key, :associations)).to eq true
46
+ allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true)
47
+ allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false)
48
+ allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false)
49
+ expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq true
50
50
  end
51
51
 
52
52
  it "should be false if object is not possible, not impossible and object, associations pair is not already existed" do
53
- allow(NPlusOneQuery).to receive(:possible?).with(@post.bullet_key).and_return(false)
54
- allow(NPlusOneQuery).to receive(:impossible?).with(@post.bullet_key).and_return(false)
55
- allow(NPlusOneQuery).to receive(:association?).with(@post.bullet_key, :associations).and_return(false)
56
- expect(NPlusOneQuery.send(:conditions_met?, @post.bullet_key, :associations)).to eq false
53
+ allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(false)
54
+ allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false)
55
+ allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false)
56
+ expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false
57
57
  end
58
58
 
59
59
  it "should be false if object is possible, but impossible and object, associations pair is not already existed" do
60
- allow(NPlusOneQuery).to receive(:possible?).with(@post.bullet_key).and_return(true)
61
- allow(NPlusOneQuery).to receive(:impossible?).with(@post.bullet_key).and_return(true)
62
- allow(NPlusOneQuery).to receive(:association?).with(@post.bullet_key, :associations).and_return(false)
63
- expect(NPlusOneQuery.send(:conditions_met?, @post.bullet_key, :associations)).to eq false
60
+ allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true)
61
+ allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(true)
62
+ allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false)
63
+ expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false
64
64
  end
65
65
 
66
66
  it "should be false if object is possible, not impossible and object, associations pair is already existed" do
67
- allow(NPlusOneQuery).to receive(:possible?).with(@post.bullet_key).and_return(true)
68
- allow(NPlusOneQuery).to receive(:impossible?).with(@post.bullet_key).and_return(false)
69
- allow(NPlusOneQuery).to receive(:association?).with(@post.bullet_key, :associations).and_return(true)
70
- expect(NPlusOneQuery.send(:conditions_met?, @post.bullet_key, :associations)).to eq false
67
+ allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true)
68
+ allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false)
69
+ allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(true)
70
+ expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false
71
71
  end
72
72
  end
73
73
 
74
74
  context ".call_association" do
75
75
  it "should create notification if conditions met" do
76
- expect(NPlusOneQuery).to receive(:conditions_met?).with(@post.bullet_key, :association).and_return(true)
76
+ expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
77
77
  expect(NPlusOneQuery).to receive(:caller_in_project).and_return(["caller"])
78
78
  expect(NPlusOneQuery).to receive(:create_notification).with(["caller"], "Post", :association)
79
79
  NPlusOneQuery.call_association(@post, :association)
80
80
  end
81
81
 
82
82
  it "should not create notification if conditions not met" do
83
- expect(NPlusOneQuery).to receive(:conditions_met?).with(@post.bullet_key, :association).and_return(false)
83
+ expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(false)
84
84
  expect(NPlusOneQuery).not_to receive(:caller_in_project!)
85
85
  expect(NPlusOneQuery).not_to receive(:create_notification).with("Post", :association)
86
86
  NPlusOneQuery.call_association(@post, :association)
@@ -93,7 +93,7 @@ module Bullet
93
93
  not_in_project = '/def/def.rb'
94
94
 
95
95
  expect(NPlusOneQuery).to receive(:caller).and_return([in_project, not_in_project])
96
- expect(NPlusOneQuery).to receive(:conditions_met?).with(@post.bullet_key, :association).and_return(true)
96
+ expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
97
97
  expect(NPlusOneQuery).to receive(:create_notification).with([in_project], "Post", :association)
98
98
  NPlusOneQuery.call_association(@post, :association)
99
99
  end
@@ -108,7 +108,7 @@ module Bullet
108
108
  excluded_gem = '/ghi/ghi.rb'
109
109
 
110
110
  expect(NPlusOneQuery).to receive(:caller).and_return([in_project, included_gem, excluded_gem])
111
- expect(NPlusOneQuery).to receive(:conditions_met?).with(@post.bullet_key, :association).and_return(true)
111
+ expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
112
112
  expect(NPlusOneQuery).to receive(:create_notification).with([in_project, included_gem], "Post", :association)
113
113
  NPlusOneQuery.call_association(@post, :association)
114
114
  end
@@ -118,8 +118,8 @@ module Bullet
118
118
  context ".add_possible_objects" do
119
119
  it "should add possible objects" do
120
120
  NPlusOneQuery.add_possible_objects([@post, @post2])
121
- expect(NPlusOneQuery.send(:possible_objects)).to be_include(@post.bullet_key)
122
- expect(NPlusOneQuery.send(:possible_objects)).to be_include(@post2.bullet_key)
121
+ expect(NPlusOneQuery.possible_objects).to be_include(@post.bullet_key)
122
+ expect(NPlusOneQuery.possible_objects).to be_include(@post2.bullet_key)
123
123
  end
124
124
 
125
125
  it "should not raise error if object is nil" do
@@ -130,7 +130,7 @@ module Bullet
130
130
  context ".add_impossible_object" do
131
131
  it "should add impossible object" do
132
132
  NPlusOneQuery.add_impossible_object(@post)
133
- expect(NPlusOneQuery.send(:impossible_objects)).to be_include(@post.bullet_key)
133
+ expect(NPlusOneQuery.impossible_objects).to be_include(@post.bullet_key)
134
134
  end
135
135
  end
136
136
  end
@@ -335,6 +335,15 @@ if !mongoid? && active_record3?
335
335
  expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Comment, :post)
336
336
  end
337
337
 
338
+ it "should not detect non preload association with only one comment" do
339
+ Comment.first.post.category.name
340
+
341
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
342
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
343
+
344
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
345
+ end
346
+
338
347
  it "should detect non preload association with post => category" do
339
348
  Comment.includes(:post).each do |comment|
340
349
  comment.post.category.name
@@ -347,6 +347,15 @@ if !mongoid? && active_record4?
347
347
  expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Comment, :post)
348
348
  end
349
349
 
350
+ it "should not detect non preload association with only one comment" do
351
+ Comment.first.post.category.name
352
+
353
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
354
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
355
+
356
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
357
+ end
358
+
350
359
  it "should detect non preload association with post => category" do
351
360
  Comment.includes(:post).each do |comment|
352
361
  comment.post.category.name
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.14.5
4
+ version: 4.14.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-19 00:00:00.000000000 Z
11
+ date: 2015-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -184,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
184
  version: 1.3.6
185
185
  requirements: []
186
186
  rubyforge_project:
187
- rubygems_version: 2.4.5
187
+ rubygems_version: 2.4.6
188
188
  signing_key:
189
189
  specification_version: 4
190
190
  summary: help to kill N+1 queries and unused eager loading.