jnunemaker-mongomapper 0.2.0 → 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/.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)
|