mongoid 1.1.4 → 1.2.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 (65) hide show
  1. data/HISTORY +69 -1
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/lib/mongoid.rb +39 -13
  5. data/lib/mongoid/associations.rb +1 -0
  6. data/lib/mongoid/associations/has_many.rb +19 -3
  7. data/lib/mongoid/attributes.rb +6 -1
  8. data/lib/mongoid/collection.rb +106 -0
  9. data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
  10. data/lib/mongoid/collections/master.rb +28 -0
  11. data/lib/mongoid/collections/mimic.rb +46 -0
  12. data/lib/mongoid/collections/operations.rb +39 -0
  13. data/lib/mongoid/collections/slaves.rb +44 -0
  14. data/lib/mongoid/commands.rb +1 -0
  15. data/lib/mongoid/config.rb +61 -9
  16. data/lib/mongoid/contexts/enumerable.rb +24 -15
  17. data/lib/mongoid/contexts/mongo.rb +25 -31
  18. data/lib/mongoid/contexts/paging.rb +2 -2
  19. data/lib/mongoid/criteria.rb +48 -7
  20. data/lib/mongoid/criterion/exclusion.rb +2 -0
  21. data/lib/mongoid/criterion/optional.rb +2 -2
  22. data/lib/mongoid/cursor.rb +82 -0
  23. data/lib/mongoid/document.rb +12 -13
  24. data/lib/mongoid/errors.rb +35 -4
  25. data/lib/mongoid/extensions.rb +1 -0
  26. data/lib/mongoid/extensions/array/aliasing.rb +4 -0
  27. data/lib/mongoid/extensions/string/inflections.rb +44 -1
  28. data/lib/mongoid/factory.rb +17 -0
  29. data/lib/mongoid/finders.rb +7 -2
  30. data/lib/mongoid/matchers/default.rb +6 -0
  31. data/lib/mongoid/matchers/gt.rb +1 -1
  32. data/lib/mongoid/matchers/gte.rb +1 -1
  33. data/lib/mongoid/matchers/lt.rb +1 -1
  34. data/lib/mongoid/matchers/lte.rb +1 -1
  35. data/mongoid.gemspec +30 -5
  36. data/perf/benchmark.rb +5 -3
  37. data/spec/integration/mongoid/associations_spec.rb +12 -0
  38. data/spec/integration/mongoid/contexts/enumerable_spec.rb +20 -0
  39. data/spec/integration/mongoid/criteria_spec.rb +28 -0
  40. data/spec/integration/mongoid/document_spec.rb +1 -1
  41. data/spec/integration/mongoid/inheritance_spec.rb +2 -2
  42. data/spec/models/person.rb +1 -1
  43. data/spec/spec_helper.rb +9 -4
  44. data/spec/unit/mongoid/associations/has_many_spec.rb +19 -0
  45. data/spec/unit/mongoid/associations_spec.rb +9 -0
  46. data/spec/unit/mongoid/attributes_spec.rb +4 -4
  47. data/spec/unit/mongoid/collection_spec.rb +113 -0
  48. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
  49. data/spec/unit/mongoid/collections/master_spec.rb +41 -0
  50. data/spec/unit/mongoid/collections/mimic_spec.rb +43 -0
  51. data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
  52. data/spec/unit/mongoid/commands_spec.rb +7 -0
  53. data/spec/unit/mongoid/config_spec.rb +52 -1
  54. data/spec/unit/mongoid/contexts/enumerable_spec.rb +38 -12
  55. data/spec/unit/mongoid/contexts/mongo_spec.rb +38 -31
  56. data/spec/unit/mongoid/criteria_spec.rb +20 -12
  57. data/spec/unit/mongoid/criterion/exclusion_spec.rb +26 -0
  58. data/spec/unit/mongoid/criterion/optional_spec.rb +13 -0
  59. data/spec/unit/mongoid/cursor_spec.rb +74 -0
  60. data/spec/unit/mongoid/document_spec.rb +4 -5
  61. data/spec/unit/mongoid/errors_spec.rb +5 -9
  62. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +21 -2
  63. data/spec/unit/mongoid/factory_spec.rb +16 -0
  64. data/spec/unit/mongoid_spec.rb +4 -4
  65. metadata +28 -3
@@ -3,10 +3,12 @@ require "ruby-prof"
3
3
  require "benchmark"
4
4
  require "mongoid"
5
5
 
