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.
Files changed (81) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +4 -1
  3. data/Gemfile +3 -2
  4. data/Gemfile.lock +85 -69
  5. data/Guardfile +8 -0
  6. data/README.textile +2 -2
  7. data/lib/bullet/action_controller2.rb +4 -4
  8. data/lib/bullet/active_record2.rb +5 -6
  9. data/lib/bullet/active_record3.rb +2 -3
  10. data/lib/bullet/active_record31.rb +10 -12
  11. data/lib/bullet/detector/association.rb +27 -53
  12. data/lib/bullet/detector/counter.rb +34 -29
  13. data/lib/bullet/detector/n_plus_one_query.rb +47 -28
  14. data/lib/bullet/detector/unused_eager_association.rb +31 -30
  15. data/lib/bullet/notification/base.rb +14 -12
  16. data/lib/bullet/notification/n_plus_one_query.rb +6 -10
  17. data/lib/bullet/notification/unused_eager_loading.rb +1 -2
  18. data/lib/bullet/notification_collector.rb +1 -2
  19. data/lib/bullet/rack.rb +6 -3
  20. data/lib/bullet/registry/association.rb +4 -6
  21. data/lib/bullet/registry/base.rb +10 -7
  22. data/lib/bullet/registry/object.rb +6 -6
  23. data/lib/bullet/version.rb +1 -1
  24. data/lib/bullet.rb +13 -8
  25. data/perf/benchmark.rb +30 -12
  26. data/spec/bullet/detector/association_spec.rb +90 -0
  27. data/spec/bullet/detector/base_spec.rb +14 -0
  28. data/spec/bullet/detector/counter_spec.rb +65 -0
  29. data/spec/bullet/detector/n_plus_one_query_spec.rb +94 -0
  30. data/spec/bullet/detector/unused_eager_association_spec.rb +62 -0
  31. data/spec/bullet/notification/base_spec.rb +67 -0
  32. data/spec/bullet/notification/counter_cache_spec.rb +12 -0
  33. data/spec/bullet/notification/n_plus_one_query_spec.rb +13 -0
  34. data/spec/bullet/notification/unused_eager_loading_spec.rb +12 -0
  35. data/spec/bullet/notification_collector_spec.rb +32 -0
  36. data/spec/bullet/rack_spec.rb +80 -24
  37. data/spec/bullet/registry/association_spec.rb +26 -0
  38. data/spec/bullet/registry/base_spec.rb +44 -0
  39. data/spec/bullet/registry/object_spec.rb +25 -0
  40. data/spec/integration/association_for_chris_spec.rb +37 -0
  41. data/spec/integration/association_for_peschkaj_spec.rb +26 -0
  42. data/spec/{bullet → integration}/association_spec.rb +1 -359
  43. data/spec/integration/counter_spec.rb +37 -0
  44. data/spec/models/address.rb +3 -0
  45. data/spec/models/author.rb +3 -0
  46. data/spec/models/base_user.rb +5 -0
  47. data/spec/models/category.rb +7 -0
  48. data/spec/models/city.rb +3 -0
  49. data/spec/models/client.rb +4 -0
  50. data/spec/models/comment.rb +4 -0
  51. data/spec/models/company.rb +3 -0
  52. data/spec/models/contact.rb +3 -0
  53. data/spec/models/country.rb +3 -0
  54. data/spec/models/deal.rb +4 -0
  55. data/spec/models/document.rb +5 -0
  56. data/spec/models/email.rb +3 -0
  57. data/spec/models/entry.rb +3 -0
  58. data/spec/models/firm.rb +4 -0
  59. data/spec/models/folder.rb +2 -0
  60. data/spec/models/hotel.rb +4 -0
  61. data/spec/models/location.rb +3 -0
  62. data/spec/models/newspaper.rb +3 -0
  63. data/spec/models/page.rb +2 -0
  64. data/spec/models/person.rb +3 -0
  65. data/spec/models/pet.rb +3 -0
  66. data/spec/models/post.rb +11 -0
  67. data/spec/models/relationship.rb +4 -0
  68. data/spec/models/student.rb +3 -0
  69. data/spec/models/submission.rb +4 -0
  70. data/spec/models/teacher.rb +3 -0
  71. data/spec/models/user.rb +4 -0
  72. data/spec/models/writer.rb +2 -0
  73. data/spec/spec_helper.rb +16 -106
  74. data/spec/support/bullet_ext.rb +55 -0
  75. data/spec/support/rack_double.rb +55 -0
  76. data/spec/support/seed.rb +256 -0
  77. metadata +104 -14
  78. data/.watchr +0 -24
  79. data/spec/bullet/association_for_chris_spec.rb +0 -96
  80. data/spec/bullet/association_for_peschkaj_spec.rb +0 -86
  81. data/spec/bullet/counter_spec.rb +0 -136
