mongo_mapper 0.5.8 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/Rakefile +4 -4
  2. data/VERSION +1 -1
  3. data/bin/mmconsole +10 -5
  4. data/lib/mongo_mapper.rb +28 -5
  5. data/lib/mongo_mapper/associations.rb +113 -12
  6. data/lib/mongo_mapper/associations/base.rb +24 -9
  7. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +1 -1
  8. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +1 -1
  9. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +2 -2
  10. data/lib/mongo_mapper/associations/many_documents_proxy.rb +7 -2
  11. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +22 -36
  12. data/lib/mongo_mapper/associations/proxy.rb +11 -6
  13. data/lib/mongo_mapper/document.rb +37 -21
  14. data/lib/mongo_mapper/embedded_document.rb +32 -18
  15. data/lib/mongo_mapper/finder_options.rb +19 -12
  16. data/lib/mongo_mapper/rails_compatibility/document.rb +4 -0
  17. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +4 -0
  18. data/lib/mongo_mapper/support.rb +18 -46
  19. data/lib/mongo_mapper/types.rb +64 -0
  20. data/lib/mongo_mapper/validations.rb +13 -43
  21. data/mongo_mapper.gemspec +13 -10
  22. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +10 -10
  23. data/test/functional/associations/test_belongs_to_proxy.rb +29 -30
  24. data/test/functional/associations/test_many_documents_as_proxy.rb +13 -12
  25. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +34 -34
  26. data/test/functional/associations/test_many_embedded_proxy.rb +69 -74
  27. data/test/functional/associations/test_many_polymorphic_proxy.rb +10 -10
  28. data/test/functional/associations/test_many_proxy.rb +14 -15
  29. data/test/functional/test_associations.rb +4 -4
  30. data/test/functional/test_binary.rb +1 -1
  31. data/test/functional/test_dirty.rb +6 -6
  32. data/test/functional/test_document.rb +76 -69
  33. data/test/functional/test_embedded_document.rb +15 -14
  34. data/test/functional/test_pagination.rb +9 -1
  35. data/test/functional/test_string_id_compatibility.rb +72 -0
  36. data/test/functional/test_validations.rb +56 -7
  37. data/test/models.rb +7 -7
  38. data/test/test_helper.rb +2 -5
  39. data/test/unit/test_association_base.rb +6 -1
  40. data/test/unit/test_document.rb +22 -13
  41. data/test/unit/test_embedded_document.rb +47 -5
  42. data/test/unit/test_finder_options.rb +22 -3
  43. data/test/unit/test_mongo_mapper.rb +65 -0
  44. data/test/unit/test_rails_compatibility.rb +14 -0
  45. data/test/unit/test_support.rb +45 -0
  46. metadata +9 -6
  47. data/test/unit/test_mongomapper.rb +0 -28
@@ -28,9 +28,9 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
28
28
  @doc.foo.city.should == 'South Bend'
29
29
  @doc.foo.state.should == 'IN'
30
30
 
31
- from_db = @document.find(@doc.id)
32
- from_db.foo.city.should == 'South Bend'
33
- from_db.foo.state.should == 'IN'
31
+ doc = @doc.reload
32
+ doc.foo.city.should == 'South Bend'
33
+ doc.foo.state.should == 'IN'
34
34
  end
35
35
  end
36
36
 
@@ -58,8 +58,9 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
58
58
  address = Address.new(:city => 'South Bend', :state => 'IN')
59
59
  doc = @document.new(:foo => address)
60
60
  doc.save
61
- read_doc = @document.find(doc.id)
62
- read_doc.foo.new?.should == false
61
+
62
+ doc = doc.reload
63
+ doc.foo.new?.should == false
63
64
  end
64
65
  end
65
66
 
@@ -71,15 +72,16 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
71
72
  person.pets << pet
72
73
  pet.save
73
74
 
