djsun-mongo_mapper 0.5.6.6 → 0.5.8.1

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.
Files changed (53) hide show
  1. data/.gitignore +3 -1
  2. data/Rakefile +13 -8
  3. data/VERSION +1 -1
  4. data/djsun-mongo_mapper.gemspec +17 -21
  5. data/lib/mongo_mapper/associations/base.rb +32 -36
  6. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -2
  7. data/lib/mongo_mapper/associations/many_documents_proxy.rb +19 -10
  8. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +2 -2
  9. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +21 -36
  10. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +1 -1
  11. data/lib/mongo_mapper/associations/proxy.rb +3 -2
  12. data/lib/mongo_mapper/associations.rb +114 -8
  13. data/lib/mongo_mapper/callbacks.rb +18 -0
  14. data/lib/mongo_mapper/document.rb +173 -37
  15. data/lib/mongo_mapper/dynamic_finder.rb +1 -1
  16. data/lib/mongo_mapper/embedded_document.rb +9 -13
  17. data/lib/mongo_mapper/finder_options.rb +67 -44
  18. data/lib/mongo_mapper/pagination.rb +2 -0
  19. data/lib/mongo_mapper/serialization.rb +1 -1
  20. data/lib/mongo_mapper/serializers/json_serializer.rb +1 -1
  21. data/lib/mongo_mapper/support.rb +9 -0
  22. data/lib/mongo_mapper/validations.rb +12 -42
  23. data/lib/mongo_mapper.rb +11 -5
  24. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +5 -5
  25. data/test/functional/associations/test_belongs_to_proxy.rb +29 -31
  26. data/test/functional/associations/test_many_documents_as_proxy.rb +5 -5
  27. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +27 -3
  28. data/test/functional/associations/test_many_embedded_proxy.rb +58 -38
  29. data/test/functional/associations/test_many_polymorphic_proxy.rb +45 -3
  30. data/test/functional/associations/test_many_proxy.rb +61 -11
  31. data/test/functional/test_associations.rb +3 -3
  32. data/test/functional/test_binary.rb +1 -1
  33. data/test/functional/test_callbacks.rb +1 -1
  34. data/test/functional/test_dirty.rb +3 -3
  35. data/test/functional/test_document.rb +62 -58
  36. data/test/functional/test_embedded_document.rb +1 -1
  37. data/test/functional/test_pagination.rb +1 -1
  38. data/test/functional/test_rails_compatibility.rb +1 -1
  39. data/test/functional/test_validations.rb +46 -14
  40. data/test/models.rb +87 -35
  41. data/test/support/{test_timing.rb → timing.rb} +1 -1
  42. data/test/test_helper.rb +8 -13
  43. data/test/unit/serializers/test_json_serializer.rb +0 -4
  44. data/test/unit/test_association_base.rb +24 -8
  45. data/test/unit/test_document.rb +40 -71
  46. data/test/unit/test_embedded_document.rb +27 -67
  47. data/test/unit/test_finder_options.rb +16 -0
  48. data/test/unit/test_key.rb +5 -17
  49. data/test/unit/test_mongomapper.rb +2 -2
  50. data/test/unit/test_pagination.rb +4 -0
  51. metadata +10 -12
  52. data/mongo_mapper.gemspec +0 -170
  53. data/test/functional/associations/test_namespace.rb +0 -27
@@ -4,67 +4,37 @@ module MongoMapper
4
4
  def validates_uniqueness_of(*args)
5
5
  add_validations(args, MongoMapper::Validations::ValidatesUniquenessOf)
6
6
  end
7
-
8
- def validates_exclusion_of(*args)
9
- add_validations(args, MongoMapper::Validations::ValidatesExclusionOf)
10
- end
11
-
12
- def validates_inclusion_of(*args)
13
- add_validations(args, MongoMapper::Validations::ValidatesInclusionOf)
14
- end
15
7
  end
16
8
 
17
9
  class ValidatesUniquenessOf < Validatable::ValidationBase
18
- option :scope
19
-
10
+ option :scope, :case_sensitive
11
+ default :case_sensitive => true
12
+
20
13
  def valid?(instance)
21
14
  value = instance[attribute]
22
15
  return true if allow_blank && value.blank?