@@ -1,125 +1,6 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
2
-
3
- ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
1
+ require 'spec_helper'
4
2
 
5
3
  describe Bullet::Detector::Association, 'has_many' do
6
-
7
- def setup_db
8
- ActiveRecord::Schema.define(:version => 1) do
9
- create_table :categories do |t|
10
- t.column :name, :string
11
- end
12
-
13
- create_table :posts do |t|
14
- t.column :name, :string
15
- t.column :category_id, :integer
16
- t.column :writer_id, :integer
17
- end
18
-
19
- create_table :comments do |t|
20
- t.column :name, :string
21
- t.column :post_id, :integer
22
- t.column :author_id, :integer
23
- end
24
-
25
- create_table :entries do |t|
26
- t.column :name, :string
27
- t.column :category_id, :integer
28
- end
29
-
30
- create_table :base_users do |t|
31
- t.column :name, :string
32
- t.column :type, :string
33
- t.column :newspaper_id, :integer
34
- end
35
- create_table :newspapers do |t|
36
- t.column :name, :string
37
- end
38
- end
39
- end
40
-
41
- def teardown_db
42
- ActiveRecord::Base.connection.tables.each do |table|
43
- ActiveRecord::Base.connection.drop_table(table)
44
- end
45
- end
46
-
47
- class Category < ActiveRecord::Base
48
- has_many :posts
49
- has_many :entries
50
- end
51
-
52
- class Post < ActiveRecord::Base
53
- belongs_to :category
54
- has_many :comments
55
- belongs_to :writer
56
-
57
-
58
- scope :preload_posts, lambda { includes(:comments) }
59
- scope :in_category_name, lambda { |name|
60
- where(['categories.name = ?', name]).includes(:category)
61
- }
62
- end
63
-
64
- class Entry < ActiveRecord::Base
65
- belongs_to :category
66
- end
67
-
68
- class Comment < ActiveRecord::Base
69
- belongs_to :post
70
- belongs_to :author, :class_name => "BaseUser"
71
- end
72
-
73
- class BaseUser < ActiveRecord::Base
74
- has_many :comments
75
- has_many :posts
76
- belongs_to :newspaper
77
- end
78
-
79
- class Newspaper < ActiveRecord::Base
80
- has_many :writers, :class_name => "BaseUser"
81
- end
82
-
83
- class Writer < BaseUser
84
- end
85
-
86
- before(:all) do
87
- setup_db
88
-
89
- newspaper1 = Newspaper.create(:name => "First Newspaper")
90
- newspaper2 = Newspaper.create(:name => "Second Newspaper")
91
-
92
- writer1 = Writer.create(:name => 'first', :newspaper => newspaper1)
93
- writer2 = Writer.create(:name => 'second', :newspaper => newspaper2)
94
- user1 = BaseUser.create(:name => 'third', :newspaper => newspaper1)
95
- user2 = BaseUser.create(:name => 'fourth', :newspaper => newspaper2)
96
-
97
-
98
- category1 = Category.create(:name => 'first')
99
- category2 = Category.create(:name => 'second')
100
-
101
- post1 = category1.posts.create(:name => 'first', :writer => writer1)
102
- post1a = category1.posts.create(:name => 'like first', :writer => writer2)
103
- post2 = category2.posts.create(:name => 'second', :writer => writer2)
104
-
105
- comment1 = post1.comments.create(:name => 'first', :author => writer1)
106
- comment2 = post1.comments.create(:name => 'first2', :author => writer1)
107
- comment3 = post1.comments.create(:name => 'first3', :author => writer1)
108
- comment4 = post1.comments.create(:name => 'second', :author => writer2)
109
- comment8 = post1a.comments.create(:name => "like first 1", :author => writer1)
110
- comment9 = post1a.comments.create(:name => "like first 2", :author => writer2)
111
- comment5 = post2.comments.create(:name => 'third', :author => user1)
112
- comment6 = post2.comments.create(:name => 'fourth', :author => user2)
113
- comment7 = post2.comments.create(:name => 'fourth', :author => writer1)
114
-
115
- entry1 = category1.entries.create(:name => 'first')
116
- entry2 = category1.entries.create(:name => 'second')
117
- end
118
-
119
- after(:all) do
120
- teardown_db
121
- end
122
-
123
4
  before(:each) do
