bullet 7.0.7 → 7.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +3 -0
- data/lib/bullet/active_record4.rb +9 -0
- data/lib/bullet/active_record41.rb +9 -0
- data/lib/bullet/active_record42.rb +9 -0
- data/lib/bullet/active_record5.rb +11 -0
- data/lib/bullet/active_record52.rb +11 -0
- data/lib/bullet/active_record60.rb +11 -0
- data/lib/bullet/active_record61.rb +11 -0
- data/lib/bullet/active_record70.rb +19 -6
- data/lib/bullet/active_record71.rb +297 -0
- data/lib/bullet/dependency.rb +12 -0
- data/lib/bullet/detector/unused_eager_loading.rb +1 -1
- data/lib/bullet/mongoid8x.rb +59 -0
- data/lib/bullet/notification/counter_cache.rb +1 -1
- data/lib/bullet/rack.rb +1 -1
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +5 -1
- metadata +7 -155
- data/.github/workflows/main.yml +0 -82
- data/.gitignore +0 -15
- data/.rspec +0 -2
- data/Gemfile +0 -24
- data/Gemfile.mongoid +0 -12
- data/Gemfile.mongoid-4.0 +0 -15
- data/Gemfile.mongoid-5.0 +0 -15
- data/Gemfile.mongoid-6.0 +0 -15
- data/Gemfile.mongoid-7.0 +0 -15
- data/Gemfile.rails-4.0 +0 -16
- data/Gemfile.rails-4.1 +0 -16
- data/Gemfile.rails-4.2 +0 -16
- data/Gemfile.rails-5.0 +0 -15
- data/Gemfile.rails-5.1 +0 -15
- data/Gemfile.rails-5.2 +0 -15
- data/Gemfile.rails-6.0 +0 -15
- data/Gemfile.rails-6.1 +0 -15
- data/Gemfile.rails-7.0 +0 -10
- data/Guardfile +0 -8
- data/Hacking.md +0 -75
- data/Rakefile +0 -51
- data/bullet.gemspec +0 -33
- data/perf/benchmark.rb +0 -118
- data/rails/init.rb +0 -3
- data/spec/bullet/detector/association_spec.rb +0 -28
- data/spec/bullet/detector/base_spec.rb +0 -10
- data/spec/bullet/detector/counter_cache_spec.rb +0 -58
- data/spec/bullet/detector/n_plus_one_query_spec.rb +0 -150
- data/spec/bullet/detector/unused_eager_loading_spec.rb +0 -126
- data/spec/bullet/ext/object_spec.rb +0 -44
- data/spec/bullet/ext/string_spec.rb +0 -15
- data/spec/bullet/notification/base_spec.rb +0 -94
- data/spec/bullet/notification/counter_cache_spec.rb +0 -14
- data/spec/bullet/notification/n_plus_one_query_spec.rb +0 -29
- data/spec/bullet/notification/unused_eager_loading_spec.rb +0 -18
- data/spec/bullet/notification_collector_spec.rb +0 -34
- data/spec/bullet/rack_spec.rb +0 -296
- data/spec/bullet/registry/association_spec.rb +0 -28
- data/spec/bullet/registry/base_spec.rb +0 -46
- data/spec/bullet/registry/object_spec.rb +0 -26
- data/spec/bullet/stack_trace_filter_spec.rb +0 -26
- data/spec/bullet_spec.rb +0 -136
- data/spec/integration/active_record/association_spec.rb +0 -822
- data/spec/integration/counter_cache_spec.rb +0 -68
- data/spec/integration/mongoid/association_spec.rb +0 -246
- data/spec/models/address.rb +0 -5
- data/spec/models/attachment.rb +0 -5
- data/spec/models/author.rb +0 -5
- data/spec/models/base_user.rb +0 -7
- data/spec/models/category.rb +0 -12
- data/spec/models/city.rb +0 -5
- data/spec/models/client.rb +0 -8
- data/spec/models/comment.rb +0 -8
- data/spec/models/company.rb +0 -5
- data/spec/models/country.rb +0 -5
- data/spec/models/deal.rb +0 -5
- data/spec/models/document.rb +0 -7
- data/spec/models/entry.rb +0 -5
- data/spec/models/firm.rb +0 -7
- data/spec/models/folder.rb +0 -4
- data/spec/models/group.rb +0 -4
- data/spec/models/mongoid/address.rb +0 -9
- data/spec/models/mongoid/category.rb +0 -10
- data/spec/models/mongoid/comment.rb +0 -9
- data/spec/models/mongoid/company.rb +0 -9
- data/spec/models/mongoid/entry.rb +0 -9
- data/spec/models/mongoid/post.rb +0 -14
- data/spec/models/mongoid/user.rb +0 -7
- data/spec/models/newspaper.rb +0 -5
- data/spec/models/page.rb +0 -4
- data/spec/models/person.rb +0 -5
- data/spec/models/pet.rb +0 -5
- data/spec/models/post.rb +0 -34
- data/spec/models/relationship.rb +0 -6
- data/spec/models/reply.rb +0 -5
- data/spec/models/role.rb +0 -7
- data/spec/models/student.rb +0 -5
- data/spec/models/submission.rb +0 -7
- data/spec/models/teacher.rb +0 -5
- data/spec/models/user.rb +0 -8
- data/spec/models/writer.rb +0 -4
- data/spec/spec_helper.rb +0 -97
- data/spec/support/bullet_ext.rb +0 -56
- data/spec/support/mongo_seed.rb +0 -59
- data/spec/support/rack_double.rb +0 -49
- data/spec/support/sqlite_seed.rb +0 -284
- data/test.sh +0 -15
- data/update.sh +0 -10
data/Rakefile
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
|
2
|
-
require 'bundler'
|
|
3
|
-
Bundler.setup
|
|
4
|
-
|
|
5
|
-
require 'rake'
|
|
6
|
-
require 'rspec'
|
|
7
|
-
require 'rspec/core/rake_task'
|
|
8
|
-
|
|
9
|
-
require 'bullet/version'
|
|
10
|
-
|
|
11
|
-
task :build do
|
|
12
|
-
system 'gem build bullet.gemspec'
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
task install: :build do
|
|
16
|
-
system "sudo gem install bullet-#{Bullet::VERSION}.gem"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
task release: :build do
|
|
20
|
-
puts "Tagging #{Bullet::VERSION}..."
|
|
21
|
-
system "git tag -a #{Bullet::VERSION} -m 'Tagging #{Bullet::VERSION}'"
|
|
22
|
-
puts 'Pushing to Github...'
|
|
23
|
-
system 'git push --tags'
|
|
24
|
-
puts 'Pushing to rubygems.org...'
|
|
25
|
-
system "gem push bullet-#{Bullet::VERSION}.gem"
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
29
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
RSpec::Core::RakeTask.new('spec:progress') do |spec|
|
|
33
|
-
spec.rspec_opts = %w[--format progress]
|
|
34
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
begin
|
|
38
|
-
require 'rdoc/task'
|
|
39
|
-
|
|
40
|
-
desc 'Generate documentation for the plugin.'
|
|
41
|
-
Rake::RDocTask.new do |rdoc|
|
|
42
|
-
rdoc.rdoc_dir = 'rdoc'
|
|
43
|
-
rdoc.title = "bullet #{Bullet::VERSION}"
|
|
44
|
-
rdoc.rdoc_files.include('README*')
|
|
45
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
46
|
-
end
|
|
47
|
-
rescue LoadError
|
|
48
|
-
puts 'RDocTask is not supported for this platform'
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
task default: :spec
|
data/bullet.gemspec
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
lib = File.expand_path('lib', __dir__)
|
|
4
|
-
$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
|
|
5
|
-
|
|
6
|
-
require 'bullet/version'
|
|
7
|
-
|
|
8
|
-
Gem::Specification.new do |s|
|
|
9
|
-
s.name = 'bullet'
|
|
10
|
-
s.version = Bullet::VERSION
|
|
11
|
-
s.platform = Gem::Platform::RUBY
|
|
12
|
-
s.authors = ['Richard Huang']
|
|
13
|
-
s.email = ['flyerhzm@gmail.com']
|
|
14
|
-
s.homepage = 'https://github.com/flyerhzm/bullet'
|
|
15
|
-
s.summary = 'help to kill N+1 queries and unused eager loading.'
|
|
16
|
-
s.description = 'help to kill N+1 queries and unused eager loading.'
|
|
17
|
-
s.metadata = {
|
|
18
|
-
'changelog_uri' => 'https://github.com/flyerhzm/bullet/blob/master/CHANGELOG.md',
|
|
19
|
-
'source_code_uri' => 'https://github.com/flyerhzm/bullet'
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
s.license = 'MIT'
|
|
23
|
-
|
|
24
|
-
s.required_ruby_version = '>= 2.3'
|
|
25
|
-
s.required_rubygems_version = '>= 1.3.6'
|
|
26
|
-
|
|
27
|
-
s.add_runtime_dependency 'activesupport', '>= 3.0.0'
|
|
28
|
-
s.add_runtime_dependency 'uniform_notifier', '~> 1.11'
|
|
29
|
-
|
|
30
|
-
s.files = `git ls-files`.split("\n")
|
|
31
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
32
|
-
s.require_paths = ['lib']
|
|
33
|
-
end
|
data/perf/benchmark.rb
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
$LOAD_PATH << 'lib'
|
|
4
|
-
require 'benchmark'
|
|
5
|
-
require 'rails'
|
|
6
|
-
require 'active_record'
|
|
7
|
-
require 'activerecord-import'
|
|
8
|
-
require 'bullet'
|
|
9
|
-
|
|
10
|
-
begin
|
|
11
|
-
require 'perftools'
|
|
12
|
-
rescue LoadError
|
|
13
|
-
puts "Could not load perftools.rb, profiling won't be possible"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class Post < ActiveRecord::Base
|
|
17
|
-
belongs_to :user
|
|
18
|
-
has_many :comments
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
class Comment < ActiveRecord::Base
|
|
22
|
-
belongs_to :user
|
|
23
|
-
belongs_to :post
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
class User < ActiveRecord::Base
|
|
27
|
-
has_many :posts
|
|
28
|
-
has_many :comments
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# create database bullet_benchmark;
|
|
32
|
-
ActiveRecord::Base.establish_connection(
|
|
33
|
-
adapter: 'mysql2',
|
|
34
|
-
database: 'bullet_benchmark',
|
|
35
|
-
server: '/tmp/mysql.socket',
|
|
36
|
-
username: 'root'
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
|
|
40
|
-
|
|
41
|
-
ActiveRecord::Schema.define(version: 1) do
|
|
42
|
-
create_table :posts do |t|
|
|
43
|
-
t.column :title, :string
|
|
44
|
-
t.column :body, :string
|
|
45
|
-
t.column :user_id, :integer
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
create_table :comments do |t|
|
|
49
|
-
t.column :body, :string
|
|
50
|
-
t.column :post_id, :integer
|
|
51
|
-
t.column :user_id, :integer
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
create_table :users do |t|
|
|
55
|
-
t.column :name, :string
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
users_size = 100
|
|
60
|
-
posts_size = 1_000
|
|
61
|
-
comments_size = 10_000
|
|
62
|
-
users = []
|
|
63
|
-
users_size.times { |i| users << User.new(name: "user#{i}") }
|
|
64
|
-
User.import users
|
|
65
|
-
users = User.all
|
|
66
|
-
|
|
67
|
-
posts = []
|
|
68
|
-
posts_size.times { |i| posts << Post.new(title: "Title #{i}", body: "Body #{i}", user: users[i % 100]) }
|
|
69
|
-
Post.import posts
|
|
70
|
-
posts = Post.all
|
|
71
|
-
|
|
72
|
-
comments = []
|
|
73
|
-
comments_size.times { |i| comments << Comment.new(body: "Comment #{i}", post: posts[i % 1_000], user: users[i % 100]) }
|
|
74
|
-
Comment.import comments
|
|
75
|
-
|
|
76
|
-
puts 'Start benchmarking...'
|
|
77
|
-
|
|
78
|
-
Bullet.enable = true
|
|
79
|
-
|
|
80
|
-
Benchmark.bm(70) do |bm|
|
|
81
|
-
bm.report("Querying & Iterating #{posts_size} Posts with #{comments_size} Comments and #{users_size} Users") do
|
|
82
|
-
10.times do
|
|
83
|
-
Bullet.start_request
|
|
84
|
-
Post.select('SQL_NO_CACHE *').includes(:user, comments: :user).each do |p|
|
|
85
|
-
p.title
|
|
86
|
-
p.user.name
|
|
87
|
-
p.comments.each do |c|
|
|
88
|
-
c.body
|
|
89
|
-
c.user.name
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
Bullet.end_request
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
puts 'End benchmarking...'
|
|
98
|
-
|
|
99
|
-
# Run benchmark with bundler
|
|
100
|
-
#
|
|
101
|
-
# bundle exec ruby perf/benchmark.rb
|
|
102
|
-
#
|
|
103
|
-
# bullet 2.3.0 with rails 3.2.2
|
|
104
|
-
# user system total real
|
|
105
|
-
# Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 16.460000 0.190000 16.650000 ( 16.968246)
|
|
106
|
-
#
|
|
107
|
-
# bullet 2.3.0 with rails 3.1.4
|
|
108
|
-
# user system total real
|
|
109
|
-
# Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 14.600000 0.130000 14.730000 ( 14.937590)
|
|
110
|
-
#
|
|
111
|
-
# bullet 2.3.0 with rails 3.0.12
|
|
112
|
-
# user system total real
|
|
113
|
-
# Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 26.120000 0.430000 26.550000 ( 27.179304)
|
|
114
|
-
#
|
|
115
|
-
#
|
|
116
|
-
# bullet 2.2.1 with rails 3.0.12
|
|
117
|
-
# user system total real
|
|
118
|
-
# Querying & Iterating 1000 Posts with 10000 Comments and 100 Users 29.970000 0.270000 30.240000 ( 30.452083)
|
data/rails/init.rb
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
module Bullet
|
|
6
|
-
module Detector
|
|
7
|
-
describe Association do
|
|
8
|
-
before :all do
|
|
9
|
-
@post1 = Post.first
|
|
10
|
-
@post2 = Post.last
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
context '.add_object_association' do
|
|
14
|
-
it 'should add object, associations pair' do
|
|
15
|
-
Association.add_object_associations(@post1, :associations)
|
|
16
|
-
expect(Association.send(:object_associations)).to be_include(@post1.bullet_key, :associations)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
context '.add_call_object_associations' do
|
|
21
|
-
it 'should add call object, associations pair' do
|
|
22
|
-
Association.add_call_object_associations(@post1, :associations)
|
|
23
|
-
expect(Association.send(:call_object_associations)).to be_include(@post1.bullet_key, :associations)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
module Bullet
|
|
6
|
-
module Detector
|
|
7
|
-
describe CounterCache do
|
|
8
|
-
before :all do
|
|
9
|
-
@post1 = Post.first
|
|
10
|
-
@post2 = Post.last
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
context '.add_counter_cache' do
|
|
14
|
-
it 'should create notification if conditions met' do
|
|
15
|
-
expect(CounterCache).to receive(:conditions_met?).with(@post1, %i[comments]).and_return(true)
|
|
16
|
-
expect(CounterCache).to receive(:create_notification).with('Post', %i[comments])
|
|
17
|
-
CounterCache.add_counter_cache(@post1, %i[comments])
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it 'should not create notification if conditions not met' do
|
|
21
|
-
expect(CounterCache).to receive(:conditions_met?).with(@post1, %i[comments]).and_return(false)
|
|
22
|
-
expect(CounterCache).to receive(:create_notification).never
|
|
23
|
-
CounterCache.add_counter_cache(@post1, %i[comments])
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
context '.add_possible_objects' do
|
|
28
|
-
it 'should add possible objects' do
|
|
29
|
-
CounterCache.add_possible_objects([@post1, @post2])
|
|
30
|
-
expect(CounterCache.possible_objects).to be_include(@post1.bullet_key)
|
|
31
|
-
expect(CounterCache.possible_objects).to be_include(@post2.bullet_key)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it 'should add impossible object' do
|
|
35
|
-
CounterCache.add_impossible_object(@post1)
|
|
36
|
-
expect(CounterCache.impossible_objects).to be_include(@post1.bullet_key)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
context '.conditions_met?' do
|
|
41
|
-
it 'should be true when object is possible, not impossible' do
|
|
42
|
-
CounterCache.add_possible_objects(@post1)
|
|
43
|
-
expect(CounterCache.conditions_met?(@post1, :associations)).to eq true
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it 'should be false when object is not possible' do
|
|
47
|
-
expect(CounterCache.conditions_met?(@post1, :associations)).to eq false
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
it 'should be false when object is possible, and impossible' do
|
|
51
|
-
CounterCache.add_possible_objects(@post1)
|
|
52
|
-
CounterCache.add_impossible_object(@post1)
|
|
53
|
-
expect(CounterCache.conditions_met?(@post1, :associations)).to eq false
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
module Bullet
|
|
6
|
-
module Detector
|
|
7
|
-
describe NPlusOneQuery do
|
|
8
|
-
before(:all) do
|
|
9
|
-
@post = Post.first
|
|
10
|
-
@post2 = Post.last
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
context '.call_association' do
|
|
14
|
-
it 'should add call_object_associations' do
|
|
15
|
-
expect(NPlusOneQuery).to receive(:add_call_object_associations).with(@post, :associations)
|
|
16
|
-
NPlusOneQuery.call_association(@post, :associations)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
context '.possible?' do
|
|
21
|
-
it 'should be true if possible_objects contain' do
|
|
22
|
-
NPlusOneQuery.add_possible_objects(@post)
|
|
23
|
-
expect(NPlusOneQuery.possible?(@post)).to eq true
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
context '.impossible?' do
|
|
28
|
-
it 'should be true if impossible_objects contain' do
|
|
29
|
-
NPlusOneQuery.add_impossible_object(@post)
|
|
30
|
-
expect(NPlusOneQuery.impossible?(@post)).to eq true
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
context '.association?' do
|
|
35
|
-
it 'should be true if object, associations pair is already existed' do
|
|
36
|
-
NPlusOneQuery.add_object_associations(@post, :association)
|
|
37
|
-
expect(NPlusOneQuery.association?(@post, :association)).to eq true
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it 'should be false if object, association pair is not existed' do
|
|
41
|
-
NPlusOneQuery.add_object_associations(@post, :association1)
|
|
42
|
-
expect(NPlusOneQuery.association?(@post, :association2)).to eq false
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
context '.conditions_met?' do
|
|
47
|
-
it 'should be true if object is possible, not impossible and object, associations pair is not already existed' do
|
|
48
|
-
allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true)
|
|
49
|
-
allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false)
|
|
50
|
-
allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false)
|
|
51
|
-
expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq true
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it 'should be false if object is not possible, not impossible and object, associations pair is not already existed' do
|
|
55
|
-
allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(false)
|
|
56
|
-
allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false)
|
|
57
|
-
allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false)
|
|
58
|
-
expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
it 'should be false if object is possible, but impossible and object, associations pair is not already existed' do
|
|
62
|
-
allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true)
|
|
63
|
-
allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(true)
|
|
64
|
-
allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false)
|
|
65
|
-
expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it 'should be false if object is possible, not impossible and object, associations pair is already existed' do
|
|
69
|
-
allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true)
|
|
70
|
-
allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false)
|
|
71
|
-
allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(true)
|
|
72
|
-
expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
context '.call_association' do
|
|
77
|
-
it 'should create notification if conditions met' do
|
|
78
|
-
expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
|
|
79
|
-
expect(NPlusOneQuery).to receive(:caller_in_project).and_return(%w[caller])
|
|
80
|
-
expect(NPlusOneQuery).to receive(:create_notification).with(%w[caller], 'Post', :association)
|
|
81
|
-
NPlusOneQuery.call_association(@post, :association)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
it 'should not create notification if conditions not met' do
|
|
85
|
-
expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(false)
|
|
86
|
-
expect(NPlusOneQuery).not_to receive(:caller_in_project!)
|
|
87
|
-
expect(NPlusOneQuery).not_to receive(:create_notification).with('Post', :association)
|
|
88
|
-
NPlusOneQuery.call_association(@post, :association)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
context 'stacktrace_excludes' do
|
|
92
|
-
before { Bullet.stacktrace_excludes = [/def/] }
|
|
93
|
-
after { Bullet.stacktrace_excludes = nil }
|
|
94
|
-
|
|
95
|
-
it 'should not create notification when stacktrace contains paths that are in the exclude list' do
|
|
96
|
-
in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
|
|
97
|
-
included_path = OpenStruct.new(absolute_path: '/ghi/ghi.rb')
|
|
98
|
-
excluded_path = OpenStruct.new(absolute_path: '/def/def.rb')
|
|
99
|
-
|
|
100
|
-
expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, included_path, excluded_path])
|
|
101
|
-
expect(NPlusOneQuery).to_not receive(:create_notification)
|
|
102
|
-
NPlusOneQuery.call_association(@post, :association)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# just a sanity spec to make sure the following spec works correctly
|
|
106
|
-
it "should create notification when stacktrace contains methods that aren't in the exclude list" do
|
|
107
|
-
method = NPlusOneQuery.method(:excluded_stacktrace_path?).source_location
|
|
108
|
-
in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
|
|
109
|
-
excluded_path = OpenStruct.new(absolute_path: method.first, lineno: method.last)
|
|
110
|
-
|
|
111
|
-
expect(NPlusOneQuery).to receive(:caller_locations).at_least(1).and_return([in_project, excluded_path])
|
|
112
|
-
expect(NPlusOneQuery).to receive(:conditions_met?).and_return(true)
|
|
113
|
-
expect(NPlusOneQuery).to receive(:create_notification)
|
|
114
|
-
NPlusOneQuery.call_association(@post, :association)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it 'should not create notification when stacktrace contains methods that are in the exclude list' do
|
|
118
|
-
method = NPlusOneQuery.method(:excluded_stacktrace_path?).source_location
|
|
119
|
-
Bullet.stacktrace_excludes = [method]
|
|
120
|
-
in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
|
|
121
|
-
excluded_path = OpenStruct.new(absolute_path: method.first, lineno: method.last)
|
|
122
|
-
|
|
123
|
-
expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, excluded_path])
|
|
124
|
-
expect(NPlusOneQuery).to_not receive(:create_notification)
|
|
125
|
-
NPlusOneQuery.call_association(@post, :association)
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
context '.add_possible_objects' do
|
|
131
|
-
it 'should add possible objects' do
|
|
132
|
-
NPlusOneQuery.add_possible_objects([@post, @post2])
|
|
133
|
-
expect(NPlusOneQuery.possible_objects).to be_include(@post.bullet_key)
|
|
134
|
-
expect(NPlusOneQuery.possible_objects).to be_include(@post2.bullet_key)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
it 'should not raise error if object is nil' do
|
|
138
|
-
expect { NPlusOneQuery.add_possible_objects(nil) }.not_to raise_error
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
context '.add_impossible_object' do
|
|
143
|
-
it 'should add impossible object' do
|
|
144
|
-
NPlusOneQuery.add_impossible_object(@post)
|
|
145
|
-
expect(NPlusOneQuery.impossible_objects).to be_include(@post.bullet_key)
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
module Bullet
|
|
6
|
-
module Detector
|
|
7
|
-
describe UnusedEagerLoading do
|
|
8
|
-
before(:all) do
|
|
9
|
-
@post = Post.first
|
|
10
|
-
@post2 = Post.all[1]
|
|
11
|
-
@post3 = Post.last
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
context '.call_associations' do
|
|
15
|
-
it 'should get empty array if eager_loadings' do
|
|
16
|
-
expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to be_empty
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it 'should get call associations if object and association are both in eager_loadings and call_object_associations' do
|
|
20
|
-
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
21
|
-
UnusedEagerLoading.add_call_object_associations(@post, :association)
|
|
22
|
-
expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to eq(
|
|
23
|
-
[:association]
|
|
24
|
-
)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it 'should not get call associations if not exist in call_object_associations' do
|
|
28
|
-
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
29
|
-
expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to be_empty
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
context '.diff_object_associations' do
|
|
34
|
-
it 'should return associations not exist in call_association' do
|
|
35
|
-
expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to eq(
|
|
36
|
-
[:association]
|
|
37
|
-
)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it 'should return empty if associations exist in call_association' do
|
|
41
|
-
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
42
|
-
UnusedEagerLoading.add_call_object_associations(@post, :association)
|
|
43
|
-
expect(
|
|
44
|
-
UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))
|
|
45
|
-
).to be_empty
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
context '.check_unused_preload_associations' do
|
|
50
|
-
let(:paths) { %w[/dir1 /dir1/subdir] }
|
|
51
|
-
it 'should create notification if object_association_diff is not empty' do
|
|
52
|
-
UnusedEagerLoading.add_object_associations(@post, :association)
|
|
53
|
-
allow(UnusedEagerLoading).to receive(:caller_in_project).and_return(paths)
|
|
54
|
-
expect(UnusedEagerLoading).to receive(:create_notification).with(paths, 'Post', [:association])
|
|
55
|
-
UnusedEagerLoading.check_unused_preload_associations
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it 'should not create notification if object_association_diff is empty' do
|
|
59
|
-
UnusedEagerLoading.add_object_associations(@post, :association)
|
|
60
|
-
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
61
|
-
UnusedEagerLoading.add_call_object_associations(@post, :association)
|
|
62
|
-
expect(
|
|
63
|
-
UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))
|
|
64
|
-
).to be_empty
|
|
65
|
-
expect(UnusedEagerLoading).not_to receive(:create_notification).with('Post', [:association])
|
|
66
|
-
UnusedEagerLoading.check_unused_preload_associations
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
it 'should create call stack for notification' do
|
|
70
|
-
UnusedEagerLoading.add_object_associations(@post, :association)
|
|
71
|
-
expect(UnusedEagerLoading.send(:call_stacks).registry).not_to be_empty
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
context '.add_eager_loadings' do
|
|
76
|
-
it 'should add objects, associations pair when eager_loadings are empty' do
|
|
77
|
-
UnusedEagerLoading.add_eager_loadings([@post, @post2], :associations)
|
|
78
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
|
79
|
-
[@post.bullet_key, @post2.bullet_key],
|
|
80
|
-
:associations
|
|
81
|
-
)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
it 'should add objects, associations pair for existing eager_loadings' do
|
|
85
|
-
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
|
|
86
|
-
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association2)
|
|
87
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
|
88
|
-
[@post.bullet_key, @post2.bullet_key],
|
|
89
|
-
:association1
|
|
90
|
-
)
|
|
91
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
|
92
|
-
[@post.bullet_key, @post2.bullet_key],
|
|
93
|
-
:association2
|
|
94
|
-
)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
it 'should merge objects, associations pair for existing eager_loadings' do
|
|
98
|
-
UnusedEagerLoading.add_eager_loadings([@post], :association1)
|
|
99
|
-
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association2)
|
|
100
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
|
|
101
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association2)
|
|
102
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post2.bullet_key], :association2)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
it 'should vmerge objects recursively, associations pair for existing eager_loadings' do
|
|
106
|
-
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
|
|
107
|
-
UnusedEagerLoading.add_eager_loadings([@post, @post3], :association1)
|
|
108
|
-
UnusedEagerLoading.add_eager_loadings([@post, @post3], :association2)
|
|
109
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
|
|
110
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association2)
|
|
111
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post2.bullet_key], :association1)
|
|
112
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post3.bullet_key], :association1)
|
|
113
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post3.bullet_key], :association2)
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
it 'should delete objects, associations pair for existing eager_loadings' do
|
|
117
|
-
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
|
|
118
|
-
UnusedEagerLoading.add_eager_loadings([@post], :association2)
|
|
119
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
|
|
120
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association2)
|
|
121
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post2.bullet_key], :association1)
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
end
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
describe Object do
|
|
6
|
-
context 'bullet_key' do
|
|
7
|
-
it 'should return class and id composition' do
|
|
8
|
-
post = Post.first
|
|
9
|
-
expect(post.bullet_key).to eq("Post:#{post.id}")
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
if mongoid?
|
|
13
|
-
it 'should return class with namespace and id composition' do
|
|
14
|
-
post = Mongoid::Post.first
|
|
15
|
-
expect(post.bullet_key).to eq("Mongoid::Post:#{post.id}")
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
context 'bullet_primary_key_value' do
|
|
21
|
-
it 'should return id' do
|
|
22
|
-
post = Post.first
|
|
23
|
-
expect(post.bullet_primary_key_value).to eq(post.id)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it 'should return primary key value' do
|
|
27
|
-
post = Post.first
|
|
28
|
-
Post.primary_key = 'name'
|
|
29
|
-
expect(post.bullet_primary_key_value).to eq(post.name)
|
|
30
|
-
Post.primary_key = 'id'
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it 'should return value for multiple primary keys' do
|
|
34
|
-
post = Post.first
|
|
35
|
-
allow(Post).to receive(:primary_keys).and_return(%i[category_id writer_id])
|
|
36
|
-
expect(post.bullet_primary_key_value).to eq("#{post.category_id},#{post.writer_id}")
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it 'it should return nil for unpersisted records' do
|
|
40
|
-
post = Post.new(id: 123)
|
|
41
|
-
expect(post.bullet_primary_key_value).to be_nil
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
describe String do
|
|
6
|
-
context 'bullet_class_name' do
|
|
7
|
-
it 'should only return class name' do
|
|
8
|
-
expect('Post:1'.bullet_class_name).to eq('Post')
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it 'should return class name with namespace' do
|
|
12
|
-
expect('Mongoid::Post:1234567890'.bullet_class_name).to eq('Mongoid::Post')
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|