23
- doc = instance.class.first({self.attribute => value}.merge(scope_conditions(instance)))
16
+ base_conditions = case_sensitive ? {self.attribute => value} : {}
17
+ doc = instance.class.first(base_conditions.merge(scope_conditions(instance)).merge(where_conditions(instance)))
24
18
  doc.nil? || instance.id == doc.id
25
19
  end
26
20
 
27
21
  def message(instance)
28
22
  super || "has already been taken"
29
23
  end
30
-
24
+
31
25
  def scope_conditions(instance)
32
26
  return {} unless scope
33
27
  Array(scope).inject({}) do |conditions, key|
34
28
  conditions.merge(key => instance[key])
35
29
  end
36
30
  end
37
- end
38
-
39
- class ValidatesExclusionOf < Validatable::ValidationBase
40
- required_option :within
41
-
42
- def valid?(instance)
43
- value = instance[attribute]
44
- return true if allow_nil && value.nil?
45
- return true if allow_blank && value.blank?
46
-
47
- !within.include?(instance[attribute])
48
- end
49
-
50
- def message(instance)
51
- super || "is reserved"
52
- end
53
- end
54
31
 
55
- class ValidatesInclusionOf < Validatable::ValidationBase
56
- required_option :within
57
-
58
- def valid?(instance)
59
- value = instance[attribute]
60
- return true if allow_nil && value.nil?
61
- return true if allow_blank && value.blank?
62
-
63
- within.include?(value)
64
- end
65
-
66
- def message(instance)
67
- super || "is not in the list"
32
+ def where_conditions(instance)
33
+ conditions = {}
34
+ unless case_sensitive
35
+ conditions.merge!({'$where' => "this.#{attribute}.toLowerCase() == '#{instance[attribute].downcase}'"})
36
+ end
37
+ conditions
68
38
  end
69
39
  end
70
40
  end
data/lib/mongo_mapper.rb CHANGED
@@ -1,13 +1,19 @@
1
- require 'rubygems'
2
- gem 'activesupport', '>= 2.3'
3
1
  require 'active_support'
4
2
  require 'mongo'
5
3
  require 'validatable'
6
4
 
7
5
  module MongoMapper
8
- class KeyNotFound < RuntimeError; end
9
- DocumentNotFound = Class.new(StandardError)
10
- DocumentNotValid = Class.new(StandardError) do
6
+ # generic MM error
7
+ class MongoMapperError < StandardError; end
8
+
9
+ # raised when key expected to exist but not found
10
+ class KeyNotFound < MongoMapperError; end
11
+
12
+ # raised when document expected but not found
13
+ class DocumentNotFound < MongoMapperError; end
14
+
15
+ # raised when document not valid and using !
16
+ class DocumentNotValid < MongoMapperError
11
17
  def initialize(document)
12
18
  @document = document
13
19
  super("Validation failed: #{@document.errors.full_messages.join(", ")}")
@@ -3,8 +3,8 @@ require 'models'
3
3
 
4
4
  class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
5
5
  def setup
6
- Status.collection.clear
7
- Project.collection.clear
6
+ Status.collection.remove
7
+ Project.collection.remove
8
8
  end
9
9
 
10
10
  should "default to nil" do
@@ -14,7 +14,7 @@ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
14
14
  end
15
15
 
16
16
  should "be able to replace the association" do
17
- status = Status.new
17
+ status = Status.new(:name => 'Foo!')
18
18
  project = Project.new(:name => "mongomapper")
19
19
  status.target = project
20
20
  status.save.should be_true
@@ -27,7 +27,7 @@ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
27
27
  end
28
28
 
29
29
  should "unset the association" do
30
- status = Status.new
30
+ status = Status.new(:name => 'Foo!')
31
31
  project = Project.new(:name => "mongomapper")
32
32
  status.target = project
33
33
  status.save.should be_true
@@ -41,7 +41,7 @@ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
41
41
 
42
42
  context "association id set but document not found" do
43
43
  setup do
44
- @status = Status.new
44
+ @status = Status.new(:name => 'Foo!')
45
45
  project = Project.new(:name => "mongomapper")
46
46
  @status.target = project
47
47
  @status.save.should be_true
@@ -2,48 +2,46 @@ require 'test_helper'
2
2
  require 'models'