6
- connection = Mongo::Connection.new
7
- Mongoid.database = connection.db("mongoid_perf_test")
6
+ Mongoid.configure do |config|
7
+ config.persist_in_safe_mode = false
8
+ config.master = Mongo::Connection.new.db("mongoid_perf_test")
9
+ end
8
10
 
9
- Mongoid.database.collection("people").drop
11
+ Mongoid.master.collection("people").drop
10
12
 
11
13
  class Person
12
14
  include Mongoid::Document
@@ -118,6 +118,18 @@ describe Mongoid::Associations do
118
118
  from_db.posts.should == [@post]
119
119
  end
120
120
 
121
+ context "when adding a new association" do
122
+
123
+ before do
124
+ @new_post = Post.new(:title => "New")
125
+ @person.posts << @new_post
126
+ end
127
+
128
+ it "rememoizes the new association" do
129
+ @person.posts.should == [ @post, @new_post ]
130
+ end
131
+ end
132
+
121
133
  context "when building" do
122
134
 
123
135
  before do
@@ -0,0 +1,20 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Contexts::Enumerable do
4
+
5
+ before do
6
+ @person = Person.new(:title => "Sir")
7
+ 10.times do |n|
8
+ @person.addresses << Address.new(:number => n, :street => "Upper Street")
9
+ end
10
+ end
11
+
12
+ describe "#paginate" do
13
+
14
+ it "paginates the embedded documents" do
15
+ addresses = @person.addresses.paginate(:page => nil, :per_page => 5)
16
+ addresses.current_page.should == 1
17
+ addresses.size.should == 5
18
+ end
19
+ end
20
+ end
@@ -2,6 +2,34 @@ require "spec_helper"
2
2
 
3
3
  describe Mongoid::Criteria do
4
4
 
5
+ describe "#excludes" do
6
+
7
+ before do
8
+ @person = Person.create(:title => "Sir", :age => 100, :aliases => ["D", "Durran"], :ssn => "666666666")
9
+ end
10
+
11
+ after do
12
+ Person.delete_all
13
+ end
14
+
15
+ context "when passed id" do
16
+
17
+ it "it properly excludes ids" do
18
+ Person.criteria.excludes(:id => @person.id).entries.should be_empty
19
+ end
20
+
21
+ end
22
+
23
+ context "when passed _id" do
24
+
25
+ it "it properly excludes ids" do
26
+ Person.criteria.excludes(:_id => @person.id).entries.should be_empty
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
5
33
  describe "#max" do
6
34
 
7
35
  before do
@@ -41,7 +41,7 @@ describe Mongoid::Document do
41
41
 
42
42
  it "gets a new or current database connection" do
43
43
  person = Person.new
44
- person.collection.should be_a_kind_of(Mongo::Collection)
44
+ person.collection.should be_a_kind_of(Mongoid::Collection)
45
45
  end
46
46
 
47
47
  end
@@ -16,7 +16,7 @@ describe Mongoid::Document do
16
16
  end
17
17
 
18
18
  it "saves in the same collection as the root" do
19
- collection = Mongoid.database.collection("canvases")
19
+ collection = Mongoid.master.collection("canvases")
20
20
  attributes = collection.find({ :name => "Test"}, {}).next_document
21
21
  attributes["version"].should == 3
22
22
  attributes["name"].should == "Test"
@@ -34,7 +34,7 @@ describe Mongoid::Document do
34
34
  end
35
35
 
36
36
  it "saves in the same collection as the root" do
37
- collection = Mongoid.database.collection("canvases")
37
+ collection = Mongoid.master.collection("canvases")
38
38
  attributes = collection.find({ :name => "Testy"}, {}).next_document
39
39
  attributes["version"].should == 2
40
40
  attributes["name"].should == "Testy"
@@ -94,4 +94,4 @@ end
94
94
 
95
95
  class Doctor < Person
96
96
  field :specialty
97
- end
97
+ end
@@ -12,15 +12,20 @@ require "mocha"
12
12
  require "mongoid"
13
13
  require "spec"
14
14
 
15
- Mongoid.config do |config|
16
- config.database = Mongo::Connection.new.db("mongoid_test")
15
+ Mongoid.configure do |config|
16
+ name = "mongoid_test"
17
+ host = "localhost"
18
+ config.master = Mongo::Connection.new.db(name)
19
+ # config.slaves = [
20
+ # Mongo::Connection.new(host, 27018, :slave_ok => true).db(name)
21
+ # ]
17
22
  end
18
23
 
