jnunemaker-mongomapper 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/History +17 -0
- data/README.rdoc +6 -3
- data/Rakefile +3 -2
- data/VERSION +1 -1
- data/bin/mmconsole +56 -0
- data/lib/mongomapper.rb +48 -17
- data/lib/mongomapper/associations.rb +31 -39
- data/lib/mongomapper/associations/base.rb +40 -22
- data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +33 -0
- data/lib/mongomapper/associations/belongs_to_proxy.rb +10 -14
- data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +34 -0
- data/lib/mongomapper/associations/{has_many_embedded_proxy.rb → many_embedded_proxy.rb} +5 -5
- data/lib/mongomapper/associations/many_proxy.rb +55 -0
- data/lib/mongomapper/associations/proxy.rb +21 -14
- data/lib/mongomapper/callbacks.rb +1 -1
- data/lib/mongomapper/document.rb +82 -59
- data/lib/mongomapper/embedded_document.rb +121 -130
- data/lib/mongomapper/finder_options.rb +21 -6
- data/lib/mongomapper/key.rb +5 -7
- data/lib/mongomapper/observing.rb +1 -41
- data/lib/mongomapper/pagination.rb +52 -0
- data/lib/mongomapper/rails_compatibility/document.rb +15 -0
- data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
- data/lib/mongomapper/serialization.rb +1 -1
- data/mongomapper.gemspec +62 -36
- data/test/NOTE_ON_TESTING +1 -0
- data/test/functional/test_associations.rb +485 -0
- data/test/{test_callbacks.rb → functional/test_callbacks.rb} +2 -1
- data/test/functional/test_document.rb +636 -0
- data/test/functional/test_pagination.rb +82 -0
- data/test/functional/test_rails_compatibility.rb +31 -0
- data/test/functional/test_validations.rb +172 -0
- data/test/models.rb +92 -0
- data/test/test_helper.rb +5 -0
- data/test/{serializers → unit/serializers}/test_json_serializer.rb +0 -0
- data/test/unit/test_association_base.rb +131 -0
- data/test/unit/test_document.rb +115 -0
- data/test/{test_embedded_document.rb → unit/test_embedded_document.rb} +158 -66
- data/test/{test_finder_options.rb → unit/test_finder_options.rb} +66 -0
- data/test/{test_key.rb → unit/test_key.rb} +13 -1
- data/test/unit/test_mongo_id.rb +35 -0
- data/test/{test_mongomapper.rb → unit/test_mongomapper.rb} +0 -0
- data/test/{test_observing.rb → unit/test_observing.rb} +0 -0
- data/test/unit/test_pagination.rb +113 -0
- data/test/unit/test_rails_compatibility.rb +34 -0
- data/test/{test_serializations.rb → unit/test_serializations.rb} +0 -2
- data/test/{test_validations.rb → unit/test_validations.rb} +0 -134
- metadata +68 -36
- data/lib/mongomapper/associations/has_many_proxy.rb +0 -28
- data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +0 -31
- data/lib/mongomapper/rails_compatibility.rb +0 -23
- data/test/test_associations.rb +0 -149
- data/test/test_document.rb +0 -944
- data/test/test_rails_compatibility.rb +0 -29
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DocumentTest < Test::Unit::TestCase
|
4
|
+
context "The Document Class" do
|
5
|
+
setup do
|
6
|
+
@document = Class.new do
|
7
|
+
include MongoMapper::Document
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
should "track its descendants" do
|
12
|
+
MongoMapper::Document.descendants.should include(@document)
|
13
|
+
end
|
14
|
+
|
15
|
+
should "use default database by default" do
|
16
|
+
@document.database.should == MongoMapper.database
|
17
|
+
end
|
18
|
+
|
19
|
+
should "have a connection" do
|
20
|
+
@document.connection.should be_instance_of(XGen::Mongo::Driver::Mongo)
|
21
|
+
end
|
22
|
+
|
23
|
+
should "allow setting different connection without affecting the default" do
|
24
|
+
conn = XGen::Mongo::Driver::Mongo.new
|
25
|
+
@document.connection conn
|
26
|
+
@document.connection.should == conn
|
27
|
+
@document.connection.should_not == MongoMapper.connection
|
28
|
+
end
|
29
|
+
|
30
|
+
should "allow setting a different database without affecting the default" do
|
31
|
+
@document.database AlternateDatabase
|
32
|
+
@document.database.name.should == AlternateDatabase
|
33
|
+
|
34
|
+
another_document = Class.new do
|
35
|
+
include MongoMapper::Document
|
36
|
+
end
|
37
|
+
another_document.database.should == MongoMapper.database
|
38
|
+
end
|
39
|
+
|
40
|
+
should "default collection name to class name tableized" do
|
41
|
+
class Item
|
42
|
+
include MongoMapper::Document
|
43
|
+
end
|
44
|
+
|
45
|
+
Item.collection.should be_instance_of(XGen::Mongo::Driver::Collection)
|
46
|
+
Item.collection.name.should == 'items'
|
47
|
+
end
|
48
|
+
|
49
|
+
should "allow setting the collection name" do
|
50
|
+
@document.collection('foobar')
|
51
|
+
@document.collection.should be_instance_of(XGen::Mongo::Driver::Collection)
|
52
|
+
@document.collection.name.should == 'foobar'
|
53
|
+
end
|
54
|
+
end # Document class
|
55
|
+
|
56
|
+
context "An instance of a document" do
|
57
|
+
setup do
|
58
|
+
@document = Class.new do
|
59
|
+
include MongoMapper::Document
|
60
|
+
|
61
|
+
key :name, String
|
62
|
+
key :age, Integer
|
63
|
+
end
|
64
|
+
@document.collection.clear
|
65
|
+
end
|
66
|
+
|
67
|
+
should "have access to the class's collection" do
|
68
|
+
doc = @document.new
|
69
|
+
doc.collection.should == @document.collection
|
70
|
+
end
|
71
|
+
|
72
|
+
should "automatically have an _id key" do
|
73
|
+
@document.keys.keys.should include('_id')
|
74
|
+
end
|
75
|
+
|
76
|
+
should "automatically have a created_at key" do
|
77
|
+
@document.keys.keys.should include('created_at')
|
78
|
+
end
|
79
|
+
|
80
|
+
should "automatically have an updated_at key" do
|
81
|
+
@document.keys.keys.should include('updated_at')
|
82
|
+
end
|
83
|
+
|
84
|
+
should "use default values if defined for keys" do
|
85
|
+
@document.key :active, Boolean, :default => true
|
86
|
+
|
87
|
+
@document.new.active.should be_true
|
88
|
+
@document.new(:active => false).active.should be_false
|
89
|
+
end
|
90
|
+
|
91
|
+
context "new?" do
|
92
|
+
should "be true if no id" do
|
93
|
+
@document.new.new?.should be(true)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "equality" do
|
98
|
+
should "be equal if id and class are the same" do
|
99
|
+
(@document.new('_id' => 1) == @document.new('_id' => 1)).should be(true)
|
100
|
+
end
|
101
|
+
|
102
|
+
should "not be equal if class same but id different" do
|
103
|
+
(@document.new('_id' => 1) == @document.new('_id' => 2)).should be(false)
|
104
|
+
end
|
105
|
+
|
106
|
+
should "not be equal if id same but class different" do
|
107
|
+
@another_document = Class.new do
|
108
|
+
include MongoMapper::Document
|
109
|
+
end
|
110
|
+
|
111
|
+
(@document.new('_id' => 1) == @another_document.new('_id' => 1)).should be(false)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end # instance of a document
|
115
|
+
end # DocumentTest
|
@@ -1,5 +1,25 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
+
class Grandparent
|
4
|
+
include MongoMapper::EmbeddedDocument
|
5
|
+
key :grandparent, String
|
6
|
+
end
|
7
|
+
|
8
|
+
class Parent < Grandparent
|
9
|
+
include MongoMapper::EmbeddedDocument
|
10
|
+
key :parent, String
|
11
|
+
end
|
12
|
+
|
13
|
+
class Child < Parent
|
14
|
+
include MongoMapper::EmbeddedDocument
|
15
|
+
key :child, String
|
16
|
+
end
|
17
|
+
|
18
|
+
class OtherChild < Parent
|
19
|
+
include MongoMapper::EmbeddedDocument
|
20
|
+
key :other_child, String
|
21
|
+
end
|
22
|
+
|
3
23
|
class EmbeddedDocumentTest < Test::Unit::TestCase
|
4
24
|
context "Including MongoMapper::EmbeddedDocument" do
|
5
25
|
setup do
|
@@ -7,33 +27,135 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
7
27
|
include MongoMapper::EmbeddedDocument
|
8
28
|
end
|
9
29
|
end
|
10
|
-
|
30
|
+
|
11
31
|
should "clear out document default keys" do
|
12
32
|
@klass.keys.size.should == 0
|
13
33
|
end
|
14
34
|
end
|
15
35
|
|
36
|
+
context "parent_model" do
|
37
|
+
should "be nil if none of parents ancestors include EmbeddedDocument" do
|
38
|
+
parent = Class.new
|
39
|
+
document = Class.new(parent) do
|
40
|
+
include MongoMapper::EmbeddedDocument
|
41
|
+
end
|
42
|
+
document.parent_model.should be_nil
|
43
|
+
end
|
44
|
+
|
45
|
+
should "find parent" do
|
46
|
+
Parent.parent_model.should == Grandparent
|
47
|
+
Child.parent_model.should == Parent
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "defining a key" do
|
52
|
+
setup do
|
53
|
+
@document = Class.new do
|
54
|
+
include MongoMapper::EmbeddedDocument
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
should "work" do
|
59
|
+
key = @document.key(:name, String)
|
60
|
+
key.name.should == 'name'
|
61
|
+
key.type.should == String
|
62
|
+
key.should be_instance_of(MongoMapper::Key)
|
63
|
+
end
|
64
|
+
|
65
|
+
should "work with options" do
|
66
|
+
key = @document.key(:name, String, :required => true)
|
67
|
+
key.options[:required].should be(true)
|
68
|
+
end
|
69
|
+
|
70
|
+
should "be tracked per document" do
|
71
|
+
@document.key(:name, String)
|
72
|
+
@document.key(:age, Integer)
|
73
|
+
@document.keys['name'].name.should == 'name'
|
74
|
+
@document.keys['name'].type.should == String
|
75
|
+
@document.keys['age'].name.should == 'age'
|
76
|
+
@document.keys['age'].type.should == Integer
|
77
|
+
end
|
78
|
+
|
79
|
+
should "be redefinable" do
|
80
|
+
@document.key(:foo, String)
|
81
|
+
@document.keys['foo'].type.should == String
|
82
|
+
@document.key(:foo, Integer)
|
83
|
+
@document.keys['foo'].type.should == Integer
|
84
|
+
end
|
85
|
+
|
86
|
+
should "create reader method" do
|
87
|
+
@document.new.should_not respond_to(:foo)
|
88
|
+
@document.key(:foo, String)
|
89
|
+
@document.new.should respond_to(:foo)
|
90
|
+
end
|
91
|
+
|
92
|
+
should "create reader before typecast method" do
|
93
|
+
@document.new.should_not respond_to(:foo_before_typecast)
|
94
|
+
@document.key(:foo, String)
|
95
|
+
@document.new.should respond_to(:foo_before_typecast)
|
96
|
+
end
|
97
|
+
|
98
|
+
should "create writer method" do
|
99
|
+
@document.new.should_not respond_to(:foo=)
|
100
|
+
@document.key(:foo, String)
|
101
|
+
@document.new.should respond_to(:foo=)
|
102
|
+
end
|
103
|
+
|
104
|
+
should "create boolean method" do
|
105
|
+
@document.new.should_not respond_to(:foo?)
|
106
|
+
@document.key(:foo, String)
|
107
|
+
@document.new.should respond_to(:foo?)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "keys" do
|
112
|
+
should "be inherited" do
|
113
|
+
Grandparent.keys.keys.should == ['grandparent']
|
114
|
+
Parent.keys.keys.sort.should == ['grandparent', 'parent']
|
115
|
+
Child.keys.keys.sort.should == ['child', 'grandparent', 'parent']
|
116
|
+
end
|
117
|
+
|
118
|
+
should "propogate to subclasses if key added after class definition" do
|
119
|
+
Grandparent.key :_type, String
|
120
|
+
|
121
|
+
Grandparent.keys.keys.sort.should == ['_type', 'grandparent']
|
122
|
+
Parent.keys.keys.sort.should == ['_type', 'grandparent', 'parent']
|
123
|
+
Child.keys.keys.sort.should == ['_type', 'child', 'grandparent', 'parent']
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "subclasses" do
|
128
|
+
should "default to nil" do
|
129
|
+
Child.subclasses.should be_nil
|
130
|
+
end
|
131
|
+
|
132
|
+
should "be recorded" do
|
133
|
+
Grandparent.subclasses.should == [Parent]
|
134
|
+
Parent.subclasses.should == [Child, OtherChild]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
16
138
|
context "An instance of an embedded document" do
|
17
139
|
setup do
|
18
140
|
@document = Class.new do
|
19
141
|
include MongoMapper::EmbeddedDocument
|
20
|
-
|
142
|
+
|
21
143
|
key :name, String
|
22
144
|
key :age, Integer
|
23
145
|
end
|
24
146
|
end
|
25
|
-
|
26
|
-
context "
|
147
|
+
|
148
|
+
context "being initialized" do
|
27
149
|
should "accept a hash that sets keys and values" do
|
28
150
|
doc = @document.new(:name => 'John', :age => 23)
|
29
151
|
doc.attributes.should == {'name' => 'John', 'age' => 23}
|
30
152
|
end
|
31
|
-
|
153
|
+
|
32
154
|
should "not throw error if initialized with nil" do
|
33
155
|
doc = @document.new(nil)
|
34
156
|
end
|
35
157
|
end
|
36
|
-
|
158
|
+
|
37
159
|
context "mass assigning keys" do
|
38
160
|
should "update values for keys provided" do
|
39
161
|
doc = @document.new(:name => 'foobar', :age => 10)
|
@@ -49,22 +171,22 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
49
171
|
doc.attributes[:age].should == 10
|
50
172
|
end
|
51
173
|
|
52
|
-
should "
|
174
|
+
should "raise undefined method if no key exists" do
|
53
175
|
doc = @document.new(:name => 'foobar', :age => 10)
|
54
|
-
|
55
|
-
|
56
|
-
|
176
|
+
lambda {
|
177
|
+
doc.attributes = {:name => 'new value', :foobar => 'baz'}
|
178
|
+
}.should raise_error(NoMethodError)
|
57
179
|
end
|
58
|
-
|
180
|
+
|
59
181
|
should "not ignore keys that have methods defined" do
|
60
182
|
@document.class_eval do
|
61
183
|
attr_writer :password
|
62
|
-
|
184
|
+
|
63
185
|
def passwd
|
64
186
|
@password
|
65
187
|
end
|
66
188
|
end
|
67
|
-
|
189
|
+
|
68
190
|
doc = @document.new(:name => 'foobar', :password => 'secret')
|
69
191
|
doc.passwd.should == 'secret'
|
70
192
|
end
|
@@ -76,7 +198,7 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
76
198
|
end
|
77
199
|
end
|
78
200
|
|
79
|
-
context "
|
201
|
+
context "attributes" do
|
80
202
|
should "default to empty hash" do
|
81
203
|
doc = @document.new
|
82
204
|
doc.attributes.should == {}
|
@@ -87,20 +209,20 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
87
209
|
doc.attributes.should == {'name' => 'string'}
|
88
210
|
end
|
89
211
|
end
|
90
|
-
|
91
|
-
context "key
|
212
|
+
|
213
|
+
context "key shorcut access" do
|
92
214
|
should "be able to read key with []" do
|
93
215
|
doc = @document.new(:name => 'string')
|
94
216
|
doc[:name].should == 'string'
|
95
217
|
end
|
96
|
-
|
218
|
+
|
97
219
|
should "be able to write key value with []=" do
|
98
220
|
doc = @document.new
|
99
221
|
doc[:name] = 'string'
|
100
222
|
doc[:name].should == 'string'
|
101
223
|
end
|
102
224
|
end
|
103
|
-
|
225
|
+
|
104
226
|
context "indifferent access" do
|
105
227
|
should "be enabled for keys" do
|
106
228
|
doc = @document.new(:name => 'string')
|
@@ -119,47 +241,37 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
119
241
|
doc = @document.new
|
120
242
|
lambda { doc.fart }.should raise_error(NoMethodError)
|
121
243
|
end
|
122
|
-
|
123
|
-
should "know if reader defined" do
|
124
|
-
doc = @document.new
|
125
|
-
doc.reader?('name').should be(true)
|
126
|
-
doc.reader?(:name).should be(true)
|
127
|
-
doc.reader?('age').should be(true)
|
128
|
-
doc.reader?(:age).should be(true)
|
129
|
-
doc.reader?('foobar').should be(false)
|
130
|
-
doc.reader?(:foobar).should be(false)
|
131
|
-
end
|
132
|
-
|
244
|
+
|
133
245
|
should "be accessible for use in the model" do
|
134
246
|
@document.class_eval do
|
135
247
|
def name_and_age
|
136
248
|
"#{read_attribute(:name)} (#{read_attribute(:age)})"
|
137
249
|
end
|
138
250
|
end
|
139
|
-
|
251
|
+
|
140
252
|
doc = @document.new(:name => 'John', :age => 27)
|
141
253
|
doc.name_and_age.should == 'John (27)'
|
142
254
|
end
|
143
255
|
end
|
144
|
-
|
256
|
+
|
145
257
|
context "reading an attribute before typcasting" do
|
146
258
|
should "work for defined keys" do
|
147
259
|
doc = @document.new(:name => 12)
|
148
260
|
doc.name_before_typecast.should == 12
|
149
261
|
end
|
150
|
-
|
262
|
+
|
151
263
|
should "raise no method error for undefined keys" do
|
152
264
|
doc = @document.new
|
153
265
|
lambda { doc.foo_before_typecast }.should raise_error(NoMethodError)
|
154
266
|
end
|
155
|
-
|
267
|
+
|
156
268
|
should "be accessible for use in a document" do
|
157
269
|
@document.class_eval do
|
158
270
|
def untypcasted_name
|
159
271
|
read_attribute_before_typecast(:name)
|
160
272
|
end
|
161
273
|
end
|
162
|
-
|
274
|
+
|
163
275
|
doc = @document.new(:name => 12)
|
164
276
|
doc.name.should == '12'
|
165
277
|
doc.untypcasted_name.should == 12
|
@@ -186,28 +298,15 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
186
298
|
doc.age.should == 21
|
187
299
|
end
|
188
300
|
|
189
|
-
should "know if writer defined" do
|
190
|
-
doc = @document.new
|
191
|
-
doc.writer?('name').should be(true)
|
192
|
-
doc.writer?('name=').should be(true)
|
193
|
-
doc.writer?(:name).should be(true)
|
194
|
-
doc.writer?('age').should be(true)
|
195
|
-
doc.writer?('age=').should be(true)
|
196
|
-
doc.writer?(:age).should be(true)
|
197
|
-
doc.writer?('foobar').should be(false)
|
198
|
-
doc.writer?('foobar=').should be(false)
|
199
|
-
doc.writer?(:foobar).should be(false)
|
200
|
-
end
|
201
|
-
|
202
301
|
should "be accessible for use in the model" do
|
203
|
-
@document.class_eval do
|
302
|
+
@document.class_eval do
|
204
303
|
def name_and_age=(new_value)
|
205
304
|
new_value.match(/([^\(\s]+) \((.*)\)/)
|
206
305
|
write_attribute :name, $1
|
207
306
|
write_attribute :age, $2
|
208
307
|
end
|
209
308
|
end
|
210
|
-
|
309
|
+
|
211
310
|
doc = @document.new
|
212
311
|
doc.name_and_age = 'Frank (62)'
|
213
312
|
doc.name.should == 'Frank'
|
@@ -215,24 +314,17 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
215
314
|
end
|
216
315
|
end # writing an attribute
|
217
316
|
|
218
|
-
context "
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
@doc.respond_to?(:name).should be_true
|
225
|
-
@doc.respond_to?('name').should be_true
|
226
|
-
end
|
227
|
-
|
228
|
-
should "work for writers" do
|
229
|
-
@doc.respond_to?(:name=).should be_true
|
230
|
-
@doc.respond_to?('name=').should be_true
|
317
|
+
context "checking if an attributes value is present" do
|
318
|
+
should "work for defined keys" do
|
319
|
+
doc = @document.new
|
320
|
+
doc.name?.should be_false
|
321
|
+
doc.name = 'John'
|
322
|
+
doc.name?.should be_true
|
231
323
|
end
|
232
324
|
|
233
|
-
should "
|
234
|
-
@
|
235
|
-
|
325
|
+
should "raise no method error for undefined keys" do
|
326
|
+
doc = @document.new
|
327
|
+
lambda { doc.fart? }.should raise_error(NoMethodError)
|
236
328
|
end
|
237
329
|
end
|
238
330
|
|
@@ -242,7 +334,7 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
242
334
|
doc2 = @document.new(:name => 'John', :age => 27)
|
243
335
|
doc1.should == doc2
|
244
336
|
end
|
245
|
-
|
337
|
+
|
246
338
|
should "be false if not all the keys and values are equal" do
|
247
339
|
doc1 = @document.new(:name => 'Steve', :age => 27)
|
248
340
|
doc2 = @document.new(:name => 'John', :age => 27)
|