3
3
 
4
4
  class BelongsToProxyTest < Test::Unit::TestCase
5
- def setup
6
- Status.collection.clear
7
- Project.collection.clear
5
+ def setup
6
+ @post_class = Class.new do
7
+ include MongoMapper::Document
8
+ end
9
+
10
+ @comment_class = Class.new do
11
+ include MongoMapper::Document
12
+ key :post_id, String
13
+ end
14
+ @comment_class.belongs_to :post, :class => @post_class
15
+
16
+ @post_class.collection.remove
17
+ @comment_class.collection.remove
8
18
  end
9
19
 
10
20
  should "default to nil" do
11
- status = Status.new
12
- status.project.nil?.should == true
13
- status.project.inspect.should == 'nil'
21
+ @comment_class.new.post.nil?.should be_true
14
22
  end
15
23
 
16
24
  should "be able to replace the association" do
17
- status = Status.new
18
- project = Project.new(:name => "mongomapper")
19
- status.project = project
20
- status.save.should be_true
25
+ post = @post_class.new(:name => 'mongomapper')
26
+ comment = @comment_class.new(:name => 'Foo!', :post => post)
27
+ comment.save.should be_true
21
28
 
22
- from_db = Status.find(status.id)
23
- from_db.project.nil?.should be_false
24
- from_db.project.name.should == "mongomapper"
29
+ comment = comment.reload
30
+ comment.post.should == post
31
+ comment.post.nil?.should be_false
25
32
  end
26
33
 
27
34
  should "unset the association" do
28
- status = Status.new
29
- project = Project.new(:name => "mongomapper")
30
- status.project = project
31
- status.save.should be_true
35
+ post = @post_class.new(:name => 'mongomapper')
36
+ comment = @comment_class.new(:name => 'Foo!', :post => post)
37
+ comment.save.should be_true
32
38
 
33
- from_db = Status.find(status.id)
34
- from_db.project = nil
35
- from_db.project.nil?.should be_true
36
- from_db.project.inspect.should == 'nil'
39
+ comment = comment.reload
40
+ comment.post = nil
41
+ comment.post.nil?.should be_true
37
42
  end
38
43
 
39
- context "association id set but document not found" do
40
- setup do
41
- @status = Status.new(:name => 'Foo', :project_id => '1234')
42
- end
43
-
44
- should "return nil instead of raising error" do
45
- @status.project.nil?.should be_true
46
- @status.project.inspect.should == 'nil'
47
- end
44
+ should "return nil if id set but document not found" do
45
+ @comment_class.new(:name => 'Foo', :post_id => '1234').post.nil?.should be_true
48
46
  end
49
- end
47
+ end
@@ -3,8 +3,8 @@ require 'models'
3
3
 
4
4
  class ManyDocumentsAsProxyTest < Test::Unit::TestCase
5
5
  def setup
6
- Post.collection.clear
7
- PostComment.collection.clear
6
+ Post.collection.remove
7
+ PostComment.collection.remove
8
8
  end
9
9
 
10
10
  should "default reader to empty array" do
@@ -171,20 +171,20 @@ class ManyDocumentsAsProxyTest < Test::Unit::TestCase
171
171
 
172
172
  should "not work for id not in association" do
173
173
  lambda {
174
- @post.comments.find(@comment5.id)
174
+ @post.comments.find!(@comment5.id)
175
175
  }.should raise_error(MongoMapper::DocumentNotFound)
176
176
  end
177
177
  end
178
178
 
179
179
  context "with multiple ids" do
180
180
  should "work for ids in association" do
181
- posts = @post.comments.find(@comment1.id, @comment2.id)
181
+ posts = @post.comments.find!(@comment1.id, @comment2.id)
182
182
  posts.should == [@comment1, @comment2]
183
183
  end
184
184
 
185
185
  should "not work for ids not in association" do
186
186
  lambda {
187
- @post.comments.find(@comment1.id, @comment2.id, @comment4.id)
187
+ @post.comments.find!(@comment1.id, @comment2.id, @comment4.id)
188
188
  }.should raise_error(MongoMapper::DocumentNotFound)
189
189
  end
190
190
  end
@@ -3,8 +3,8 @@ require 'models'
3
3
 