19
- Dir[File.join(MODELS, "*.rb")].each {|file| require File.basename(file) }
24
+ Dir[ File.join(MODELS, "*.rb") ].sort.each { |file| require File.basename(file) }
20
25
 
21
26
  Spec::Runner.configure do |config|
22
27
  config.mock_with :mocha
23
28
  config.after :suite do
24
- Mongoid.database.collections.each(&:drop)
29
+ Mongoid.master.collections.each(&:drop)
25
30
  end
26
31
  end
@@ -399,6 +399,25 @@ describe Mongoid::Associations::HasMany do
399
399
 
400
400
  end
401
401
 
402
+ describe "#paginate" do
403
+
404
+ before do
405
+ @association = Mongoid::Associations::HasMany.new(
406
+ @document,
407
+ Mongoid::Associations::Options.new(:name => :addresses)
408
+ )
409
+ @options = { :page => 1, :per_page => 10 }
410
+ @criteria = mock
411
+ end
412
+
413
+ it "creates a criteria and paginates it" do
414
+ Mongoid::Criteria.expects(:translate).with(Address, @options).returns(@criteria)
415
+ @criteria.expects(:documents=).with(@association.target)
416
+ @criteria.expects(:paginate).returns([])
417
+ @association.paginate(@options).should == []
418
+ end
419
+ end
420
+
402
421
  describe "#push" do
403
422
 
404
423
  before do
@@ -417,6 +417,15 @@ describe Mongoid::Associations do
417
417
  @game.should respond_to(:person)
418
418
  end
419
419
 
420
+ context "when document is root level" do
421
+
422
+ it "puts an index on the foreign key" do
423
+ Game.expects(:index).with("person_id")
424
+ Game.belongs_to_related :person
425
+ end
426
+
427
+ end
428
+
420
429
  end
421
430
 
422
431
  describe ".has_one_related" do
@@ -118,7 +118,7 @@ describe Mongoid::Attributes do
118
118
  describe "#method_missing" do
119
119
 
120
120
  before do
121
- Mongoid.allow_dynamic_fields = true
121
+ Mongoid.configure.allow_dynamic_fields = true
122
122
  @attributes = {
123
123
  :testing => "Testing"
124
124
  }
@@ -155,7 +155,7 @@ describe Mongoid::Attributes do
155
155
  context "when allowing dynamic fields" do
156
156
 
157
157
  before do
158
- Mongoid.allow_dynamic_fields = true
158
+ Mongoid.configure.allow_dynamic_fields = true
159
159
  @person = Person.new(@attributes)
160
160
  end
161
161
 
@@ -180,7 +180,7 @@ describe Mongoid::Attributes do
180
180
  context "when not allowing dynamic fields" do
181
181
 
182
182
  before do
183
- Mongoid.allow_dynamic_fields = false
183
+ Mongoid.configure.allow_dynamic_fields = false
184
184
  Person.fields.delete(:nofieldstring)