124
5
  Bullet.start_request
125
6
  end
@@ -482,54 +363,6 @@ describe Bullet::Detector::Association, 'has_many' do
482
363
  end
483
364
 
484
365
  describe Bullet::Detector::Association, 'has_and_belongs_to_many' do
485
-
486
- def setup_db
487
- ActiveRecord::Schema.define(:version => 1) do
488
- create_table :students do |t|
489
- t.column :name, :string
490
- end
491
-
492
- create_table :teachers do |t|
493
- t.column :name, :string
494
- end
495
-
496
- create_table :students_teachers, :id => false do |t|
497
- t.column :student_id, :integer
498
- t.column :teacher_id, :integer
499
- end
500
- end
501
- end
502
-
503
- def teardown_db
504
- ActiveRecord::Base.connection.tables.each do |table|
505
- ActiveRecord::Base.connection.drop_table(table)
506
- end
507
- end
508
-
509
- class Student < ActiveRecord::Base
510
- has_and_belongs_to_many :teachers
511
- end
512
-
513
- class Teacher < ActiveRecord::Base
514
- has_and_belongs_to_many :students
515
- end
516
-
517
- before(:all) do
518
- setup_db
519
- student1 = Student.create(:name => 'first')
520
- student2 = Student.create(:name => 'second')
521
- teacher1 = Teacher.create(:name => 'first')
522
- teacher2 = Teacher.create(:name => 'second')
523
- student1.teachers = [teacher1, teacher2]
524
- student2.teachers = [teacher1, teacher2]
525
- teacher1.students << student1
526
- teacher2.students << student2
527
- end
528
-
529
- after(:all) do
530
- teardown_db
531
- end
532
-
533
366
  before(:each) do
534
367
  Bullet.start_request
535
368
  end
@@ -566,61 +399,6 @@ describe Bullet::Detector::Association, 'has_and_belongs_to_many' do
566
399
  end
567
400
 
568
401
  describe Bullet::Detector::Association, 'has_many :through' do