4
4
  class ManyEmbeddedPolymorphicProxyTest < Test::Unit::TestCase
5
5
  def setup
6
- Catalog.collection.clear
7
- TrModels::Fleet.collection.clear
6
+ Catalog.collection.remove
7
+ TrModels::Fleet.collection.remove
8
8
  end
9
9
 
10
10
  should "default reader to empty array" do
@@ -129,4 +129,28 @@ class ManyEmbeddedPolymorphicProxyTest < Test::Unit::TestCase
129
129
  from_db.transports[2].icu.should == true
130
130
  end
131
131
  end
132
- end
132
+
133
+ context "extending the association" do
134
+ should "work using a block passed to many" do
135
+ catalog = Catalog.new
136
+ medias = catalog.medias = [
137
+ Video.new("file" => "video.mpg", "length" => 3600, :visible => true),
138
+ Music.new("file" => "music.mp3", "bitrate" => "128kbps", :visible => true),
139
+ Image.new("file" => "image.png", "width" => 800, "height" => 600, :visible => false)
140
+ ]
141
+ catalog.save
142
+ catalog.medias.visible.should == [medias[0], medias[1]]
143
+ end
144
+
145
+ should "work using many's :extend option" do
146
+ fleet = TrModels::Fleet.new
147
+ transports = fleet.transports = [
148
+ TrModels::Car.new("license_plate" => "ABC1223", "model" => "Honda Civic", "year" => 2003, :purchased_on => 2.years.ago.to_date),
149
+ TrModels::Bus.new("license_plate" => "XYZ9090", "max_passengers" => 51, :purchased_on => 3.years.ago.to_date),
150
+ TrModels::Ambulance.new("license_plate" => "HDD3030", "icu" => true, :purchased_on => 1.year.ago.to_date)
151
+ ]
152
+ fleet.save
153
+ fleet.transports.to_be_replaced.should == [transports[1]]
154
+ end
155
+ end
156
+ end
@@ -3,8 +3,8 @@ require 'models'
3
3
 
4
4
  class ManyEmbeddedProxyTest < Test::Unit::TestCase
5
5
  def setup
6
- Project.collection.clear
7
- RealPerson.collection.clear
6
+ Project.collection.remove
7
+ RealPerson.collection.remove
8
8
  end
9
9
 
10
10
  should "default reader to empty array" do
@@ -17,13 +17,6 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
17
17
  project.addresses.push Address.new
18
18
  project.addresses.size.should == 2
19
19
  end
20
-
21
- should "allow finding :all embedded documents" do
22
- project = Project.new
23
- project.addresses << Address.new
24
- project.addresses << Address.new
25
- project.save
26
- end
27
20
 
28
21
  should "be embedded in document on save" do
29
22
  sb = Address.new(:city => 'South Bend', :state => 'IN')
@@ -45,7 +38,7 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
45
38
  set_collection_name 'test'
46
39
  key :person, Person
47
40
  end
48
- @document.collection.clear
41
+ @document.collection.remove
49
42
 
50
43
  meg = Person.new(:name => "Meg")
51
44
  meg.child = Person.new(:name => "Steve")
@@ -92,7 +85,7 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
92
85
  set_collection_name 'test'
93
86
  many :people
94
87
  end
95
- @document.collection.clear
88
+ @document.collection.remove
96
89
  end
97
90
 
98
91
  should "persist all embedded documents" do
@@ -130,45 +123,72 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
130
123
  doc.people.first.pets.first._root_document.should == doc
131
124
  end
132
125
 
133
- should "create properly-named reference to parent document when building off association proxy" do
134
- person = RealPerson.new
135
- pet = person.pets.build
136
- person.should == pet.real_person
137
- end
138
-
139
-
140
126
  should "create a reference to the root document for all embedded documents" do
141
- meg = Person.new(:name => "Meg")
142
127
  sparky = Pet.new(:name => "Sparky", :species => "Dog")
143
-
128
+ meg = Person.new(:name => "Meg", :pets => [sparky])
144
129
  doc = @document.new
145
-
146
- meg.pets << sparky
147
-
148
130
  doc.people << meg
149
131
  doc.save
150
132
 
