mongodoc 0.1.2 → 0.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.
- data/README.textile +143 -0
- data/Rakefile +35 -3
- data/VERSION +1 -1
- data/examples/simple_document.rb +35 -0
- data/examples/simple_object.rb +32 -0
- data/features/finders.feature +72 -0
- data/features/mongodoc_base.feature +12 -2
- data/features/named_scopes.feature +66 -0
- data/features/new_record.feature +36 -0
- data/features/partial_updates.feature +105 -0
- data/features/step_definitions/criteria_steps.rb +4 -41
- data/features/step_definitions/document_steps.rb +56 -5
- data/features/step_definitions/documents.rb +14 -3
- data/features/step_definitions/finder_steps.rb +15 -0
- data/features/step_definitions/named_scope_steps.rb +18 -0
- data/features/step_definitions/partial_update_steps.rb +32 -0
- data/features/step_definitions/query_steps.rb +51 -0
- data/features/using_criteria.feature +5 -1
- data/lib/mongodoc/attributes.rb +76 -63
- data/lib/mongodoc/collection.rb +9 -9
- data/lib/mongodoc/criteria.rb +152 -161
- data/lib/mongodoc/cursor.rb +7 -5
- data/lib/mongodoc/document.rb +95 -31
- data/lib/mongodoc/finders.rb +29 -0
- data/lib/mongodoc/named_scope.rb +68 -0
- data/lib/mongodoc/parent_proxy.rb +15 -6
- data/lib/mongodoc/proxy.rb +22 -13
- data/lib/mongodoc.rb +3 -3
- data/mongodoc.gemspec +42 -14
- data/perf/mongodoc_runner.rb +90 -0
- data/perf/ruby_driver_runner.rb +64 -0
- data/spec/attributes_spec.rb +46 -12
- data/spec/collection_spec.rb +23 -23
- data/spec/criteria_spec.rb +124 -187
- data/spec/cursor_spec.rb +21 -17
- data/spec/document_ext.rb +2 -2
- data/spec/document_spec.rb +187 -218
- data/spec/embedded_save_spec.rb +104 -0
- data/spec/finders_spec.rb +81 -0
- data/spec/hash_matchers.rb +27 -0
- data/spec/named_scope_spec.rb +82 -0
- data/spec/new_record_spec.rb +216 -0
- data/spec/parent_proxy_spec.rb +8 -6
- data/spec/proxy_spec.rb +80 -0
- data/spec/spec_helper.rb +2 -0
- metadata +35 -7
- data/README.rdoc +0 -75
@@ -0,0 +1,104 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Saving embedded documents" do
|
4
|
+
class NestedDocsRoot
|
5
|
+
include MongoDoc::Document
|
6
|
+
|
7
|
+
has_many :nested_children
|
8
|
+
end
|
9
|
+
|
10
|
+
class NestedChild
|
11
|
+
include MongoDoc::Document
|
12
|
+
|
13
|
+
has_one :leaf
|
14
|
+
end
|
15
|
+
|
16
|
+
class LeafDoc
|
17
|
+
include MongoDoc::Document
|
18
|
+
|
19
|
+
key :data
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:leaf) { LeafDoc.new }
|
23
|
+
let(:data) { 'data' }
|
24
|
+
|
25
|
+
context "#save" do
|
26
|
+
let(:root) { NestedDocsRoot.new(:nested_children => [NestedChild.new(:leaf => leaf)]) }
|
27
|
+
|
28
|
+
it "calls the root document's save" do
|
29
|
+
root.should_receive(:save).with(true)
|
30
|
+
leaf.save
|
31
|
+
end
|
32
|
+
|
33
|
+
it "(with bang!) calls the root documents save!" do
|
34
|
+
root.should_receive(:save!)
|
35
|
+
leaf.save!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "update_attributes naive" do
|
40
|
+
context "with no has_many, update_attributes" do
|
41
|
+
let(:root) { NestedChild.new(:leaf => leaf) }
|
42
|
+
|
43
|
+
it "calls the root document's _naive_update_attributes with a full attribute path and not safe" do
|
44
|
+
root.should_receive(:_naive_update_attributes).with({'leaf.data' => data}, false)
|
45
|
+
leaf.update_attributes(:data => data)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
|
49
|
+
root.should_receive(:_naive_update_attributes).with({'leaf.data' => data}, true)
|
50
|
+
leaf.update_attributes!(:data => data)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "with has_many, update_attributes" do
|
55
|
+
let(:root) { NestedDocsRoot.new(:nested_children => [NestedChild.new(:leaf => leaf)]) }
|
56
|
+
|
57
|
+
it "calls the root document's _naive_update_attributes with a full attribute path and not safe" do
|
58
|
+
root.should_receive(:_naive_update_attributes).with({'nested_children.0.leaf.data' => data}, false)
|
59
|
+
leaf.update_attributes(:data => data)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
|
63
|
+
root.should_receive(:_naive_update_attributes).with({'nested_children.0.leaf.data' => data}, true)
|
64
|
+
leaf.update_attributes!(:data => data)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "update_attributes strict" do
|
70
|
+
let(:leaf_id) { 'leaf_id' }
|
71
|
+
|
72
|
+
before do
|
73
|
+
leaf.stub(:_id).and_return(leaf_id)
|
74
|
+
end
|
75
|
+
|
76
|
+
context "with no has_many, update_attributes" do
|
77
|
+
let(:root) { NestedChild.new(:leaf => leaf) }
|
78
|
+
|
79
|
+
it "calls the root document's _strict_update_attributes with a full attribute path and not safe" do
|
80
|
+
root.should_receive(:_strict_update_attributes).with({'leaf.data' => data}, false, 'leaf._id' => leaf_id)
|
81
|
+
leaf.update_attributes(:data => data, :__strict__ => true)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
|
85
|
+
root.should_receive(:_strict_update_attributes).with({'leaf.data' => data}, true, 'leaf._id' => leaf_id)
|
86
|
+
leaf.update_attributes!(:data => data, :__strict__ => true)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "with has_many, update_attributes" do
|
91
|
+
let(:root) { NestedDocsRoot.new(:nested_children => [NestedChild.new(:leaf => leaf)]) }
|
92
|
+
|
93
|
+
it "calls the root document's _naive_update_attributes with a full attribute path and not safe" do
|
94
|
+
root.should_receive(:_strict_update_attributes).with({'nested_children.0.leaf.data' => data}, false, 'nested_children.leaf._id' => leaf_id)
|
95
|
+
leaf.update_attributes(:data => data, :__strict__ => true)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "(with bang!) calls the root document's _naive_update_attributes with a full attribute path and safe" do
|
99
|
+
root.should_receive(:_strict_update_attributes).with({'nested_children.0.leaf.data' => data}, true, 'nested_children.leaf._id' => leaf_id)
|
100
|
+
leaf.update_attributes!(:data => data, :__strict__ => true)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper.rb"))
|
2
|
+
|
3
|
+
describe MongoDoc::Finders do
|
4
|
+
class FindersTest
|
5
|
+
include MongoDoc::Document
|
6
|
+
|
7
|
+
key :data
|
8
|
+
end
|
9
|
+
|
10
|
+
context ".criteria" do
|
11
|
+
it "creates a new criteria for the document" do
|
12
|
+
FindersTest.criteria.should be_a_kind_of(MongoDoc::Criteria)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "sets the criteria klass" do
|
16
|
+
FindersTest.criteria.klass.should == FindersTest
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context ".find" do
|
21
|
+
before do
|
22
|
+
@criteria = stub('criteria').as_null_object
|
23
|
+
@conditions = {:where => 'this.a > 3'}
|
24
|
+
MongoDoc::Criteria.stub(:translate).and_return(@criteria)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "creates a criteria" do
|
28
|
+
MongoDoc::Criteria.should_receive(:translate).with(FindersTest, @conditions).and_return(@criteria)
|
29
|
+
FindersTest.find(:first, @conditions)
|
30
|
+
end
|
31
|
+
|
32
|
+
[:all, :first, :last].each do |which|
|
33
|
+
it "calls #{which} on the criteria" do
|
34
|
+
@criteria.should_receive(which)
|
35
|
+
FindersTest.find(which, @conditions)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context ".find_one" do
|
41
|
+
context "with an id" do
|
42
|
+
it "calls translate with the id" do
|
43
|
+
id = 'an id'
|
44
|
+
MongoDoc::Criteria.should_receive(:translate).with(FindersTest, id)
|
45
|
+
FindersTest.find_one(id)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "with conditions" do
|
50
|
+
before do
|
51
|
+
@criteria = stub('criteria').as_null_object
|
52
|
+
@conditions = {:where => 'this.a > 3'}
|
53
|
+
end
|
54
|
+
|
55
|
+
it "calls translate with the conditions" do
|
56
|
+
MongoDoc::Criteria.should_receive(:translate).with(FindersTest, @conditions).and_return(@criteria)
|
57
|
+
FindersTest.find_one(@conditions)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "call :one on the result" do
|
61
|
+
MongoDoc::Criteria.stub(:translate).and_return(@criteria)
|
62
|
+
@criteria.should_receive(:one)
|
63
|
+
FindersTest.find_one(@conditions)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "all other finders" do
|
69
|
+
before do
|
70
|
+
@criteria = stub('criteria').as_null_object
|
71
|
+
MongoDoc::Criteria.stub(:new).and_return(@criteria)
|
72
|
+
end
|
73
|
+
|
74
|
+
[:all, :count, :first, :last].each do |which|
|
75
|
+
it "calls #{which} on the new criteria" do
|
76
|
+
@criteria.should_receive(which)
|
77
|
+
FindersTest.send(which)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class HasEntry
|
2
|
+
def initialize(expected)
|
3
|
+
@expected = expected
|
4
|
+
end
|
5
|
+
|
6
|
+
def matches?(target)
|
7
|
+
@target = target
|
8
|
+
@expected.all? do |key, value|
|
9
|
+
@target[key] == value
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def failure_message_for_should
|
14
|
+
"expected #{@target.inspect} to have entries #{@expected.inspect}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure_message_for_should_not
|
18
|
+
"expected #{@target.inspect} not to have entries #{@expected.inspect}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module HashMatchers
|
23
|
+
def has_entry(expected)
|
24
|
+
HasEntry.new(expected)
|
25
|
+
end
|
26
|
+
alias :has_entries :has_entry
|
27
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper.rb"))
|
2
|
+
|
3
|
+
describe MongoDoc::NamedScope do
|
4
|
+
|
5
|
+
module Extension
|
6
|
+
def extension_module_method
|
7
|
+
"extension module method"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class NamedScopeTest
|
12
|
+
include MongoDoc::Document
|
13
|
+
|
14
|
+
key :active
|
15
|
+
key :count
|
16
|
+
|
17
|
+
named_scope :active, :where => {:active => true} do
|
18
|
+
def extension_method
|
19
|
+
"extension method"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
named_scope :count_gt_one, :where => {:count => {'$gt' => 1}}, :extend => Extension
|
23
|
+
named_scope :at_least_count, lambda {|count| {:where => {:count => {'$gt' => count}}}}
|
24
|
+
end
|
25
|
+
|
26
|
+
context ".named_scope" do
|
27
|
+
it "adds the named scope to the hash of scopes" do
|
28
|
+
NamedScopeTest.scopes.should have_key(:active)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "creates a class method for the named scope" do
|
32
|
+
NamedScopeTest.should respond_to(:active)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "accessing a named scope" do
|
37
|
+
it "is a criteria proxy" do
|
38
|
+
MongoDoc::NamedScope::CriteriaProxy.should === NamedScopeTest.active
|
39
|
+
end
|
40
|
+
|
41
|
+
it "responds like a criteria" do
|
42
|
+
NamedScopeTest.active.should respond_to(:selector)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "instantiates the criteria" do
|
46
|
+
criteria = MongoDoc::Criteria.new(NamedScopeTest)
|
47
|
+
MongoDoc::Criteria.should_receive(:new).and_return(criteria)
|
48
|
+
NamedScopeTest.active.selector
|
49
|
+
end
|
50
|
+
|
51
|
+
it "has set the conditions on the criteria" do
|
52
|
+
NamedScopeTest.active.selector.should has_entry(:active => true)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "sets the association extension by block" do
|
56
|
+
NamedScopeTest.active.extension_method.should == "extension method"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "sets the association extension by :extend" do
|
60
|
+
NamedScopeTest.count_gt_one.extension_module_method.should == "extension module method"
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when using a lambda" do
|
64
|
+
it "accepts parameters to the criteria" do
|
65
|
+
NamedScopeTest.at_least_count(3).selector.should has_entry(:count => {'$gt' => 3})
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "chained scopes" do
|
71
|
+
it "instantiates the criteria" do
|
72
|
+
criteria = MongoDoc::Criteria.new(NamedScopeTest)
|
73
|
+
MongoDoc::Criteria.should_receive(:new).and_return(criteria)
|
74
|
+
NamedScopeTest.active.count_gt_one.selector
|
75
|
+
end
|
76
|
+
|
77
|
+
it "merges the criteria" do
|
78
|
+
NamedScopeTest.active.count_gt_one.selector.should has_entry(:count => {'$gt' => 1}, :active => true)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "MongoDoc::Document _id and #new_record?" do
|
4
|
+
class Child
|
5
|
+
include MongoDoc::Document
|
6
|
+
end
|
7
|
+
|
8
|
+
class Parent
|
9
|
+
include MongoDoc::Document
|
10
|
+
|
11
|
+
has_one :child
|
12
|
+
has_many :children
|
13
|
+
|
14
|
+
key :data
|
15
|
+
|
16
|
+
validates_presence_of :data
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
@child = Child.new
|
21
|
+
end
|
22
|
+
|
23
|
+
context "as a has one@child" do
|
24
|
+
it "when added to the parent is a new record" do
|
25
|
+
Parent.new(:data => 'data', :child => @child)
|
26
|
+
@child.should be_new_record
|
27
|
+
end
|
28
|
+
|
29
|
+
context "creating" do
|
30
|
+
before do
|
31
|
+
@id = 'id'
|
32
|
+
@collection = stub('collection')
|
33
|
+
@collection.stub(:insert).and_return(@id)
|
34
|
+
Parent.stub(:collection).and_return(@collection)
|
35
|
+
end
|
36
|
+
|
37
|
+
context ".create" do
|
38
|
+
it "when created is not a new record" do
|
39
|
+
Parent.create(:data => 'data', :child => @child)
|
40
|
+
@child.should_not be_new_record
|
41
|
+
end
|
42
|
+
|
43
|
+
it "if parent is invalid, remains a new record" do
|
44
|
+
Parent.create(:child =>@child)
|
45
|
+
@child.should be_new_record
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context ".create!" do
|
50
|
+
it "when created is not a new record" do
|
51
|
+
Parent.create!(:data => 'data', :child => @child)
|
52
|
+
@child.should_not be_new_record
|
53
|
+
end
|
54
|
+
|
55
|
+
it "if parent is invalid, remains a new record" do
|
56
|
+
Parent.create!(:child => @child) rescue nil
|
57
|
+
@child.should be_new_record
|
58
|
+
end
|
59
|
+
|
60
|
+
it "when db error is raised, remains a new record" do
|
61
|
+
@collection.stub(:insert).and_raise(Mongo::OperationFailure)
|
62
|
+
expect do
|
63
|
+
Parent.create!(:data => 'data', :child => @child)
|
64
|
+
end.should raise_error(Mongo::OperationFailure)
|
65
|
+
@child.should be_new_record
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "saving" do
|
71
|
+
before do
|
72
|
+
@id = 'id'
|
73
|
+
@collection = stub('collection')
|
74
|
+
@collection.stub(:save).and_return(@id)
|
75
|
+
Parent.stub(:collection).and_return(@collection)
|
76
|
+
end
|
77
|
+
|
78
|
+
context "#save" do
|
79
|
+
it "when saved is not a new record" do
|
80
|
+
parent = Parent.new(:data => 'data', :child => @child)
|
81
|
+
parent.save
|
82
|
+
@child.should_not be_new_record
|
83
|
+
end
|
84
|
+
|
85
|
+
it "if parent is invalid, remains a new record" do
|
86
|
+
parent = Parent.new(:child => @child)
|
87
|
+
parent.save
|
88
|
+
@child.should be_new_record
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "#save!" do
|
93
|
+
it "when saved is not a new record" do
|
94
|
+
parent = Parent.new(:data => 'data', :child => @child)
|
95
|
+
parent.save!
|
96
|
+
@child.should_not be_new_record
|
97
|
+
end
|
98
|
+
|
99
|
+
it "if parent is invalid, remains a new record" do
|
100
|
+
parent = Parent.new(:child => @child)
|
101
|
+
parent.save! rescue nil
|
102
|
+
@child.should be_new_record
|
103
|
+
end
|
104
|
+
|
105
|
+
it "when db error is raised, remains a new record" do
|
106
|
+
@collection.stub(:save).and_raise(Mongo::OperationFailure)
|
107
|
+
parent = Parent.new(:data => 'data', :child => @child)
|
108
|
+
expect do
|
109
|
+
parent.save!
|
110
|
+
end.should raise_error(Mongo::OperationFailure)
|
111
|
+
@child.should be_new_record
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "as a has many@child" do
|
118
|
+
it "when added to the parent is a new record" do
|
119
|
+
parent = Parent.new(:data => 'data')
|
120
|
+
parent.children << @child
|
121
|
+
@child.should be_new_record
|
122
|
+
end
|
123
|
+
|
124
|
+
context "creating" do
|
125
|
+
before do
|
126
|
+
@id = 'id'
|
127
|
+
@collection = stub('collection')
|
128
|
+
@collection.stub(:insert).and_return(@id)
|
129
|
+
Parent.stub(:collection).and_return(@collection)
|
130
|
+
end
|
131
|
+
|
132
|
+
context ".create" do
|
133
|
+
it "when created is not a new record" do
|
134
|
+
Parent.create(:data => 'data', :children => [@child])
|
135
|
+
@child.should_not be_new_record
|
136
|
+
end
|
137
|
+
|
138
|
+
it "if parent is invalid, remains a new record" do
|
139
|
+
Parent.create(:children => [@child])
|
140
|
+
@child.should be_new_record
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context ".create!" do
|
145
|
+
it "when created is not a new record" do
|
146
|
+
Parent.create!(:data => 'data', :children => [@child])
|
147
|
+
@child.should_not be_new_record
|
148
|
+
end
|
149
|
+
|
150
|
+
it "if parent is invalid, remains a new record" do
|
151
|
+
Parent.create!(:children => [@child]) rescue nil
|
152
|
+
@child.should be_new_record
|
153
|
+
end
|
154
|
+
|
155
|
+
it "when db error is raised, remains a new record" do
|
156
|
+
@collection.stub(:insert).and_raise(Mongo::OperationFailure)
|
157
|
+
expect do
|
158
|
+
Parent.create!(:data => 'data', :children => [@child])
|
159
|
+
end.should raise_error(Mongo::OperationFailure)
|
160
|
+
@child.should be_new_record
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context "saving" do
|
166
|
+
before do
|
167
|
+
@id = 'id'
|
168
|
+
@collection = stub('collection')
|
169
|
+
@collection.stub(:save).and_return(@id)
|
170
|
+
Parent.stub(:collection).and_return(@collection)
|
171
|
+
end
|
172
|
+
|
173
|
+
context "#save" do
|
174
|
+
it "when saved is not a new record" do
|
175
|
+
parent = Parent.new(:data => 'data')
|
176
|
+
parent.children << @child
|
177
|
+
parent.save
|
178
|
+
@child.should_not be_new_record
|
179
|
+
end
|
180
|
+
|
181
|
+
it "if parent is invalid, remains a new record" do
|
182
|
+
parent = Parent.new
|
183
|
+
parent.children << @child
|
184
|
+
parent.save
|
185
|
+
@child.should be_new_record
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context "#save!" do
|
190
|
+
it "when saved is not a new record" do
|
191
|
+
parent = Parent.new(:data => 'data')
|
192
|
+
parent.children << @child
|
193
|
+
parent.save!
|
194
|
+
@child.should_not be_new_record
|
195
|
+
end
|
196
|
+
|
197
|
+
it "if parent is invalid, remains a new record" do
|
198
|
+
parent = Parent.new
|
199
|
+
parent.children << @child
|
200
|
+
parent.save! rescue nil
|
201
|
+
@child.should be_new_record
|
202
|
+
end
|
203
|
+
|
204
|
+
it "when db error is raised, remains a new record" do
|
205
|
+
@collection.stub(:save).and_raise(Mongo::OperationFailure)
|
206
|
+
parent = Parent.new(:data => 'data')
|
207
|
+
parent.children << @child
|
208
|
+
expect do
|
209
|
+
parent.save!
|
210
|
+
end.should raise_error(Mongo::OperationFailure)
|
211
|
+
@child.should be_new_record
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
data/spec/parent_proxy_spec.rb
CHANGED
@@ -2,9 +2,11 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe "MongoDoc::ParentProxy" do
|
4
4
|
class Parent
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
include MongoDoc::Document
|
6
|
+
end
|
7
|
+
|
8
|
+
class Child
|
9
|
+
include MongoDoc::Document
|
8
10
|
end
|
9
11
|
|
10
12
|
before do
|
@@ -36,7 +38,7 @@ describe "MongoDoc::ParentProxy" do
|
|
36
38
|
end.should raise_error
|
37
39
|
end
|
38
40
|
|
39
|
-
it "inserts the association name the
|
40
|
-
subject.
|
41
|
+
it "inserts the association name the _path_to_root" do
|
42
|
+
subject._path_to_root(Child.new, :name1 => 'value1', :name2 => 'value2').should == {"#{@assoc_name}.name1" => 'value1', "#{@assoc_name}.name2" => "value2"}
|
41
43
|
end
|
42
|
-
end
|
44
|
+
end
|
data/spec/proxy_spec.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe MongoDoc::Proxy do
|
4
|
+
class ProxyTest
|
5
|
+
include MongoDoc::Document
|
6
|
+
|
7
|
+
key :name
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:root) { stub('root', :register_save_observer => nil) }
|
11
|
+
let(:proxy) { MongoDoc::Proxy.new(:assoc_name => 'has_many_name', :collection_class => ProxyTest, :root => root, :parent => root) }
|
12
|
+
|
13
|
+
context "#<<" do
|
14
|
+
let(:item) { ProxyTest.new }
|
15
|
+
|
16
|
+
it "appends the item to the collection" do
|
17
|
+
(proxy << item).should include(item)
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when the item is a Hash" do
|
21
|
+
let(:hash) {{:name => 'hash'}}
|
22
|
+
|
23
|
+
it "calls build when the item is a hash" do
|
24
|
+
proxy.should_receive(:build).with(hash).and_return(item)
|
25
|
+
proxy << hash
|
26
|
+
end
|
27
|
+
|
28
|
+
it "registers a save observer" do
|
29
|
+
proxy.stub(:build).and_return(item)
|
30
|
+
root.should_receive(:register_save_observer)
|
31
|
+
proxy << hash
|
32
|
+
end
|
33
|
+
|
34
|
+
it "sets the root" do
|
35
|
+
proxy.stub(:build).and_return(item)
|
36
|
+
proxy << hash
|
37
|
+
item._root.should == root
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when the item is not a MongoDoc::Document" do
|
42
|
+
it "does not register a save observer" do
|
43
|
+
root.should_not_receive(:register_save_observer)
|
44
|
+
proxy << 'not_doc'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "does not set the root" do
|
48
|
+
item.should_not_receive(:_root=)
|
49
|
+
proxy << 'not_doc'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when the item is a MongoDoc::Document" do
|
54
|
+
it "registers a save observer" do
|
55
|
+
root.should_receive(:register_save_observer)
|
56
|
+
proxy << item
|
57
|
+
end
|
58
|
+
|
59
|
+
it "sets the root" do
|
60
|
+
proxy << item
|
61
|
+
item._root.should == root
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when the item is an array" do
|
66
|
+
it "adds the array" do
|
67
|
+
array = ['something else']
|
68
|
+
proxy << array
|
69
|
+
proxy.should include(array)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "#build" do
|
75
|
+
it "builds an object of the collection class from the hash attrs" do
|
76
|
+
name = 'built'
|
77
|
+
proxy.build({:name => name}).name.should == name
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/spec/spec_helper.rb
CHANGED