569
-
570
- def setup_db
571
- ActiveRecord::Schema.define(:version => 1) do
572
- create_table :firms do |t|
573
- t.column :name, :string
574
- end
575
-
576
- create_table :clients do |t|
577
- t.column :name, :string
578
- end
579
-
580
- create_table :relationships do |t|
581
- t.column :firm_id, :integer
582
- t.column :client_id, :integer
583
- end
584
- end
585
- end
586
-
587
- def teardown_db
588
- ActiveRecord::Base.connection.tables.each do |table|
589
- ActiveRecord::Base.connection.drop_table(table)
590
- end
591
- end
592
-
593
- class Firm < ActiveRecord::Base
594
- has_many :relationships
595
- has_many :clients, :through => :relationships
596
- end
597
-
598
- class Client < ActiveRecord::Base
599
- has_many :relationships
600
- has_many :firms, :through => :relationships
601
- end
602
-
603
- class Relationship < ActiveRecord::Base
604
- belongs_to :firm
605
- belongs_to :client
606
- end
607
-
608
- before(:all) do
609
- setup_db
610
- firm1 = Firm.create(:name => 'first')
611
- firm2 = Firm.create(:name => 'second')
612
- client1 = Client.create(:name => 'first')
613
- client2 = Client.create(:name => 'second')
614
- firm1.clients = [client1, client2]
615
- firm2.clients = [client1, client2]
616
- client1.firms << firm1
617
- client2.firms << firm2
618
- end
619
-
620
- after(:all) do
621
- teardown_db
622
- end
623
-
624
402
  before(:each) do
625
403
  Bullet.start_request
626
404
  end
@@ -659,48 +437,6 @@ end
659
437
 
660
438
 
661
439
  describe Bullet::Detector::Association, "has_one" do
662
-
663
- def setup_db
664
- ActiveRecord::Schema.define(:version => 1) do
665
- create_table :companies do |t|
666
- t.column :name, :string
667
- end
668
-
669
- create_table :addresses do |t|
670
- t.column :name, :string
671
- t.column :company_id, :integer
672
- end
673
- end
674
- end
675
-
676
- def teardown_db
677
- ActiveRecord::Base.connection.tables.each do |table|
678
- ActiveRecord::Base.connection.drop_table(table)
679
- end
680
- end
681
-
682
- class Company < ActiveRecord::Base
683
- has_one :address
684
- end
685
-
686
- class Address < ActiveRecord::Base
687
- belongs_to :company
688
- end
689
-
690
- before(:all) do
691
- setup_db
692
-
693
- company1 = Company.create(:name => 'first')
694
- company2 = Company.create(:name => 'second')
695
-
696
- Address.create(:name => 'first', :company => company1)
697
- Address.create(:name => 'second', :company => company2)
698
- end
699
-
700
- after(:all) do
701
- teardown_db
702
- end
703
-
704
440
  before(:each) do
705
441
  Bullet.start_request
706
442
  end
@@ -737,50 +473,6 @@ describe Bullet::Detector::Association, "has_one" do
737
473
  end
738
474
 
739
475
  describe Bullet::Detector::Association, "call one association that in possible objects" do
740
-
741
- def setup_db
742
- ActiveRecord::Schema.define(:version => 1) do
743
- create_table :contacts do |t|
744
- t.column :name, :string
745
- end
746
-
747
- create_table :emails do |t|
748
- t.column :name, :string
749
- t.column :contact_id, :integer
750
- end
751
- end
752
- end
753
-
754
- def teardown_db
755
- ActiveRecord::Base.connection.tables.each do |table|
756
- ActiveRecord::Base.connection.drop_table(table)
757
- end
758
- end
759
-
760
- class Contact < ActiveRecord::Base
761
- has_many :emails
762
- end
763
-
764
- class Email < ActiveRecord::Base
765
- belongs_to :contact
766
- end
767
-
768
- before(:all) do
769
- setup_db
770
-
771
- contact1 = Contact.create(:name => 'first')
772
- contact2 = Contact.create(:name => 'second')
773
-
774
- email1 = contact1.emails.create(:name => 'first')
775
- email2 = contact1.emails.create(:name => 'second')
776
- email3 = contact2.emails.create(:name => 'third')
777
- email4 = contact2.emails.create(:name => 'fourth')
778
- end
779
-
780
- after(:all) do
781
- teardown_db
782
- end
783
-
784
476
  before(:each) do
785
477
  Bullet.start_request
786
478
  end