151
- from_db = @document.find(doc.id)
152
- from_db.people.first._root_document.should == doc
153
- from_db.people.first.pets.first._root_document.should == doc
133
+ doc = doc.reload
134
+ doc.people.first._root_document.should == doc
135
+ doc.people.first.pets.first._root_document.should == doc
154
136
  end
155
137
  end
156
138
 
157
- should "allow retrieval via find(:all)" do
158
- meg = Person.new(:name => "Meg")
139
+ should "allow finding by id" do
159
140
  sparky = Pet.new(:name => "Sparky", :species => "Dog")
160
-
161
- meg.pets << sparky
162
-
163
- meg.pets.find(:all).should include(sparky)
141
+ meg = Person.new(:name => "Meg", :pets => [sparky])
142
+ meg.pets.find(sparky.id).should == sparky
164
143
  end
165
144
 
166
- should "allow retrieval via find(id)" do
167
- meg = Person.new(:name => "Meg")
168
- sparky = Pet.new(:name => "Sparky", :species => "Dog")
169
-
170
- meg.pets << sparky
145
+ context "extending the association" do
146
+ setup do
147
+ @address_class = Class.new do
148
+ include MongoMapper::EmbeddedDocument
149
+ key :address, String
150
+ key :city, String
151
+ key :state, String
152
+ key :zip, Integer
153
+ end
154
+
155
+ @project_class = Class.new do
156
+ include MongoMapper::Document
157
+ key :name, String
158
+ end
159
+
160
+ @project_class.collection.remove
161
+ end
171
162
 
172
- meg.pets.find(sparky.id).should == sparky
163
+ should "work using a block passed to many" do
164
+ @project_class.many :addresses, :class => @address_class do
165
+ def find_all_by_state(state)
166
+ find_all { |a| a.state == state }
167
+ end
168
+ end
169
+
170
+ addr1 = @address_class.new(:address => "Gate-3 Lankershim Blvd.", :city => "Universal City", :state => "CA", :zip => "91608")
171
+ addr2 = @address_class.new(:address => "3000 W. Alameda Ave.", :city => "Burbank", :state => "CA", :zip => "91523")
172
+ addr3 = @address_class.new(:address => "111 Some Ln", :city => "Nashville", :state => "TN", :zip => "37211")
173
+ project = @project_class.create(:name => "Some Project", :addresses => [addr1, addr2, addr3])
174
+
175
+ project.addresses.find_all_by_state("CA").should == [addr1, addr2]
176
+ end
177
+
178
+ should "work using many's :extend option" do
179
+ module FindByCity
180
+ def find_by_city(city)
181
+ find_all { |a| a.city == city }
182
+ end
183
+ end
184
+ @project_class.many :addresses, :class => @address_class, :extend => FindByCity
185
+
186
+ addr1 = @address_class.new(:address => "Gate-3 Lankershim Blvd.", :city => "Universal City", :state => "CA", :zip => "91608")
187
+ addr2 = @address_class.new(:address => "3000 W. Alameda Ave.", :city => "Burbank", :state => "CA", :zip => "91523")
188
+ addr3 = @address_class.new(:address => "111 Some Ln", :city => "Nashville", :state => "TN", :zip => "37211")
189
+ project = @project_class.create(:name => "Some Project", :addresses => [addr1, addr2, addr3])
190
+
191
+ project.addresses.find_by_city('Burbank').should == [addr2]
192
+ end
173
193
  end
174
194
  end
@@ -3,7 +3,8 @@ require 'models'
3
3
 
4
4
  class ManyPolymorphicProxyTest < Test::Unit::TestCase
5
5
  def setup
6
- Room.collection.clear
6
+ Room.collection.remove
7
+ Message.collection.remove
7
8
  end
8
9
 
9
10
  should "default reader to empty array" do
@@ -258,11 +259,25 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
258
259
 
259
260
  should "not work for id not in association" do
260
261
  lambda {
261
- @lounge.messages.find(@hm2.id)
262
+ @lounge.messages.find!(@hm2.id)
262
263
  }.should raise_error(MongoMapper::DocumentNotFound)
263
264
  end
264
265
  end
265
266
 