74
- doc = RealPerson.find(person.id)
75
- doc.pets.first.should == pet
75
+ person = person.reload
76
+ person.pets.first.should == pet
76
77
  end
77
78
 
78
79
  should "save new keys" do
79
80
  person = RealPerson.new
80
81
  person[:new_attribute] = 'foobar'
81
82
  person.save
82
- from_db = RealPerson.find(person.id)
83
+
84
+ person = person.reload
83
85
  person.new_attribute.should == 'foobar'
84
86
  end
85
87
  end
@@ -92,14 +94,13 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
92
94
  person.pets << pet
93
95
  pet.save
94
96
 
95
- doc = RealPerson.find(person.id)
96
- pet = doc.pets.first
97
+ person = person.reload
98
+ pet = person.pets.first
97
99
  pet.update_attributes :name => 'koda'
98
100
 
99
- doc = RealPerson.find(person.id)
100
- embedded = doc.pets.first
101
- embedded.id.should == pet.id
102
- embedded.name.should == 'koda'
101
+ person = person.reload
102
+ person.pets.first._id.should == pet._id
103
+ person.pets.first.name.should == 'koda'
103
104
  end
104
105
  end
105
106
  end
@@ -50,8 +50,16 @@ class PaginationTest < Test::Unit::TestCase
50
50
  })
51
51
  result.should == [@doc1, @doc3]
52
52
  result.first.age.should == 27
53
+
54
+ result = @document.paginate({
55
+ :conditions => {:last_name => 'Nunemaker'},
56
+ :order => "age DESC",
57
+ :per_page => 2,
58
+ :page => 1} )
59
+ result.should == [@doc1, @doc3]
60
+ result.first.age.should == 27
53
61
  end
54
-
62
+
55
63
  should "withstand rigor" do