@@ -797,56 +489,6 @@ describe Bullet::Detector::Association, "call one association that in possible o
797
489
  end
798
490
 
799
491
  describe Bullet::Detector::Association, "STI" do
800
-
801
- def setup_db
802
- ActiveRecord::Schema.define(:version => 1) do
803
- create_table :documents do |t|
804
- t.string :name
805
- t.string :type
806
- t.integer :parent_id
807
- t.integer :author_id
808
- end
809
-
810
- create_table :authors do |t|
811
- t.string :name
812
- end
813
- end
814
- end
815
-
816
- def teardown_db
817
- ActiveRecord::Base.connection.tables.each do |table|
818
- ActiveRecord::Base.connection.drop_table(table)
819
- end
820
- end
821
-
822
- class Document < ActiveRecord::Base
823
- has_many :children, :class_name => "Document", :foreign_key => 'parent_id'
824
- belongs_to :parent, :class_name => "Document", :foreign_key => 'parent_id'
825
- belongs_to :author
826
- end
827
-
828
- class Page < Document
829
- end
830
-
831
- class Folder < Document
832
- end
833
-
834
- class Author < ActiveRecord::Base
835
- has_many :documents
836
- end
837
-
838
- before(:all) do
839
- setup_db
840
- author1 = Author.create(:name => 'author1')
841
- author2 = Author.create(:name => 'author2')
842
- folder1 = Folder.create(:name => 'folder1', :author_id => author1.id)
843
- folder2 = Folder.create(:name => 'folder2', :author_id => author2.id)
844
- page1 = Page.create(:name => 'page1', :parent_id => folder1.id, :author_id => author1.id)
845
- page2 = Page.create(:name => 'page2', :parent_id => folder1.id, :author_id => author1.id)
846
- page3 = Page.create(:name => 'page3', :parent_id => folder2.id, :author_id => author2.id)
847
- page4 = Page.create(:name => 'page4', :parent_id => folder2.id, :author_id => author2.id)
848
- end
849
-
850
492
  before(:each) do
851
493
  Bullet.start_request
852
494
  end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bullet::Detector::Counter do