267
+ context "with query options/criteria" do
268
+ should "work with order on association" do
269
+ @lounge.messages.should == [@lm1, @lm2]
270
+ end
271
+
272
+ should "allow overriding the order provided to the association" do
273
+ @lounge.messages.all(:order => 'position desc').should == [@lm2, @lm1]
274
+ end
275
+
276
+ should "allow using conditions on association" do
277
+ @hall.latest_messages.should == [@hm3, @hm2]
278
+ end
279
+ end
280
+
266
281
  context "with multiple ids" do
267
282
  should "work for ids in association" do
268
283
  messages = @lounge.messages.find(@lm1.id, @lm2.id)
@@ -271,7 +286,7 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
271
286
 
272
287
  should "not work for ids not in association" do
273
288
  lambda {
274
- @lounge.messages.find(@lm1.id, @lm2.id, @hm2.id)
289
+ @lounge.messages.find!(@lm1.id, @lm2.id, @hm2.id)
275
290
  }.should raise_error(MongoMapper::DocumentNotFound)
276
291
  end
277
292
  end
@@ -294,4 +309,31 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
294
309
  end
295
310
  end
296
311
  end
312
+
313
+ context "extending the association" do
314
+ should "work using a block passed to many" do
315
+ room = Room.new(:name => "Amazing Room")
316
+ messages = room.messages = [
317
+ Enter.new(:body => 'John entered room', :position => 3),
318
+ Chat.new(:body => 'Heyyyoooo!', :position => 4),
319
+ Exit.new(:body => 'John exited room', :position => 5),
320
+ Enter.new(:body => 'Steve entered room', :position => 6),
321
+ Chat.new(:body => 'Anyone there?', :position => 7),
322
+ Exit.new(:body => 'Steve exited room', :position => 8)
323
+ ]
324
+ room.save
325
+ room.messages.older.should == messages[3..5]
326
+ end
327
+
328
+ should "work using many's :extend option" do
329
+ room = Room.new(:name => "Amazing Room")
330
+ accounts = room.accounts = [
331
+ Bot.new(:last_logged_in => 3.weeks.ago),
332
+ User.new(:last_logged_in => nil),
333
+ Bot.new(:last_logged_in => 1.week.ago)
334
+ ]
335
+ room.save
336
+ room.accounts.inactive.should == [accounts[1]]
337
+ end
338
+ end
297
339
  end
@@ -3,8 +3,8 @@ require 'models'
3
3
 
4
4
  class ManyProxyTest < Test::Unit::TestCase
5
5
  def setup
6
- Project.collection.clear
7
- Status.collection.clear
6
+ Project.collection.remove
7
+ Status.collection.remove
8
8
  end
9
9
 
10
10
  should "default reader to empty array" do
@@ -14,9 +14,9 @@ class ManyProxyTest < Test::Unit::TestCase
14
14
 
15
15
  should "allow adding to association like it was an array" do
16
16
  project = Project.new
17
- project.statuses << Status.new
18
- project.statuses.push Status.new
19
- project.statuses.concat Status.new
17
+ project.statuses << Status.new(:name => 'Foo1!')
18
+ project.statuses.push Status.new(:name => 'Foo2!')
19
+ project.statuses.concat Status.new(:name => 'Foo3!')
20
20
  project.statuses.size.should == 3
21
21
  end
22
22
 
@@ -59,14 +59,14 @@ class ManyProxyTest < Test::Unit::TestCase
59
59
  context "create" do
60
60
  should "assign foreign key" do
61
61
  project = Project.create
62
- status = project.statuses.create
62
+ status = project.statuses.create(:name => 'Foo!')
63
63
  status.project_id.should == project.id
64
64
  end
65
65
 
66
66
  should "save record" do
67
67
  project = Project.create
68
68
  lambda {
69
- project.statuses.create
69
+ project.statuses.create(:name => 'Foo!')
70
70
  }.should change { Status.count }
71
71
  end
72
72
 
@@ -77,13 +77,42 @@ class ManyProxyTest < Test::Unit::TestCase
77
77
  end
78
78
  end
79
79
 
