mongo_doc 0.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.
- data/.document +5 -0
- data/.gitignore +7 -0
- data/LICENSE +20 -0
- data/README.textile +174 -0
- data/Rakefile +135 -0
- data/TODO +31 -0
- data/VERSION +1 -0
- data/data/.gitignore +2 -0
- data/examples/simple_document.rb +35 -0
- data/examples/simple_object.rb +30 -0
- data/features/finders.feature +76 -0
- data/features/mongodb.yml +7 -0
- data/features/mongodoc_base.feature +128 -0
- data/features/new_record.feature +36 -0
- data/features/partial_updates.feature +105 -0
- data/features/removing_documents.feature +68 -0
- data/features/saving_an_object.feature +15 -0
- data/features/scopes.feature +66 -0
- data/features/step_definitions/collection_steps.rb +14 -0
- data/features/step_definitions/document_steps.rb +149 -0
- data/features/step_definitions/documents.rb +30 -0
- data/features/step_definitions/finder_steps.rb +15 -0
- data/features/step_definitions/json_steps.rb +9 -0
- data/features/step_definitions/object_steps.rb +50 -0
- data/features/step_definitions/objects.rb +24 -0
- data/features/step_definitions/partial_update_steps.rb +32 -0
- data/features/step_definitions/query_steps.rb +54 -0
- data/features/step_definitions/removing_documents_steps.rb +14 -0
- data/features/step_definitions/scope_steps.rb +18 -0
- data/features/step_definitions/util_steps.rb +7 -0
- data/features/support/support.rb +10 -0
- data/features/using_criteria.feature +128 -0
- data/lib/mongo_doc/associations/collection_proxy.rb +105 -0
- data/lib/mongo_doc/associations/document_proxy.rb +56 -0
- data/lib/mongo_doc/associations/hash_proxy.rb +98 -0
- data/lib/mongo_doc/associations/proxy_base.rb +53 -0
- data/lib/mongo_doc/attributes.rb +140 -0
- data/lib/mongo_doc/bson.rb +45 -0
- data/lib/mongo_doc/collection.rb +55 -0
- data/lib/mongo_doc/connection.rb +88 -0
- data/lib/mongo_doc/contexts/enumerable.rb +128 -0
- data/lib/mongo_doc/contexts/ids.rb +41 -0
- data/lib/mongo_doc/contexts/mongo.rb +232 -0
- data/lib/mongo_doc/contexts.rb +25 -0
- data/lib/mongo_doc/criteria.rb +38 -0
- data/lib/mongo_doc/cursor.rb +32 -0
- data/lib/mongo_doc/document.rb +216 -0
- data/lib/mongo_doc/ext/array.rb +5 -0
- data/lib/mongo_doc/ext/binary.rb +7 -0
- data/lib/mongo_doc/ext/boolean_class.rb +11 -0
- data/lib/mongo_doc/ext/date.rb +16 -0
- data/lib/mongo_doc/ext/date_time.rb +13 -0
- data/lib/mongo_doc/ext/dbref.rb +7 -0
- data/lib/mongo_doc/ext/hash.rb +7 -0
- data/lib/mongo_doc/ext/nil_class.rb +5 -0
- data/lib/mongo_doc/ext/numeric.rb +17 -0
- data/lib/mongo_doc/ext/object.rb +17 -0
- data/lib/mongo_doc/ext/object_id.rb +7 -0
- data/lib/mongo_doc/ext/regexp.rb +5 -0
- data/lib/mongo_doc/ext/string.rb +5 -0
- data/lib/mongo_doc/ext/symbol.rb +5 -0
- data/lib/mongo_doc/ext/time.rb +5 -0
- data/lib/mongo_doc/finders.rb +49 -0
- data/lib/mongo_doc/matchers.rb +35 -0
- data/lib/mongo_doc/query.rb +7 -0
- data/lib/mongo_doc/scope.rb +64 -0
- data/lib/mongo_doc/validations/macros.rb +11 -0
- data/lib/mongo_doc/validations/validates_embedded.rb +13 -0
- data/lib/mongo_doc.rb +19 -0
- data/lib/mongoid/contexts/paging.rb +42 -0
- data/lib/mongoid/criteria.rb +247 -0
- data/lib/mongoid/criterion/complex.rb +21 -0
- data/lib/mongoid/criterion/exclusion.rb +65 -0
- data/lib/mongoid/criterion/inclusion.rb +92 -0
- data/lib/mongoid/criterion/optional.rb +136 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +26 -0
- data/lib/mongoid/matchers/exists.rb +13 -0
- data/lib/mongoid/matchers/gt.rb +11 -0
- data/lib/mongoid/matchers/gte.rb +11 -0
- data/lib/mongoid/matchers/in.rb +11 -0
- data/lib/mongoid/matchers/lt.rb +11 -0
- data/lib/mongoid/matchers/lte.rb +11 -0
- data/lib/mongoid/matchers/ne.rb +11 -0
- data/lib/mongoid/matchers/nin.rb +11 -0
- data/lib/mongoid/matchers/size.rb +11 -0
- data/mongo_doc.gemspec +205 -0
- data/mongod.example.yml +2 -0
- data/mongodb.example.yml +14 -0
- data/perf/mongo_doc_runner.rb +90 -0
- data/perf/ruby_driver_runner.rb +64 -0
- data/script/console +8 -0
- data/spec/associations/collection_proxy_spec.rb +200 -0
- data/spec/associations/document_proxy_spec.rb +42 -0
- data/spec/associations/hash_proxy_spec.rb +163 -0
- data/spec/attributes_spec.rb +273 -0
- data/spec/bson_matchers.rb +54 -0
- data/spec/bson_spec.rb +196 -0
- data/spec/collection_spec.rb +161 -0
- data/spec/connection_spec.rb +147 -0
- data/spec/contexts/enumerable_spec.rb +274 -0
- data/spec/contexts/ids_spec.rb +49 -0
- data/spec/contexts/mongo_spec.rb +198 -0
- data/spec/contexts_spec.rb +28 -0
- data/spec/criteria_spec.rb +33 -0
- data/spec/cursor_spec.rb +91 -0
- data/spec/document_ext.rb +9 -0
- data/spec/document_spec.rb +664 -0
- data/spec/embedded_save_spec.rb +109 -0
- data/spec/finders_spec.rb +73 -0
- data/spec/hash_matchers.rb +27 -0
- data/spec/matchers_spec.rb +342 -0
- data/spec/mongodb.yml +6 -0
- data/spec/mongodb_pairs.yml +8 -0
- data/spec/new_record_spec.rb +128 -0
- data/spec/query_spec.rb +12 -0
- data/spec/scope_spec.rb +79 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +13 -0
- metadata +290 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
|
2
|
+
|
|
3
|
+
describe "MongoDoc::Associations::DocumentProxy" do
|
|
4
|
+
class Parent
|
|
5
|
+
include MongoDoc::Document
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class Child
|
|
9
|
+
include MongoDoc::Document
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:parent) { Parent.new }
|
|
13
|
+
let(:name) {'association'}
|
|
14
|
+
|
|
15
|
+
subject do
|
|
16
|
+
MongoDoc::Associations::DocumentProxy.new(:assoc_name => name, :root => parent, :parent => parent, :assoc_class => Child)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "has the association name" do
|
|
20
|
+
subject.assoc_name.should == name
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "has the parent" do
|
|
24
|
+
subject._parent.should == parent
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "has the root" do
|
|
28
|
+
subject._root.should == parent
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "has the association class" do
|
|
32
|
+
subject.assoc_class.should == Child
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "inserts the association name the _path_to_root" do
|
|
36
|
+
subject._path_to_root(Child.new, :name1 => 'value1', :name2 => 'value2').should == {"#{name}.name1" => 'value1', "#{name}.name2" => "value2"}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "#build builds a new object" do
|
|
40
|
+
Child.should === subject.build({})
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '/spec_helper'))
|
|
2
|
+
|
|
3
|
+
describe MongoDoc::Associations::HashProxy do
|
|
4
|
+
class HashProxyTest
|
|
5
|
+
include MongoDoc::Document
|
|
6
|
+
|
|
7
|
+
key :name
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
let(:root) { stub('root', :register_save_observer => nil) }
|
|
11
|
+
let(:proxy) { MongoDoc::Associations::HashProxy.new(:assoc_name => 'has_many_name', :assoc_class => HashProxyTest, :root => root, :parent => root) }
|
|
12
|
+
let(:item) { HashProxyTest.new }
|
|
13
|
+
let(:other_item) {[1,2]}
|
|
14
|
+
|
|
15
|
+
context "#[]=" do
|
|
16
|
+
it "adds the item to the hash" do
|
|
17
|
+
proxy['new'] = item
|
|
18
|
+
proxy['new'].should == item
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context "key names must be a string or symbol constrained by BSON element name" do
|
|
22
|
+
['$invalid', 'in.valid', :_id, 'query', 1, Object.new].each do |name|
|
|
23
|
+
it "#{name} is invalid" do
|
|
24
|
+
expect do
|
|
25
|
+
proxy[name] = other_item
|
|
26
|
+
end.to raise_error(MongoDoc::InvalidEmbeddedHashKey)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
[:key, 'key'].each do |name|
|
|
31
|
+
it "#{name} is a valid name" do
|
|
32
|
+
expect do
|
|
33
|
+
proxy[name] = other_item
|
|
34
|
+
end.to_not raise_error(MongoDoc::InvalidEmbeddedHashKey)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context "when the item is not a MongoDoc::Document" do
|
|
40
|
+
|
|
41
|
+
it "does not register a save observer" do
|
|
42
|
+
root.should_not_receive(:register_save_observer)
|
|
43
|
+
proxy['new'] = other_item
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "does not set the root" do
|
|
47
|
+
other_item.should_not_receive(:_root=)
|
|
48
|
+
proxy['new'] = other_item
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context "when the item is a MongoDoc::Document" do
|
|
53
|
+
it "registers a save observer" do
|
|
54
|
+
root.should_receive(:register_save_observer)
|
|
55
|
+
proxy['new'] = item
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "sets the root" do
|
|
59
|
+
proxy['new'] = item
|
|
60
|
+
item._root.should == root
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context "#merge!" do
|
|
66
|
+
context "when the key value is not a MongoDoc::Document" do
|
|
67
|
+
|
|
68
|
+
it "does not register a save observer" do
|
|
69
|
+
root.should_not_receive(:register_save_observer)
|
|
70
|
+
proxy.merge!(:new => other_item)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "does not set the root" do
|
|
74
|
+
other_item.should_not_receive(:_root=)
|
|
75
|
+
proxy.merge!(:new => other_item)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
context "when the key value is a MongoDoc::Document" do
|
|
80
|
+
it "registers a save observer" do
|
|
81
|
+
root.should_receive(:register_save_observer)
|
|
82
|
+
proxy.merge!(:new => item)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "sets the root" do
|
|
86
|
+
proxy.merge!(:new => item)
|
|
87
|
+
item._root.should == root
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context "with a block" do
|
|
92
|
+
it "calls into the block" do
|
|
93
|
+
proxy.merge!(:new => other_item) {|k, v1, v2| @result = v2}
|
|
94
|
+
@result.should == other_item
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
context "when the key value is not a MongoDoc::Document" do
|
|
98
|
+
|
|
99
|
+
it "does not register a save observer" do
|
|
100
|
+
root.should_not_receive(:register_save_observer)
|
|
101
|
+
proxy.merge!(:new => other_item) {|k, v1, v2| v2}
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "does not set the root" do
|
|
105
|
+
other_item.should_not_receive(:_root=)
|
|
106
|
+
proxy.merge!(:new => other_item) {|k, v1, v2| v2}
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
context "when the key value is a MongoDoc::Document" do
|
|
111
|
+
it "registers a save observer" do
|
|
112
|
+
root.should_receive(:register_save_observer)
|
|
113
|
+
proxy.merge!(:new => item) {|k, v1, v2| v2}
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it "sets the root" do
|
|
117
|
+
proxy.merge!(:new => item) {|k, v1, v2| v2}
|
|
118
|
+
item._root.should == root
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
context "#replace" do
|
|
125
|
+
it "clears any existing data" do
|
|
126
|
+
proxy.should_receive(:clear)
|
|
127
|
+
proxy.replace(:new => other_item)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context "when the key value is not a MongoDoc::Document" do
|
|
131
|
+
|
|
132
|
+
it "does not register a save observer" do
|
|
133
|
+
root.should_not_receive(:register_save_observer)
|
|
134
|
+
proxy.replace(:new => other_item)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "does not set the root" do
|
|
138
|
+
other_item.should_not_receive(:_root=)
|
|
139
|
+
proxy.replace(:new => other_item)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
context "when the key value is a MongoDoc::Document" do
|
|
144
|
+
it "registers a save observer" do
|
|
145
|
+
root.should_receive(:register_save_observer)
|
|
146
|
+
proxy.replace(:new => item)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "sets the root" do
|
|
150
|
+
proxy.replace(:new => item)
|
|
151
|
+
item._root.should == root
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
context "#build" do
|
|
158
|
+
it "builds an object of the collection class from the hash attrs" do
|
|
159
|
+
name = 'built'
|
|
160
|
+
proxy.build(:key, {:name => name}).name.should == name
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
|
|
3
|
+
describe "MongoDoc::Attributes" do
|
|
4
|
+
class AttributesTest
|
|
5
|
+
include MongoDoc::Attributes
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "defines _id attribute" do
|
|
9
|
+
AttributesTest.new.should respond_to(:_id)
|
|
10
|
+
AttributesTest.new.should respond_to(:_id=)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context ".key" do
|
|
14
|
+
class TestKeys
|
|
15
|
+
include MongoDoc::Document
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "adds its arguments to _keys" do
|
|
19
|
+
TestKeys.key :attr1, :attr2
|
|
20
|
+
TestKeys._keys.should == [:attr1, :attr2]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe "accessors" do
|
|
24
|
+
before do
|
|
25
|
+
TestKeys.key :attr1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
subject do
|
|
29
|
+
TestKeys.new
|
|
30
|
+
end
|
|
31
|
+
it "has an attr1 reader" do
|
|
32
|
+
should respond_to(:attr1)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "has an attr1 writer" do
|
|
36
|
+
should respond_to(:attr1=)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe "used with inheritance" do
|
|
41
|
+
class TestParent
|
|
42
|
+
include MongoDoc::Document
|
|
43
|
+
|
|
44
|
+
key :parent_attr
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class TestChild < TestParent
|
|
48
|
+
key :child_attr
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "has its own keys" do
|
|
52
|
+
TestChild._keys.should include(:child_attr)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "has the keys from the parent class" do
|
|
56
|
+
TestChild._keys.should include(*TestParent._keys)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "does not add keys to the parent class" do
|
|
60
|
+
TestParent._keys.should_not include(:child_attr)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context ".has_one" do
|
|
66
|
+
class TestDoc
|
|
67
|
+
include MongoDoc::Document
|
|
68
|
+
|
|
69
|
+
has_one :sub_doc
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class SubDoc
|
|
73
|
+
include MongoDoc::Document
|
|
74
|
+
|
|
75
|
+
key :data
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
let(:subdoc) { SubDoc.new }
|
|
79
|
+
let(:doc) { TestDoc.new(:sub_doc => subdoc) }
|
|
80
|
+
|
|
81
|
+
it "uses a proxy" do
|
|
82
|
+
MongoDoc::Associations::DocumentProxy.should === doc.sub_doc
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "sets the subdocuments parent to the proxy" do
|
|
86
|
+
doc.sub_doc.should == subdoc._parent
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "set the subdocuments root" do
|
|
90
|
+
doc.should == subdoc._root
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context "validations" do
|
|
94
|
+
class HasOneValidationTest
|
|
95
|
+
include MongoDoc::Document
|
|
96
|
+
|
|
97
|
+
key :data
|
|
98
|
+
validates_presence_of :data
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "cascades validations down" do
|
|
102
|
+
invalid = HasOneValidationTest.new
|
|
103
|
+
TestDoc.new(:sub_doc => invalid).should have(1).error_on(:sub_doc)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
context "._attributes" do
|
|
109
|
+
class TestHasOneDoc
|
|
110
|
+
include MongoDoc::Document
|
|
111
|
+
|
|
112
|
+
key :key
|
|
113
|
+
has_one :has_one
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it "is _keys + _associations" do
|
|
117
|
+
TestHasOneDoc._attributes.should == TestHasOneDoc._keys + TestHasOneDoc._associations
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
context ".has_many" do
|
|
122
|
+
|
|
123
|
+
class SubHasManyDoc
|
|
124
|
+
include MongoDoc::Document
|
|
125
|
+
|
|
126
|
+
key :data
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
class TestHasManyDoc
|
|
130
|
+
include MongoDoc::Document
|
|
131
|
+
|
|
132
|
+
has_many :sub_docs, :class_name => 'SubHasManyDoc'
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
class TestHasManyDoc2
|
|
136
|
+
include MongoDoc::Document
|
|
137
|
+
|
|
138
|
+
has_many :sub_docs, :class_name => :sub_has_many_doc
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
class TestImplicitHasManyDoc
|
|
142
|
+
include MongoDoc::Document
|
|
143
|
+
|
|
144
|
+
has_many :sub_has_many_docs
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
let(:subdoc) { SubHasManyDoc.new }
|
|
148
|
+
let(:doc) { TestHasManyDoc.new(:sub_docs => [subdoc]) }
|
|
149
|
+
|
|
150
|
+
it "uses a proxy" do
|
|
151
|
+
MongoDoc::Associations::CollectionProxy.should === TestHasManyDoc.new.sub_docs
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it "sets the subdocuments parent to the proxy" do
|
|
155
|
+
doc.sub_docs.should == subdoc._parent
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it "set the subdocuments root to the root" do
|
|
159
|
+
doc.should == subdoc._root
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "uses the association name to find the children's class name" do
|
|
163
|
+
TestImplicitHasManyDoc.new.sub_has_many_docs.assoc_class.should == SubHasManyDoc
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "uses class_name attribute for the children's class name" do
|
|
167
|
+
TestHasManyDoc.new.sub_docs.assoc_class.should == SubHasManyDoc
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it "uses class_name attribute for the children's class name" do
|
|
171
|
+
TestHasManyDoc2.new.sub_docs.assoc_class.should == SubHasManyDoc
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
context "validations" do
|
|
175
|
+
class HasManyValidationChild
|
|
176
|
+
include MongoDoc::Document
|
|
177
|
+
|
|
178
|
+
key :data
|
|
179
|
+
validates_presence_of :data
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
class HasManyValidationTest
|
|
183
|
+
include MongoDoc::Document
|
|
184
|
+
|
|
185
|
+
has_many :subdocs, :class_name => 'HasManyValidationChild'
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
let(:invalid_child) { HasManyValidationChild.new }
|
|
189
|
+
let(:doc) { HasManyValidationTest.new(:subdocs => [invalid_child]) }
|
|
190
|
+
|
|
191
|
+
it "cascades validations and marks it in the parent" do
|
|
192
|
+
doc.should have(1).error_on(:subdocs)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "cascades validations and marks it in the child" do
|
|
196
|
+
invalid_child.should have(1).error_on(:data)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it "ignores non-document children" do
|
|
200
|
+
HasManyValidationTest.new(:subdocs => ['not a doc']).should be_valid
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
context ".has_hash" do
|
|
206
|
+
class SubHasHashDoc
|
|
207
|
+
include MongoDoc::Document
|
|
208
|
+
|
|
209
|
+
key :data
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
class TestHasHashDoc
|
|
213
|
+
include MongoDoc::Document
|
|
214
|
+
|
|
215
|
+
has_hash :sub_docs, :class_name => 'SubHasHashDoc'
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
class TestImplicitHasHashDoc
|
|
219
|
+
include MongoDoc::Document
|
|
220
|
+
|
|
221
|
+
has_hash :sub_has_hash_docs
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
let(:subdoc) { SubHasHashDoc.new }
|
|
225
|
+
let(:doc) { TestHasHashDoc.new(:sub_docs => {:key => subdoc}) }
|
|
226
|
+
|
|
227
|
+
it "uses a proxy" do
|
|
228
|
+
MongoDoc::Associations::HashProxy.should === TestHasHashDoc.new.sub_docs
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
it "sets the subdocuments parent to the proxy" do
|
|
232
|
+
doc.sub_docs.should == subdoc._parent
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it "set the subdocuments root to the root" do
|
|
236
|
+
doc.should == subdoc._root
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it "uses the association name to find the children's class name" do
|
|
240
|
+
TestImplicitHasHashDoc.new.sub_has_hash_docs.assoc_class.should == SubHasHashDoc
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
context "validations" do
|
|
244
|
+
class HasHashValidationChild
|
|
245
|
+
include MongoDoc::Document
|
|
246
|
+
|
|
247
|
+
key :data
|
|
248
|
+
validates_presence_of :data
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
class HasHashValidationTest
|
|
252
|
+
include MongoDoc::Document
|
|
253
|
+
|
|
254
|
+
has_hash :subdocs, :class_name => 'HasHashValidationChild'
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
let(:invalid_child) { HasHashValidationChild.new }
|
|
258
|
+
let(:doc) { HasHashValidationTest.new(:subdocs => {:key => invalid_child}) }
|
|
259
|
+
|
|
260
|
+
it "cascades validations and marks it in the parent" do
|
|
261
|
+
doc.should have(1).error_on(:subdocs)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
it "cascades validations and marks it in the child" do
|
|
265
|
+
invalid_child.should have(1).error_on(:data)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
it "ignores non-document children" do
|
|
269
|
+
HasHashValidationTest.new(:subdocs => {:key => 'data'}).should be_valid
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module BsonMatchers
|
|
2
|
+
class BeBsonEql
|
|
3
|
+
def initialize(expected)
|
|
4
|
+
@expected = expected
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def matches?(target)
|
|
8
|
+
@target = target
|
|
9
|
+
@target == @expected
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def failure_message
|
|
13
|
+
"expected\...#{@target.inspect}\n" +
|
|
14
|
+
"to be BSON code equivalent to\...#{@expected.inspect}\n" +
|
|
15
|
+
"Difference:\...#{@expected.diff(@target).inspect}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def negative_failure_message
|
|
19
|
+
"expected\...#{@target.inspect}\n" +
|
|
20
|
+
"to be BSON code different from\...#{@expected.inspect}"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class BeMongoEql
|
|
25
|
+
def initialize(expected, include_id)
|
|
26
|
+
@include_id = include_id
|
|
27
|
+
@expected = include_id ? expected : expected.except('_id')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def matches?(target)
|
|
31
|
+
@target = @include_id ? target : target.except('_id')
|
|
32
|
+
@target == @expected
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def failure_message
|
|
36
|
+
"expected\...#{@target.inspect}\n" +
|
|
37
|
+
"to be BSON code equivalent to\...#{@expected.inspect}\n" +
|
|
38
|
+
"Difference:\...#{@expected.diff(@target).inspect}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def negative_failure_message
|
|
42
|
+
"expected\...#{@target.inspect}\n" +
|
|
43
|
+
"to be BSON code different from\...#{@expected.inspect}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def be_bson_eql(expected)
|
|
48
|
+
BeBsonEql.new(expected)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def be_mongo_eql(expected, include_id = true)
|
|
52
|
+
BeMongoEql.new(expected, include_id)
|
|
53
|
+
end
|
|
54
|
+
end
|