185
185
  @attributes = {
186
186
  :nofieldstring => "Testing"
@@ -188,7 +188,7 @@ describe Mongoid::Attributes do
188
188
  end
189
189
 
190
190
  after do
191
- Mongoid.allow_dynamic_fields = true
191
+ Mongoid.configure.allow_dynamic_fields = true
192
192
  end
193
193
 
194
194
  it "raises an error" do
@@ -0,0 +1,113 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Collection do
4
+
5
+ let(:master) do
6
+ stub.quacks_like(Mongoid::Collections::Master.allocate)
7
+ end
8
+
9
+ let(:slaves) do
10
+ stub.quacks_like(Mongoid::Collections::Slaves.allocate)
11
+ end
12
+
13
+ let(:collection) do
14
+ Mongoid::Collection.new("people")
15
+ end
16
+
17
+ before do
18
+ collection.instance_variable_set(:@master, master)
19
+ collection.instance_variable_set(:@slaves, slaves)
20
+ end
21
+
22
+ context "Mongo::Collection write operations" do
23
+
24
+ Mongoid::Collections::Operations::WRITE.each do |name|
25
+
26
+ it "defines #{name}" do
27
+ collection.should respond_to(name)
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ context "Mongo::Collection read operations" do
34
+
35
+ Mongoid::Collections::Operations::READ.each do |name|
36
+
37
+ it "defines #{name}" do
38
+ collection.should respond_to(name)
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "#directed" do
44
+
45
+ context "when the counter is less than the maximum" do
46
+
47
+ before do
48
+ collection.instance_variable_set(:@counter, 0)
49
+ end
50
+
51
+ it "delegates to the master" do
52
+ collection.directed.should == master
53
+ end
54
+
55
+ it "increments the counter" do
56
+ collection.directed
57
+ collection.counter.should == 1
58
+ end
59
+ end
60
+
61
+ context "when the counter is at the max" do
62
+
63
+ before do
64
+ slaves.expects(:empty?).returns(false)
65
+ collection.instance_variable_set(:@counter, 10)
66
+ end
67
+
68
+ it "delegates to the slave" do
69
+ collection.directed.should == slaves
70
+ end
71
+
72
+ it "resets the counter" do
73
+ collection.directed
74
+ collection.counter.should == 0
75
+ end
76
+ end
77
+
78
+ context "when the slave does not exist" do
79
+
80
+ before do
81
+ collection.instance_variable_set(:@counter, 10)
82
+ slaves.expects(:empty?).returns(true)
83
+ end
84
+
85
+ it "delegates to the master" do
86
+ collection.directed.should == master
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "#find" do
92
+
93
+ before do
94
+ @cursor = stub.quacks_like(Mongoid::Cursor.allocate)
95
+ master.expects(:find).with({ :test => "value" }, {}).returns(@mongo_cursor)
96
+ Mongoid::Cursor.expects(:new).with(collection, @mongo_cursor).returns(@cursor)
97
+ end
98
+
99
+ it "finds are returns a cursor" do
100
+ collection.find({ :test => "value"}).should == @cursor
101
+ end
102
+
103
+ context "when a block is supplied" do
104
+
105
+ it "yields to the cursor and closes it" do
106
+ @cursor.expects(:close).returns(true)
107
+ collection.find({ :test => "value" }) do |cur|
108
+ cur.should == @cursor
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,75 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Collections::CyclicIterator do
4
+
5
+ before do
6
+ @first = stub
7
+ @second = stub
8
+ @third = stub
9
+ @fourth = stub
10
+ end
11
+
12
+ let(:array) do
13
+ [ @first, @second, @third, @fourth ]
14
+ end
15
+
16
+ describe "#initialize" do
17
+
18
+ let(:iterator) do
19
+ Mongoid::Collections::CyclicIterator.new(array)
20
+ end
21
+
22
+ it "defaults the counter to -1" do
23
+ iterator.counter.should == -1
24
+ end
25
+ end
26
+
27
+ describe "#next" do
28
+
29
+ context "when the iterator has just been created" do
30
+
31
+ let(:iterator) do
32
+ Mongoid::Collections::CyclicIterator.new(array)
33
+ end
34
+
35
+ it "returns the first element" do
36
+ iterator.next.should == @first
37
+ end
38
+ end
39
+
40
+ context "when the iterator is in the middle" do
41
+
42
+ let(:iterator) do
43
+ Mongoid::Collections::CyclicIterator.new(array)
44
+ end
45
+
46
+ before do
47
+ 2.times { iterator.next }
48
+ end
49
+
50
+ it "returns the next element given the index" do
51
+ iterator.next.should == @third
52
+ end
53
+ end
54
+
55
+ context "when the iterator is on the last element" do
56
+
57
+ let(:iterator) do
58
+ Mongoid::Collections::CyclicIterator.new(array)
59
+ end
60
+
61
+ before do
62
+ 4.times { iterator.next }
63
+ end
64
+
65
+ it "returns the first element" do
66
+ iterator.next.should == @first
67
+ end
68
+
69
+ it "resets the counter" do
70
+ iterator.next
71
+ iterator.counter.should == 0
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,41 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Collections::Master do
4
+
5
+ let(:collection) do
6
+ stub.quacks_like(Mongo::Collection.allocate)
7
+ end
8
+
9
+ let(:db) do
10
+ stub.quacks_like(Mongo::DB.allocate)
11
+ end
12
+
13
+ let(:master) do
14
+ Mongoid::Collections::Master.new(db, "people")
15
+ end
16
+
17
+ before do
18
+ db.expects(:collection).with("people").returns(collection)
19
+ end
20
+
21
+ context "Mongo::Collection operations" do
22
+
23
+ Mongoid::Collections::Operations::ALL.each do |name|
24
+
25
+ it "defines #{name}" do
26
+ master.should respond_to(name)
27
+ end
28
+
29
+ describe "##{name}" do
30
+
31
+ before do
32
+ collection.expects(name)
33
+ end
34
+
35
+ it "delegates to the collection" do
36
+ master.send(name)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end