80
+ context "create!" do
81
+ should "assign foreign key" do
82
+ project = Project.create
83
+ status = project.statuses.create!(:name => 'Foo!')
84
+ status.project_id.should == project.id
85
+ end
86
+
87
+ should "save record" do
88
+ project = Project.create
89
+ lambda {
90
+ project.statuses.create!(:name => 'Foo!')
91
+ }.should change { Status.count }
92
+ end
93
+
94
+ should "allow passing attributes" do
95
+ project = Project.create
96
+ status = project.statuses.create!(:name => 'Foo!')
97
+ status.name.should == 'Foo!'
98
+ end
99
+
100
+ should "raise exception if not valid" do
101
+ project = Project.create
102
+ lambda {
103
+ project.statuses.create!(:name => nil)
104
+ }.should raise_error(MongoMapper::DocumentNotValid)
105
+ end
106
+ end
107
+
108
+
80
109
  context "count" do
81
110
  should "work scoped to association" do
82
111
  project = Project.create
83
- 3.times { project.statuses.create }
112
+ 3.times { project.statuses.create(:name => 'Foo!') }
84
113
 
85
114
  other_project = Project.create
86
- 2.times { other_project.statuses.create }
115
+ 2.times { other_project.statuses.create(:name => 'Foo!') }
87
116
 
88
117
  project.statuses.count.should == 3
89
118
  other_project.statuses.count.should == 2
@@ -292,7 +321,7 @@ class ManyProxyTest < Test::Unit::TestCase
292
321
 
293
322
  should "not work for id not in association" do
294
323
  lambda {
295
- @project1.statuses.find(@archived.id)
324
+ @project1.statuses.find!(@archived.id)
296
325
  }.should raise_error(MongoMapper::DocumentNotFound)
297
326
  end
298
327
  end
@@ -305,7 +334,7 @@ class ManyProxyTest < Test::Unit::TestCase
305
334
 
306
335
  should "not work for ids not in association" do
307
336
  lambda {
308
- @project1.statuses.find(@brand_new.id, @complete.id, @archived.id)
337
+ @project1.statuses.find!(@brand_new.id, @complete.id, @archived.id)
309
338
  }.should raise_error(MongoMapper::DocumentNotFound)
310
339
  end
311
340
  end
@@ -328,4 +357,25 @@ class ManyProxyTest < Test::Unit::TestCase
328
357
  end
329
358
  end
330
359
  end
360
+
361
+ context "extending the association" do
362
+ should "work using a block passed to many" do
363
+ project = Project.new(:name => "Some Project")
364
+ status1 = Status.new(:name => "New")
365
+ status2 = Status.new(:name => "Assigned")
366
+ status3 = Status.new(:name => "Closed")
367
+ project.statuses = [status1, status2, status3]
368
+ project.save
369
+ project.statuses.open.should == [status1, status2]
370
+ end
371
+
372
+ should "work using many's :extend option" do
373
+ project = Project.new(:name => "Some Project")
374
+ collaborator1 = Collaborator.new(:name => "zing")
375
+ collaborator2 = Collaborator.new(:name => "zang")
376
+ project.collaborators = [collaborator1, collaborator2]
377
+ project.save
378
+ project.collaborators.top.should == collaborator1
379
+ end
380
+ end
331
381
  end
@@ -8,7 +8,7 @@ class AssociationsTest < Test::Unit::TestCase
8
8
 
9
9
  many :posts, :class_name => 'AssociationsTest::AwesomePost', :foreign_key => :creator_id
10
10
  end
11
- AwesomeUser.collection.clear
11
+ AwesomeUser.collection.remove
12
12
 
13
13
  class AwesomeTag
14
14
  include MongoMapper::EmbeddedDocument
@@ -28,8 +28,8 @@ class AssociationsTest < Test::Unit::TestCase
28
28
  many :tags, :class_name => 'AssociationsTest::AwesomeTag', :foreign_key => :post_id
29
29
  end
30
30
 
31
- AwesomeUser.collection.clear
32
- AwesomePost.collection.clear
31
+ AwesomeUser.collection.remove
32
+ AwesomePost.collection.remove
33
33
 
34
34
  user = AwesomeUser.create
35
35
  tag1 = AwesomeTag.new(:name => 'awesome')
@@ -7,7 +7,7 @@ class BinaryTest < Test::Unit::TestCase
7
7
  set_collection_name 'test'
8
8
  key :contents, Binary
9
9
  end
10
- klass.collection.clear
10
+ klass.collection.remove
11
11
 
12
12
  doc = klass.new(:contents => '010101')
13
13
  doc.save