mongoid 1.1.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +69 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/mongoid.rb +39 -13
- data/lib/mongoid/associations.rb +1 -0
- data/lib/mongoid/associations/has_many.rb +19 -3
- data/lib/mongoid/attributes.rb +6 -1
- data/lib/mongoid/collection.rb +106 -0
- data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
- data/lib/mongoid/collections/master.rb +28 -0
- data/lib/mongoid/collections/mimic.rb +46 -0
- data/lib/mongoid/collections/operations.rb +39 -0
- data/lib/mongoid/collections/slaves.rb +44 -0
- data/lib/mongoid/commands.rb +1 -0
- data/lib/mongoid/config.rb +61 -9
- data/lib/mongoid/contexts/enumerable.rb +24 -15
- data/lib/mongoid/contexts/mongo.rb +25 -31
- data/lib/mongoid/contexts/paging.rb +2 -2
- data/lib/mongoid/criteria.rb +48 -7
- data/lib/mongoid/criterion/exclusion.rb +2 -0
- data/lib/mongoid/criterion/optional.rb +2 -2
- data/lib/mongoid/cursor.rb +82 -0
- data/lib/mongoid/document.rb +12 -13
- data/lib/mongoid/errors.rb +35 -4
- data/lib/mongoid/extensions.rb +1 -0
- data/lib/mongoid/extensions/array/aliasing.rb +4 -0
- data/lib/mongoid/extensions/string/inflections.rb +44 -1
- data/lib/mongoid/factory.rb +17 -0
- data/lib/mongoid/finders.rb +7 -2
- data/lib/mongoid/matchers/default.rb +6 -0
- data/lib/mongoid/matchers/gt.rb +1 -1
- data/lib/mongoid/matchers/gte.rb +1 -1
- data/lib/mongoid/matchers/lt.rb +1 -1
- data/lib/mongoid/matchers/lte.rb +1 -1
- data/mongoid.gemspec +30 -5
- data/perf/benchmark.rb +5 -3
- data/spec/integration/mongoid/associations_spec.rb +12 -0
- data/spec/integration/mongoid/contexts/enumerable_spec.rb +20 -0
- data/spec/integration/mongoid/criteria_spec.rb +28 -0
- data/spec/integration/mongoid/document_spec.rb +1 -1
- data/spec/integration/mongoid/inheritance_spec.rb +2 -2
- data/spec/models/person.rb +1 -1
- data/spec/spec_helper.rb +9 -4
- data/spec/unit/mongoid/associations/has_many_spec.rb +19 -0
- data/spec/unit/mongoid/associations_spec.rb +9 -0
- data/spec/unit/mongoid/attributes_spec.rb +4 -4
- data/spec/unit/mongoid/collection_spec.rb +113 -0
- data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
- data/spec/unit/mongoid/collections/master_spec.rb +41 -0
- data/spec/unit/mongoid/collections/mimic_spec.rb +43 -0
- data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
- data/spec/unit/mongoid/commands_spec.rb +7 -0
- data/spec/unit/mongoid/config_spec.rb +52 -1
- data/spec/unit/mongoid/contexts/enumerable_spec.rb +38 -12
- data/spec/unit/mongoid/contexts/mongo_spec.rb +38 -31
- data/spec/unit/mongoid/criteria_spec.rb +20 -12
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +26 -0
- data/spec/unit/mongoid/criterion/optional_spec.rb +13 -0
- data/spec/unit/mongoid/cursor_spec.rb +74 -0
- data/spec/unit/mongoid/document_spec.rb +4 -5
- data/spec/unit/mongoid/errors_spec.rb +5 -9
- data/spec/unit/mongoid/extensions/string/inflections_spec.rb +21 -2
- data/spec/unit/mongoid/factory_spec.rb +16 -0
- data/spec/unit/mongoid_spec.rb +4 -4
- metadata +28 -3
data/perf/benchmark.rb
CHANGED
@@ -3,10 +3,12 @@ require "ruby-prof"
|
|
3
3
|
require "benchmark"
|
4
4
|
require "mongoid"
|
5
5
|
|
6
|
-
|
7
|
-
|
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.
|
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
|
@@ -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.
|
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.
|
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"
|
data/spec/models/person.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -12,15 +12,20 @@ require "mocha"
|
|
12
12
|
require "mongoid"
|
13
13
|
require "spec"
|
14
14
|
|
15
|
-
Mongoid.
|
16
|
-
|
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.
|
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
|