56
64
  result = @document.paginate({
57
65
  :per_page => 1,
@@ -0,0 +1,72 @@
1
+ require 'test_helper'
2
+
3
+ class StringIdCompatibilityTest < Test::Unit::TestCase
4
+ def setup
5
+ @note_class = Class.new do
6
+ include MongoMapper::EmbeddedDocument
7
+ key :_id, String
8
+ end
9
+
10
+ @task_class = Class.new do
11
+ include MongoMapper::Document
12
+ key :_id, String
13
+ key :project_id, String
14
+ belongs_to :project
15
+ end
16
+
17
+ @project_class = Class.new do
18
+ include MongoMapper::Document
19
+ key :_id, String
20
+ end
21
+
22
+ @task_class.belongs_to :project, :class => @project_class
23
+ @project_class.many :notes, :class => @note_class
24
+ @project_class.many :tasks, :class => @task_class, :foreign_key => 'project_id'
25
+
26
+ @project_class.collection.remove
27
+ @task_class.collection.remove
28
+ end
29
+
30
+ should "assign correct _id for documents" do
31
+ project = @project_class.create
32
+ project._id.should == project.id
33
+ project._id.should be_instance_of(String)
34
+ project.id.size.should == 24
35
+ lambda {
36
+ Mongo::ObjectID.from_string(project.id)
37
+ }.should_not raise_error
38
+ end
39
+
40
+ should "assign correct _id for embedded documents" do
41
+ note = @note_class.new
42
+ note.id.should == note._id
43
+ note.id.size.should == 24
44
+ end
45
+
46
+ should "find records" do
47
+ project = @project_class.create
48
+ @project_class.find(project.id).should == project
49
+ end
50
+
51
+ should "save embedded docs" do
52
+ n1 = @note_class.new
53
+ n2 = @note_class.new
54
+ n3 = @note_class.new
55
+ project = @project_class.create(:notes => [n1, n2, n3])
56
+
57
+ project = project.reload
58
+ project.notes.size.should == 3
59
+ project.notes.should == [n1, n2, n3]
60
+ end
61
+
62
+ should "be able to associate records" do
63
+ t1 = @task_class.new(:body => 'First task')
64
+ t2 = @task_class.new(:body => 'Second task')
65
+ t3 = @task_class.new(:body => 'Third task')
66
+ project = @project_class.create(:name => 'MM', :tasks => [t1, t2, t3])
67
+
68
+ project = project.reload
69
+ project.tasks.count.should == 3
70
+ project.tasks.should == [t1, t2, t3]
71
+ end
72
+ end
@@ -24,7 +24,24 @@ class ValidationsTest < Test::Unit::TestCase
24
24
  doc.errors.full_messages.should == ["Name can't be empty"]
25
25
  end
26
26
  end
27
-
27
+
28
+ context "Skipping validations when saving" do
29
+ setup do
30
+ @document = Class.new do
31
+ include MongoMapper::Document
32
+ set_collection_name 'test'
33
+ key :name, String, :required => true
34
+ end
35
+ @document.collection.remove
36
+ end
37
+
38
+ should "insert document" do
39
+ doc = @document.new
40
+ doc.save(false)
41
+ @document.count.should == 1
42
+ end
43
+ end
44
+
28
45
  context "Saving a document that is invalid (destructive)" do
29
46
  setup do
30
47
  @document = Class.new do
@@ -76,7 +93,7 @@ class ValidationsTest < Test::Unit::TestCase
76
93
  should "not update document" do
77
94
  @doc.name = nil
78
95
  @doc.save
79
- @document.find(@doc.id).name.should == 'John Nunemaker'
96
+ @doc.reload.name.should == 'John Nunemaker'
80
97
  end
81
98
 
82
99
  should "populate document's errors" do
@@ -212,7 +229,39 @@ class ValidationsTest < Test::Unit::TestCase
212
229
  doc2 = document.new("name" => "")
213
230
  doc2.should_not have_error_on(:name)
214
231
  end
215
-
232
+
233
+ should "allow entries that differ only in case by default" do
234
+ document = Class.new do
235
+ include MongoMapper::Document
236
+ set_collection_name 'test'
237
+
238
+ key :name
239
+ validates_uniqueness_of :name
240
+ end
241
+
242
+ doc = document.new("name" => "BLAMMO")
243
+ doc.save.should be_true
244
+
245
+ doc2 = document.new("name" => "blammo")
246
+ doc2.should_not have_error_on(:name)
247
+ end
248
+
249
+ should "fail on entries that differ only in case if :case_sensitive => false" do
250
+ document = Class.new do
251
+ include MongoMapper::Document
252
+ set_collection_name 'test'
253
+
254
+ key :name
255
+ validates_uniqueness_of :name, :case_sensitive => false
256
+ end
257
+
258
+ doc = document.new("name" => "BLAMMO")
259
+ doc.save.should be_true
260
+
261
+ doc2 = document.new("name" => "blammo")
262
+ doc2.should have_error_on(:name)
263
+ end
264
+
216
265
  context "scoped by a single attribute" do
217
266
  setup do
218
267
  @document = Class.new do
@@ -225,7 +274,7 @@ class ValidationsTest < Test::Unit::TestCase
225
274
  end
226
275
  @document.collection.remove
227
276
  end
228
-
277
+
229
278
  should "fail if the same name exists in the scope" do
230
279
  doc = @document.new("name" => "joe", "scope" => "one")
231
280
  doc.save.should be_true
@@ -238,11 +287,11 @@ class ValidationsTest < Test::Unit::TestCase
238
287
  doc2 = @document.new("name" => "joe", "scope" => "one")
239
288
  doc2.should have_error_on(:name)
240
289
  end
241
-
290
+
242
291
  should "pass if the same name exists in a different scope" do
243
292
  doc = @document.new("name" => "joe", "scope" => "one")
244
293
  doc.save.should be_true
245
-
294
+
246
295
  @document \
247
296
  .stubs(:first) \
248
297
  .with(:name => 'joe', :scope => 'two') \
@@ -252,7 +301,7 @@ class ValidationsTest < Test::Unit::TestCase
252
301
  doc2.should_not have_error_on(:name)
253
302
  end
254
303
  end
255
-
304
+
256
305
  context "scoped by a multiple attributes" do
257
306
  setup do
258
307
  @document = Class.new do
@@ -40,7 +40,7 @@ class PostComment
40
40
  key :username, String, :default => 'Anonymous'
41
41
  key :body, String
42
42
 
43
- key :commentable_id, String
43
+ key :commentable_id, ObjectId
44
44
  key :commentable_type, String
45
45
  belongs_to :commentable, :polymorphic => true
46
46
 
@@ -62,7 +62,7 @@ class Message
62
62
  key :body, String
63
63
  key :position, Integer
64
64
  key :_type, String
65
- key :room_id, String
65
+ key :room_id, ObjectId
66
66
 
67
67
  belongs_to :room
68
68
  end
@@ -81,7 +81,7 @@ class Account
81
81
  include MongoMapper::Document
82
82
 
83
83
  key :_type, String
84
- key :room_id, String
84
+ key :room_id, ObjectId
85
85
  key :last_logged_in, Time
86
86
 
87
87
  belongs_to :room
@@ -145,7 +145,7 @@ end
145
145
 
146
146
  class Collaborator
147
147
  include MongoMapper::Document
148
- key :project_id, String
148
+ key :project_id, ObjectId
149
149
  key :name, String
150
150
  belongs_to :project
151
151
  end
@@ -153,8 +153,8 @@ end
153
153
  class Status
154
154
  include MongoMapper::Document
155
155
 
156
- key :project_id, String
157
- key :target_id, String
156
+ key :project_id, ObjectId
157
+ key :target_id, ObjectId
158
158
  key :target_type, String
159
159
  key :name, String, :required => true
160
160
  key :position, Integer
@@ -166,7 +166,7 @@ end
166
166
  class RealPerson
167
167
  include MongoMapper::Document
168
168
 
169
- key :room_id, String
169
+ key :room_id, ObjectId
170
170
  key :name, String
171
171
 
172
172
  belongs_to :room
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../lib/mongo_mapper')
3
3
  gem 'jnunemaker-matchy', '0.4.0'
4
4
  gem 'shoulda', '2.10.2'
5
5
  gem 'timecop', '0.3.1'
6
- gem 'mocha', '0.9.4'
6
+ gem 'mocha', '0.9.8'
7
7
 
8
8
  require 'matchy'
9
9
  require 'shoulda'
@@ -18,13 +18,10 @@ class Test::Unit::TestCase
18
18
  include CustomMatchers
19
19
  end
20
20
 
21
- DefaultDatabase = 'test' unless defined?(DefaultDatabase)
22
- AlternateDatabase = 'test2' unless defined?(AlternateDatabase)
23
-
24
21
  test_dir = File.expand_path(File.dirname(__FILE__) + '/../tmp')
25
22
  FileUtils.mkdir_p(test_dir) unless File.exist?(test_dir)
26
23
 
27
24
  MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {
28
25
  :logger => Logger.new(test_dir + '/test.log')
29
26
  })
30
- MongoMapper.database = DefaultDatabase
27
+ MongoMapper.database = 'test'
@@ -33,9 +33,14 @@ class AssociationBaseTest < Test::Unit::TestCase
33
33
  end
34
34
 
35
35
  context "klass" do
36
- should "be class_name constantized" do
36
+ should "default to class_name constantized" do
37
37
  Base.new(:belongs_to, :foo_monster).klass.should == FooMonster
38
38
  end
39
+
40
+ should "be the specified class" do
41
+ anonnymous_class = Class.new
42
+ Base.new(:belongs_to, :foo_monster, :class => anonnymous_class).klass.should == anonnymous_class
43
+ end
39
44
  end
40
45
 
41
46
  context "many?" do
@@ -36,8 +36,9 @@ class DocumentTest < Test::Unit::TestCase
36
36
  end
37
37
 
38
38
  should "allow setting a different database without affecting the default" do
39
- @document.database AlternateDatabase
40
- @document.database.name.should == AlternateDatabase
39
+ @document.set_database_name 'test2'
40
+ @document.database_name.should == 'test2'
41
+ @document.database.name.should == 'test2'
41
42
 
42
43
  another_document = Class.new do
43
44
  include MongoMapper::Document
@@ -113,7 +114,7 @@ class DocumentTest < Test::Unit::TestCase
113
114
 
114
115
  should "have access to the class's collection" do
115
116
  doc = @document.new
116
- doc.collection.should == @document.collection
117
+ doc.collection.name.should == @document.collection.name
117
118
  end
118
119
 
119
120
  should "use default values if defined for keys" do
@@ -135,13 +136,18 @@ class DocumentTest < Test::Unit::TestCase
135
136
  @document.new._root_document.should be_nil
136
137
  end
137
138
 
138
- should "set self to the root document on embedded documents" do
139
- document = Class.new(RealPerson) do
140
- many :pets
139
+ should "set self to the root document on embedded documents" do
140
+ klass = Class.new do
141
+ include MongoMapper::Document
141
142
  end
142
-
143
- doc = document.new 'pets' => [{}]
144
- doc.pets.first._root_document.should == doc
143
+
144
+ pets = Class.new do
145
+ include MongoMapper::EmbeddedDocument
146
+ end
147
+ klass.many :pets, :class => pets
148
+
149
+ doc = klass.new(:pets => [{}])
150
+ doc.pets.first._root_document.should == doc
145
151
  end
146
152
  end
147
153
 
@@ -151,6 +157,7 @@ class DocumentTest < Test::Unit::TestCase
151
157
  end
152
158
 
153
159
  should "be true if id but using custom id and not saved yet" do
160
+ @document.key :_id, String
154
161
  doc = @document.new
155
162
  doc.id = '1234'
156
163
  doc.new?.should be_true
@@ -172,14 +179,16 @@ class DocumentTest < Test::Unit::TestCase
172
179
  end
173
180
  end
174
181
 
175
-
176
182
  context "equality" do
183
+ setup do
184
+ @oid = Mongo::ObjectID.new
185
+ end
177
186
  should "be equal if id and class are the same" do
178
- (@document.new('_id' => 1) == @document.new('_id' => 1)).should be(true)
187
+ (@document.new('_id' => @oid) == @document.new('_id' => @oid)).should be(true)
179
188
  end
180
189
 
181
190
  should "not be equal if class same but id different" do
182
- (@document.new('_id' => 1) == @document.new('_id' => 2)).should be(false)
191
+ (@document.new('_id' => @oid) == @document.new('_id' => Mongo::ObjectID.new)).should be(false)
183
192
  end
184
193
 
185
194
  should "not be equal if id same but class different" do
@@ -188,7 +197,7 @@ class DocumentTest < Test::Unit::TestCase
188
197
  set_collection_name 'test'
189
198
  end
190
199
 
191
- (@document.new('_id' => 1) == @another_document.new('_id' => 1)).should be(false)
200
+ (@document.new('_id' => @oid) == @another_document.new('_id' => @oid)).should be(false)
192
201
  end
193
202
  end
194
203
  end # instance of a document
@@ -49,6 +49,15 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
49
49
  @klass.keys['_id'].should_not be_nil
50
50
  end
51
51
 
52
+ should "know it is using object id" do
53
+ @klass.using_object_id?.should be_true
54
+ end
55
+
56
+ should "know it is not using object id if _id type is changed" do
57
+ @klass.key :_id, String
58
+ @klass.using_object_id?.should be_false
59
+ end
60
+
52
61
  context "#to_mongo" do
53
62
  should "be nil if nil" do
54
63
  @klass.to_mongo(nil).should be_nil
@@ -80,6 +89,15 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
80
89
  end
81
90
  end
82
91
 
92
+ context "looking up type constants" do
93
+ should "not raise an error" do
94
+ klass = Class.new do
95
+ include MongoMapper::EmbeddedDocument
96
+ key :file, Binary
97
+ end
98
+ end
99
+ end
100
+
83
101
  context "parent_model" do
84
102
  should "be nil if none of parents ancestors include EmbeddedDocument" do
85
103
  parent = Class.new
@@ -150,11 +168,11 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
150
168
  @document.keys['age'].type.should == Integer
151
169
  end
152
170
 
153
- should "not be redefinable" do
171
+ should "be redefinable" do
154
172
  @document.key(:foo, String)
155
173
  @document.keys['foo'].type.should == String
156
174
  @document.key(:foo, Integer)
157
- @document.keys['foo'].type.should == String
175
+ @document.keys['foo'].type.should == Integer
158
176
  end
159
177
 
160
178
  should "create reader method" do
@@ -292,6 +310,7 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
292
310
  should "have to_param that is id" do
293
311
  doc = @document.new
294
312
  doc.to_param.should == doc.id
313
+ doc.to_param.should be_instance_of(String)
295
314
  end
296
315
 
297
316
  should "have access to class logger" do
@@ -308,6 +327,24 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
308
327
  doc = @document.new
309
328
  doc.id.should == doc._id.to_s
310
329
  end
330
+
331
+ context "assigning id with _id ObjectId type" do
332
+ should "not set custom id flag" do
333
+ doc = @document.new
334
+ doc.using_custom_id?.should be_false
335
+ doc.id = Mongo::ObjectID.new
336
+ doc.using_custom_id?.should be_false
337
+ end
338
+
339
+ should "convert string object id to mongo object id" do
340
+ id = Mongo::ObjectID.new
341
+ doc = @document.new
342
+ doc.id = id.to_s
343
+ doc._id.should == id
344
+ doc.id.should == id.to_s
345
+ doc.using_custom_id?.should be_false
346
+ end
347
+ end
311
348
 
312
349
  should "have a nil _root_document" do
313
350
  @document.new._root_document.should be_nil
@@ -315,11 +352,13 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
315
352
 
316
353
  context "setting custom id" do
317
354
  should "set _id" do
355
+ @document.key :_id, String
318
356
  doc = @document.new(:id => '1234')
319
357
  doc._id.should == '1234'
320
358
  end
321
359
 
322
360
  should "know that custom id is set" do
361
+ @document.key :_id, String
323
362
  doc = @document.new
324
363
  doc.using_custom_id?.should be_false
325
364
  doc.id = '1234'
@@ -656,12 +695,15 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
656
695
  end
657
696
 
658
697
  context "equality" do
698
+ setup do
699
+ @oid = Mongo::ObjectID.new
700
+ end
659
701
  should "be equal if id and class are the same" do
660
- (@document.new('_id' => 1) == @document.new('_id' => 1)).should be(true)
702
+ (@document.new('_id' => @oid) == @document.new('_id' => @oid)).should be(true)
661
703
  end
662
704
 
663
705
  should "not be equal if class same but id different" do
664
- (@document.new('_id' => 1) == @document.new('_id' => 2)).should be(false)
706
+ (@document.new('_id' => @oid) == @document.new('_id' => Mongo::ObjectID.new)).should be(false)
665
707
  end
666
708
 
667
709
  should "not be equal if id same but class different" do
@@ -669,7 +711,7 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
669
711
  include MongoMapper::Document
670
712
  end
671
713
 
672
- (@document.new('_id' => 1) == @another_document.new('_id' => 1)).should be(false)
714
+ (@document.new('_id' => @oid) == @another_document.new('_id' => @oid)).should be(false)
673
715
  end
674
716
  end
675
717
  end # instance of a embedded document