4
+ before(:each) do
5
+ Bullet.start_request
6
+ end
7
+
8
+ after(:each) do
9
+ Bullet.end_request
10
+ end
11
+
12
+ it "should need counter cache with all cities" do
13
+ Country.all.each do |country|
14
+ country.cities.size
15
+ end
16
+ Bullet.collected_counter_cache_notifications.should_not be_empty
17
+ end
18
+
19
+ it "should not need counter cache if already define counter_cache" do
20
+ Person.all.each do |person|
21
+ person.pets.size
22
+ end
23
+ Bullet.collected_counter_cache_notifications.should be_empty
24
+ end
25
+
26
+ it "should not need counter cache with only one object" do
27
+ Country.first.cities.size
28
+ Bullet.collected_counter_cache_notifications.should be_empty
29
+ end
30
+
31
+ it "should not need counter cache with part of cities" do
32
+ Country.all.each do |country|
33
+ country.cities.where(:name => 'first').size
34
+ end
35
+ Bullet.collected_counter_cache_notifications.should be_empty
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ class Address < ActiveRecord::Base
2
+ belongs_to :company
3
+ end
@@ -0,0 +1,3 @@
1
+ class Author < ActiveRecord::Base
2
+ has_many :documents
3
+ end
@@ -0,0 +1,5 @@
1
+ class BaseUser < ActiveRecord::Base
2
+ has_many :comments
3
+ has_many :posts
4
+ belongs_to :newspaper
5
+ end
@@ -0,0 +1,7 @@
1
+ class Category < ActiveRecord::Base
2
+ has_many :posts
3
+ has_many :entries
4
+
5
+ has_many :submissions
6
+ has_many :users
7
+ end
@@ -0,0 +1,3 @@
1
+ class City < ActiveRecord::Base
2
+ belongs_to :country
3
+ end
@@ -0,0 +1,4 @@
1
+ class Client < ActiveRecord::Base
2
+ has_many :relationships
3
+ has_many :firms, :through => :relationships
4
+ end
@@ -0,0 +1,4 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :post
3
+ belongs_to :author, :class_name => "BaseUser"
4
+ end
@@ -0,0 +1,3 @@
1
+ class Company < ActiveRecord::Base
2
+ has_one :address
3
+ end
@@ -0,0 +1,3 @@
1
+ class Contact < ActiveRecord::Base
2
+ has_many :emails
3
+ end
@@ -0,0 +1,3 @@
1
+ class Country < ActiveRecord::Base
2
+ has_many :cities
3
+ end
@@ -0,0 +1,4 @@
1
+ class Deal < ActiveRecord::Base
2
+ belongs_to :hotel
3
+ has_one :location, :through => :hotel
4
+ end
@@ -0,0 +1,5 @@
1
+ class Document < ActiveRecord::Base
2
+ has_many :children, :class_name => "Document", :foreign_key => 'parent_id'
3
+ belongs_to :parent, :class_name => "Document", :foreign_key => 'parent_id'
4
+ belongs_to :author
5
+ end
@@ -0,0 +1,3 @@
1
+ class Email < ActiveRecord::Base
2
+ belongs_to :contact
3
+ end
@@ -0,0 +1,3 @@
1
+ class Entry < ActiveRecord::Base
2
+ belongs_to :category
3
+ end
@@ -0,0 +1,4 @@
1
+ class Firm < ActiveRecord::Base
2
+ has_many :relationships
3
+ has_many :clients, :through => :relationships
4
+ end
@@ -0,0 +1,2 @@
1
+ class Folder < Document
2
+ end
@@ -0,0 +1,4 @@
1
+ class Hotel < ActiveRecord::Base
2
+ belongs_to :location
3
+ has_many :deals
4
+ end
@@ -0,0 +1,3 @@
1
+ class Location < ActiveRecord::Base
2
+ has_many :hotels
3
+ end
@@ -0,0 +1,3 @@
1
+ class Newspaper < ActiveRecord::Base
2
+ has_many :writers, :class_name => "BaseUser"
3
+ end
@@ -0,0 +1,2 @@
1
+ class Page < Document
2
+ end
@@ -0,0 +1,3 @@
1
+ class Person < ActiveRecord::Base
2
+ has_many :pets
3
+ end
@@ -0,0 +1,3 @@
1
+ class Pet < ActiveRecord::Base
2
+ belongs_to :person, :counter_cache => true
3
+ end
@@ -0,0 +1,11 @@
1
+ class Post < ActiveRecord::Base
2
+ belongs_to :category
3
+ has_many :comments
4
+ belongs_to :writer
5
+
6
+
7
+ scope :preload_posts, lambda { includes(:comments) }
8
+ scope :in_category_name, lambda { |name|
9
+ where(['categories.name = ?', name]).includes(:category)
10
+ }
11
+ end
@@ -0,0 +1,4 @@
1
+ class Relationship < ActiveRecord::Base
2
+ belongs_to :firm
3
+ belongs_to :client
4
+ end
@@ -0,0 +1,3 @@
1
+ class Student < ActiveRecord::Base
2
+ has_and_belongs_to_many :teachers
3
+ end
@@ -0,0 +1,4 @@
1
+ class Submission < ActiveRecord::Base
2
+ belongs_to :category
3
+ belongs_to :user
4
+ end
@@ -0,0 +1,3 @@
1
+ class Teacher < ActiveRecord::Base
2
+ has_and_belongs_to_many :students
3
+ end
@@ -0,0 +1,4 @@
1
+ class User < ActiveRecord::Base
2
+ has_one :submission
3
+ belongs_to :category
4
+ end
@@ -0,0 +1,2 @@
1
+ class Writer < BaseUser
2
+ end