mongo_mapper-unstable 2010.1.18 → 2010.1.19

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2010.01.18
1
+ 2010.01.19
@@ -22,6 +22,7 @@ module MongoMapper
22
22
  plugin Plugins::Serialization
23
23
  plugin Plugins::Validations
24
24
  plugin Plugins::Callbacks # for now callbacks needs to be after validations
25
+ plugin Plugins::IdentityMap
25
26
 
26
27
  extend Plugins::Validations::DocumentMacros
27
28
  end
@@ -45,29 +46,28 @@ module MongoMapper
45
46
  MongoMapper.ensure_index(self, keys_to_index, options)
46
47
  end
47
48
 
48
- def find!(*args)
49
+ def find(*args)
50
+ find_all_first_last_error(args)
49
51
  options = args.extract_options!
50
- case args.first
51
- when :first then first(options)
52
- when :last then last(options)
53
- when :all then find_every(options)
54
- when Array then find_some(args, options)
55
- else
56
- case args.size
57
- when 0
58
- raise DocumentNotFound, "Couldn't find without an ID"
59
- when 1
60
- find_one!(options.merge({:_id => args[0]}))
61
- else
62
- find_some(args, options)
63
- end
52
+ return nil if args.size == 0
53
+
54
+ if args.first.is_a?(Array) || args.size > 1
55
+ find_some(args, options)
56
+ else
57
+ find_one(options.merge({:_id => args[0]}))
64
58
  end
65
59
  end
66
-
67
- def find(*args)
68
- find!(*args)
69
- rescue DocumentNotFound
70
- nil
60
+
61
+ def find!(*args)
62
+ find_all_first_last_error(args)
63
+ options = args.extract_options!
64
+ raise DocumentNotFound, "Couldn't find without an ID" if args.size == 0
65
+
66
+ if args.first.is_a?(Array) || args.size > 1
67
+ find_some!(args, options)
68
+ else
69
+ find_one(options.merge({:_id => args[0]})) || raise(DocumentNotFound, "Document match #{options.inspect} does not exist in #{collection.name} collection")
70
+ end
71
71
  end
72
72
 
73
73
  def first(options={})
@@ -80,7 +80,7 @@ module MongoMapper
80
80
  end
81
81
 
82
82
  def all(options={})
83
- find_every(options)
83
+ find_many(options)
84
84
  end
85
85
 
86
86
  def find_by_id(id)
@@ -121,7 +121,7 @@ module MongoMapper
121
121
  end
122
122
 
123
123
  def destroy(*ids)
124
- find_some(ids.flatten).each(&:destroy)
124
+ find_some!(ids.flatten).each(&:destroy)
125
125
  end
126
126
 
127
127
  def destroy_all(options={})
@@ -168,20 +168,6 @@ module MongoMapper
168
168
  def pop(*args)
169
169
  modifier_update('$pop', args)
170
170
  end
171
-
172
- def modifier_update(modifier, args)
173
- criteria, keys = criteria_and_keys_from_args(args)
174
- modifiers = {modifier => keys}
175
- collection.update(criteria, modifiers, :multi => true)
176
- end
177
- private :modifier_update
178
-
179
- def criteria_and_keys_from_args(args)
180
- keys = args.pop
181
- criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
182
- [to_criteria(criteria), keys]
183
- end
184
- private :criteria_and_keys_from_args
185
171
 
186
172
  def embeddable?
187
173
  false
@@ -257,17 +243,33 @@ module MongoMapper
257
243
  instances.size == 1 ? instances[0] : instances
258
244
  end
259
245
 
260
- def find_every(options)
261
- criteria, options = to_finder_options(options)
262
- collection.find(criteria, options).to_a.map do |doc|
263
- load(doc)
246
+ def modifier_update(modifier, args)
247
+ criteria, keys = criteria_and_keys_from_args(args)
248
+ modifiers = {modifier => keys}
249
+ collection.update(criteria, modifiers, :multi => true)
250
+ end
251
+
252
+ def criteria_and_keys_from_args(args)
253
+ keys = args.pop
254
+ criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
255
+ [to_criteria(criteria), keys]
256
+ end
257
+
258
+ def find_all_first_last_error(args)
259
+ if args[0] == :first || args[0] == :last || args[0] == :all
260
+ raise ArgumentError, "#{self}.find(:#{args}) is no longer supported, use #{self}.#{args} instead."
264
261
  end
265
262
  end
266
263
 
267
264
  def find_some(ids, options={})
268
- ids = ids.flatten.compact.uniq
269
- documents = find_every(options.merge(:_id => ids))
270
-
265
+ ids = ids.flatten.compact.uniq
266
+ find_many(options.merge(:_id => ids)).compact
267
+ end
268
+
269
+ def find_some!(ids, options={})
270
+ ids = ids.flatten.compact.uniq
271
+ documents = find_some(ids, options)
272
+
271
273
  if ids.size == documents.size
272
274
  documents
273
275
  else
@@ -282,8 +284,11 @@ module MongoMapper
282
284
  end
283
285
  end
284
286
 
285
- def find_one!(options={})
286
- find_one(options) || raise(DocumentNotFound, "Document match #{options.inspect} does not exist in #{collection.name} collection")
287
+ def find_many(options)
288
+ criteria, options = to_finder_options(options)
289
+ collection.find(criteria, options).to_a.map do |doc|
290
+ load(doc)
291
+ end
287
292
  end
288
293
 
289
294
  def invert_order_clause(order)
@@ -365,10 +370,13 @@ module MongoMapper
365
370
  end
366
371
 
367
372
  def reload
368
- doc = self.class.find(_id)
369
- self.class.associations.each { |name, assoc| send(name).reset if respond_to?(name) }
370
- self.attributes = doc.attributes
371
- self
373
+ if attrs = collection.find_one({:_id => _id})
374
+ self.class.associations.each { |name, assoc| send(name).reset if respond_to?(name) }
375
+ self.attributes = attrs
376
+ self
377
+ else
378
+ raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
379
+ end
372
380
  end
373
381
 
374
382
  private
@@ -9,7 +9,7 @@ module MongoMapper
9
9
 
10
10
  options = args.extract_options!.merge(attributes)
11
11
 
12
- if result = find(finder.finder, options)
12
+ if result = send(finder.finder, options)
13
13
  result
14
14
  else
15
15
  if finder.raise?
@@ -2,6 +2,8 @@ module MongoMapper
2
2
  module Plugins
3
3
  module Associations
4
4
  class BelongsToPolymorphicProxy < Proxy
5
+ undef_method :object_id
6
+
5
7
  def replace(doc)
6
8
  if doc
7
9
  doc.save if doc.new?
@@ -16,7 +18,7 @@ module MongoMapper
16
18
  protected
17
19
  def find_target
18
20
  return nil if association_class.nil? || owner[reflection.foreign_key].nil?
19
- association_class.first(:id => owner[reflection.foreign_key])
21
+ association_class.find_by_id(owner[reflection.foreign_key])
20
22
  end
21
23
 
22
24
  def association_class
@@ -2,6 +2,8 @@ module MongoMapper
2
2
  module Plugins
3
3
  module Associations
4
4
  class BelongsToProxy < Proxy
5
+ undef_method :object_id
6
+
5
7
  def replace(doc)
6
8
  if doc
7
9
  doc.save if doc.new?
@@ -15,7 +17,7 @@ module MongoMapper
15
17
  protected
16
18
  def find_target
17
19
  return nil if owner[reflection.foreign_key].nil?
18
- klass.first(:id => owner[reflection.foreign_key])
20
+ klass.find_by_id(owner[reflection.foreign_key])
19
21
  end
20
22
  end
21
23
  end
@@ -2,6 +2,8 @@ module MongoMapper
2
2
  module Plugins
3
3
  module Associations
4
4
  class OneProxy < Proxy
5
+ undef_method :object_id
6
+
5
7
  def build(attrs={})
6
8
  instantiate_target(:new, attrs)
7
9
  end
@@ -38,9 +38,9 @@ module MongoMapper
38
38
  changed.inject({}) { |h, key| h[key] = key_change(key); h }
39
39
  end
40
40
 
41
- def initialize(attrs={})
41
+ def initialize(*args)
42
42
  super
43
- changed_keys.clear if attrs.blank?
43
+ changed_keys.clear if args.first.blank? || !new?
44
44
  end
45
45
 
46
46
  def save(*args)
@@ -1,36 +1,41 @@
1
1
  module MongoMapper
2
2
  module Plugins
3
3
  module IdentityMap
4
+ def self.identity_map
5
+ Thread.current[:mongo_mapper_identity_map] ||= {}
6
+ end
7
+
8
+ def self.identity_map=(v)
9
+ Thread.current[:mongo_mapper_identity_map] = v
10
+ end
11
+
4
12
  module ClassMethods
5
13
  def identity_map
6
- Thread.current[:mongo_mapper_identity_map] ||= {}
14
+ IdentityMap.identity_map
7
15
  end
8
16
 
9
17
  def identity_map=(v)
10
- Thread.current[:mongo_mapper_identity_map] = v
18
+ IdentityMap.identity_map = v
11
19
  end
12
20
 
13
21
  def identity_map_key(id)
14
- "#{self}:#{id}"
22
+ "#{collection.name}:#{id}"
15
23
  end
16
24
 
17
25
  def find_one(options={})
18
- criteria, options = to_finder_options(options)
26
+ criteria, finder_options = to_finder_options(options)
19
27
  key = identity_map_key(criteria[:_id])
20
-
21
- if document = identity_map[key]
28
+ if criteria.keys == [:_id] && document = identity_map[key]
22
29
  document
23
30
  else
24
31
  document = super
25
32
  end
26
-
33
+
27
34
  document
28
35
  end
29
36
 
30
37
  def load(attrs)
31
- id = attrs[:_id] || attrs[:id] || attrs['_id'] || attrs['id']
32
- key = identity_map_key(id)
33
-
38
+ key = identity_map_key(attrs['_id'])
34
39
  unless document = identity_map[key]
35
40
  document = super
36
41
  identity_map[document.identity_map_key] = document
@@ -49,7 +54,7 @@ module MongoMapper
49
54
  self.class.identity_map
50
55
  end
51
56
 
52
- def save
57
+ def save(*args)
53
58
  if result = super
54
59
  identity_map[identity_map_key] = self
55
60
  end
@@ -42,16 +42,13 @@ module MongoMapper
42
42
  value.is_a?(self) ? value : load(value)
43
43
  end
44
44
 
45
+ # load is overridden in identity map to ensure same objects are loaded
45
46
  def load(attrs)
46
47
  begin
47
48
  klass = attrs['_type'].present? ? attrs['_type'].constantize : self
48
- doc = klass.new(attrs)
49
- doc.instance_variable_set("@new", false)
50
- doc
49
+ klass.new(attrs, true)
51
50
  rescue NameError
52
- doc = new(attrs)
53
- doc.instance_variable_set("@new", false)
54
- doc
51
+ new(attrs, true)
55
52
  end
56
53
  end
57
54
 
@@ -140,7 +137,7 @@ module MongoMapper
140
137
  model.key :_id, ObjectId
141
138
  end
142
139
 
143
- def initialize(attrs={})
140
+ def initialize(attrs={}, from_db=false)
144
141
  unless attrs.nil?
145
142
  provided_keys = attrs.keys.map { |k| k.to_s }
146
143
  unless provided_keys.include?('_id') || provided_keys.include?('id')
@@ -148,7 +145,7 @@ module MongoMapper
148
145
  end
149
146
  end
150
147
 
151
- @new = true
148
+ @new = from_db ? false : true
152
149
  self._type = self.class.name if respond_to?(:_type=)
153
150
  self.attributes = attrs
154
151
  end
@@ -13,7 +13,7 @@ module MongoMapper
13
13
  pagination = Pagination::PaginationProxy.new(total_entries, page, per_page)
14
14
 
15
15
  options.merge!(:limit => pagination.limit, :skip => pagination.skip)
16
- pagination.subject = find_every(options)
16
+ pagination.subject = find_many(options)
17
17
  pagination
18
18
  end
19
19
  end
@@ -131,23 +131,6 @@ class ManyDocumentsAsProxyTest < Test::Unit::TestCase
131
131
  @post2.save
132
132
  end
133
133
 
134
- context "with :all" do
135
- should "work" do
136
- @post.comments.find(:all).should include(@comment1)
137
- @post.comments.find(:all).should include(@comment2)
138
- end
139
-
140
- should "work with conditions" do
141
- comments = @post.comments.find(:all, :body => 'comment1')
142
- comments.should == [@comment1]
143
- end
144
-
145
- should "work with order" do
146
- comments = @post.comments.find(:all, :order => 'body desc')
147
- comments.should == [@comment2, @comment1]
148
- end
149
- end
150
-
151
134
  context "with #all" do
152
135
  should "work" do
153
136
  @post.comments.all.should include(@comment1)
@@ -171,9 +154,9 @@ class ManyDocumentsAsProxyTest < Test::Unit::TestCase
171
154
  end
172
155
 
173
156
  should "not work for id not in association" do
174
- lambda {
157
+ assert_raises(MongoMapper::DocumentNotFound) do
175
158
  @post.comments.find!(@comment5._id)
176
- }.should raise_error(MongoMapper::DocumentNotFound)
159
+ end
177
160
  end
178
161
  end
179
162
 
@@ -184,9 +167,9 @@ class ManyDocumentsAsProxyTest < Test::Unit::TestCase
184
167
  end
185
168
 
186
169
  should "not work for ids not in association" do
187
- lambda {
170
+ assert_raises(MongoMapper::DocumentNotFound) do
188
171
  @post.comments.find!(@comment1._id, @comment2._id, @comment4._id)
189
- }.should raise_error(MongoMapper::DocumentNotFound)
172
+ end
190
173
  end
191
174
  end
192
175
 
@@ -242,36 +242,30 @@ class ManyDocumentsProxyTest < Test::Unit::TestCase
242
242
 
243
243
  context "all" do
244
244
  should "work" do
245
- @project1.statuses.find(:all, :order => "position asc").should == [@brand_new, @complete]
246
245
  @project1.statuses.all(:order => "position asc").should == [@brand_new, @complete]
247
246
  end
248
247
 
249
248
  should "work with conditions" do
250
- @project1.statuses.find(:all, :name => 'Complete').should == [@complete]
251
249
  @project1.statuses.all(:name => 'Complete').should == [@complete]
252
250
  end
253
251
  end
254
252
 
255
253
  context "first" do
256
254
  should "work" do
257
- @project1.statuses.find(:first, :order => 'name').should == @complete
258
255
  @project1.statuses.first(:order => 'name').should == @complete
259
256
  end
260
257
 
261
258
  should "work with conditions" do
262
- @project1.statuses.find(:first, :name => 'Complete').should == @complete
263
259
  @project1.statuses.first(:name => 'Complete').should == @complete
264
260
  end
265
261
  end
266
262
 
267
263
  context "last" do
268
264
  should "work" do
269
- @project1.statuses.find(:last, :order => "position asc").should == @complete
270
265
  @project1.statuses.last(:order => "position asc").should == @complete
271
266
  end
272
267
 
273
268
  should "work with conditions" do
274
- @project1.statuses.find(:last, :order => 'position', :name => 'New').should == @brand_new
275
269
  @project1.statuses.last(:order => 'position', :name => 'New').should == @brand_new
276
270
  end
277
271
  end
@@ -295,9 +289,9 @@ class ManyDocumentsProxyTest < Test::Unit::TestCase
295
289
  end
296
290
 
297
291
  should "not work for ids not in association" do
298
- lambda {
292
+ assert_raises(MongoMapper::DocumentNotFound) do
299
293
  @project1.statuses.find!(@brand_new.id, @complete.id, @archived.id)
300
- }.should raise_error(MongoMapper::DocumentNotFound)
294
+ end
301
295
  end
302
296
  end
303
297
 
@@ -176,22 +176,6 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
176
176
  end
177
177
  end
178
178
 
179
- context "with :all" do
180
- should "work" do
181
- @lounge.messages.find(:all, :order => "position").should == [@lm1, @lm2]
182
- end
183
-
184
- should "work with conditions" do
185
- messages = @lounge.messages.find(:all, :body => 'Loungin!', :order => "position")
186
- messages.should == [@lm1]
187
- end
188
-
189
- should "work with order" do
190
- messages = @lounge.messages.find(:all, :order => 'position desc')
191
- messages.should == [@lm2, @lm1]
192
- end
193
- end
194
-
195
179
  context "with #all" do
196
180
  should "work" do
197
181
  @lounge.messages.all(:order => "position").should == [@lm1, @lm2]
@@ -208,17 +192,6 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
208
192
  end
209
193
  end
210
194
 
211
- context "with :first" do
212
- should "work" do
213
- @lounge.messages.find(:first, :order => "position asc").should == @lm1
214
- end
215
-
216
- should "work with conditions" do
217
- message = @lounge.messages.find(:first, :body => 'I love loungin!', :order => "position asc")
218
- message.should == @lm2
219
- end
220
- end
221
-
222
195
  context "with #first" do
223
196
  should "work" do
224
197
  @lounge.messages.first(:order => "position asc").should == @lm1
@@ -230,17 +203,6 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
230
203
  end
231
204
  end
232
205
 
233
- context "with :last" do
234
- should "work" do
235
- @lounge.messages.find(:last, :order => "position asc").should == @lm2
236
- end
237
-
238
- should "work with conditions" do
239
- message = @lounge.messages.find(:last, :body => 'Loungin!', :order => "position asc")
240
- message.should == @lm1
241
- end
242
- end
243
-
244
206
  context "with #last" do
245
207
  should "work" do
246
208
  @lounge.messages.last(:order => "position asc").should == @lm2
@@ -285,9 +247,9 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
285
247
  end
286
248
 
287
249
  should "not work for ids not in association" do
288
- lambda {
250
+ assert_raises(MongoMapper::DocumentNotFound) do
289
251
  @lounge.messages.find!(@lm1._id, @lm2._id, @hm2._id)
290
- }.should raise_error(MongoMapper::DocumentNotFound)
252
+ end
291
253
  end
292
254
  end
293
255
 
@@ -1,23 +1,17 @@
1
1
  require 'test_helper'
2
- require 'models'
3
2
 
4
3
  class DirtyTest < Test::Unit::TestCase
5
4
  def setup
6
- @document = Doc do
7
- key :phrase, String
8
- end
9
-
10
- Status.collection.remove
11
- Project.collection.remove
5
+ @document = Doc { key :phrase, String }
12
6
  end
13
-
7
+
14
8
  context "marking changes" do
15
9
  should "not happen if there are none" do
16
10
  doc = @document.new
17
11
  doc.phrase_changed?.should be_false
18
12
  doc.phrase_change.should be_nil
19
13
  end
20
-
14
+
21
15
  should "happen when change happens" do
22
16
  doc = @document.new
23
17
  doc.phrase = 'Golly Gee Willikers Batman'
@@ -25,12 +19,12 @@ class DirtyTest < Test::Unit::TestCase
25
19
  doc.phrase_was.should be_nil
26
20
  doc.phrase_change.should == [nil, 'Golly Gee Willikers Batman']
27
21
  end
28
-
22
+
29
23
  should "happen when initializing" do
30
24
  doc = @document.new(:phrase => 'Foo')
31
25
  doc.changed?.should be_true
32
26
  end
33
-
27
+
34
28
  should "clear changes on save" do
35
29
  doc = @document.new
36
30
  doc.phrase = 'Golly Gee Willikers Batman'
@@ -39,7 +33,7 @@ class DirtyTest < Test::Unit::TestCase
39
33
  doc.phrase_changed?.should_not be_true
40
34
  doc.phrase_change.should be_nil
41
35
  end
42
-
36
+
43
37
  should "clear changes on save!" do
44
38
  doc = @document.new
45
39
  doc.phrase = 'Golly Gee Willikers Batman'
@@ -48,15 +42,18 @@ class DirtyTest < Test::Unit::TestCase
48
42
  doc.phrase_changed?.should_not be_true
49
43
  doc.phrase_change.should be_nil
50
44
  end
51
-
45
+
52
46
  should "not happen when loading from database" do
53
47
  doc = @document.create(:phrase => 'Foo')
48
+ doc = @document.find(doc.id)
49
+
50
+ doc.changed?.should be_false
54
51
  doc.phrase = 'Fart'
55
52
  doc.changed?.should be_true
56
53
  doc.reload
57
54
  doc.changed?.should be_false
58
55
  end
59
-
56
+
60
57
  should "happen if changed after loading from database" do
61
58
  doc = @document.create(:phrase => 'Foo')
62
59
  doc.reload
@@ -65,7 +62,7 @@ class DirtyTest < Test::Unit::TestCase
65
62
  doc.changed?.should be_true
66
63
  end
67
64
  end
68
-
65
+
69
66
  context "blank new value and type integer" do
70
67
  should "not mark changes" do
71
68
  @document.key :age, Integer
@@ -147,10 +144,20 @@ class DirtyTest < Test::Unit::TestCase
147
144
 
148
145
  context "changing a foreign key through association" do
149
146
  should "mark changes" do
150
- status = Status.create(:name => 'Foo')
151
- status.project = Project.create(:name => 'Bar')
152
- status.changed?.should be_true
153
- status.changed.should == %w(project_id)
147
+ project_class = Doc do
148
+ key :name, String
149
+ end
150
+
151
+ milestone_class = Doc do
152
+ key :project_id, ObjectId
153
+ key :name, String
154
+ end
155
+ milestone_class.belongs_to :project, :class => project_class
156
+
157
+ milestone = milestone_class.create(:name => 'Launch')
158
+ milestone.project = project_class.create(:name => 'Harmony')
159
+ milestone.changed?.should be_true
160
+ milestone.changed.should == %w(project_id)
154
161
  end
155
162
  end
156
163
  end
@@ -239,7 +239,19 @@ class DocumentTest < Test::Unit::TestCase
239
239
  end
240
240
 
241
241
  should "raise document not found if nothing provided for find!" do
242
- lambda { @document.find! }.should raise_error(MongoMapper::DocumentNotFound)
242
+ assert_raises(MongoMapper::DocumentNotFound) do
243
+ @document.find!
244
+ end
245
+ end
246
+
247
+ should "raise error if trying to find with :all, :first, or :last" do
248
+ [:all, :first, :last].each do |m|
249
+ assert_raises(ArgumentError) { @document.find(m) }
250
+ end
251
+
252
+ [:all, :first, :last].each do |m|
253
+ assert_raises(ArgumentError) { @document.find!(m) }
254
+ end
243
255
  end
244
256
 
245
257
  context "(with a single id)" do
@@ -252,9 +264,7 @@ class DocumentTest < Test::Unit::TestCase
252
264
  end
253
265
 
254
266
  should "raise error if document not found with find!" do
255
- lambda {
256
- @document.find!(123)
257
- }.should raise_error(MongoMapper::DocumentNotFound)
267
+ assert_raises(MongoMapper::DocumentNotFound) { @document.find!(123) }
258
268
  end
259
269
  end
260
270
 
@@ -267,7 +277,17 @@ class DocumentTest < Test::Unit::TestCase
267
277
  @document.find([@doc1._id, @doc2._id]).should == [@doc1, @doc2]
268
278
  end
269
279
 
270
- should "return array if array only has one element" do
280
+ should "compact not found when using find" do
281
+ @document.find(@doc1._id, 1234).should == [@doc1]
282
+ end
283
+
284
+ should "raise error if not all found when using find!" do
285
+ assert_raises(MongoMapper::DocumentNotFound) do
286
+ @document.find!(@doc1._id, 1234)
287
+ end
288
+ end
289
+
290
+ should "return array if array with one element" do
271
291
  @document.find([@doc1._id]).should == [@doc1]
272
292
  end
273
293
  end
@@ -277,43 +297,21 @@ class DocumentTest < Test::Unit::TestCase
277
297
  @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
278
298
  end
279
299
 
280
- context "(with :all)" do
281
- should "find all documents" do
282
- @document.find(:all, :order => 'first_name').should == [@doc1, @doc3, @doc2]
283
- end
284
-
285
- should "be able to add conditions" do
286
- @document.find(:all, :first_name => 'John').should == [@doc1]
287
- end
288
- end
289
-
290
- context "(with #all)" do
300
+ context "#all" do
291
301
  should "find all documents based on criteria" do
292
302
  @document.all(:order => 'first_name').should == [@doc1, @doc3, @doc2]
293
303
  @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
294
304
  end
295
305
  end
296
306
 
297
- context "(with :first)" do
298
- should "find first document" do
299
- @document.find(:first, :order => 'first_name').should == @doc1
300
- end
301
- end
302
-
303
- context "(with #first)" do
307
+ context "#first" do
304
308
  should "find first document based on criteria" do
305
309
  @document.first(:order => 'first_name').should == @doc1
306
310
  @document.first(:age => 28).should == @doc2
307
311
  end
308
312
  end
309
313
 
310
- context "(with :last)" do
311
- should "find last document" do
312
- @document.find(:last, :order => 'age').should == @doc2
313
- end
314
- end
315
-
316
- context "(with #last)" do
314
+ context "#last" do
317
315
  should "find last document based on criteria" do
318
316
  @document.last(:order => 'age').should == @doc2
319
317
  @document.last(:order => 'age', :age => 28).should == @doc2
@@ -324,7 +322,7 @@ class DocumentTest < Test::Unit::TestCase
324
322
  end
325
323
  end
326
324
 
327
- context "(with :find_by)" do
325
+ context "#find_by..." do
328
326
  should "find document based on argument" do
329
327
  @document.find_by_first_name('John').should == @doc1
330
328
  @document.find_by_last_name('Nunemaker', :order => 'age desc').should == @doc1
@@ -340,7 +338,7 @@ class DocumentTest < Test::Unit::TestCase
340
338
  end
341
339
  end
342
340
 
343
- context "(with dynamic finders)" do
341
+ context "dynamic finders" do
344
342
  should "find document based on all arguments" do
345
343
  @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 27).should == @doc1
346
344
  end
@@ -393,7 +391,7 @@ class DocumentTest < Test::Unit::TestCase
393
391
  end
394
392
 
395
393
  should "return nil if document not found" do
396
- @document.find_by_id(1234).should be(nil)
394
+ @document.find_by_id(1234).should be_nil
397
395
  end
398
396
  end
399
397
 
@@ -835,7 +833,7 @@ class DocumentTest < Test::Unit::TestCase
835
833
  @parent.save
836
834
  @daughter.save
837
835
 
838
- collection = DocParent.find(:all)
836
+ collection = DocParent.all
839
837
  collection.size.should == 2
840
838
  collection.first.should be_kind_of(DocParent)
841
839
  collection.first.name.should == "Daddy Warbucks"
@@ -1104,6 +1102,11 @@ class DocumentTest < Test::Unit::TestCase
1104
1102
  should "return self" do
1105
1103
  @instance.reload.object_id.should == @instance.object_id
1106
1104
  end
1105
+
1106
+ should "raise DocumentNotFound if not found" do
1107
+ @instance.destroy
1108
+ assert_raises(MongoMapper::DocumentNotFound) { @instance.reload }
1109
+ end
1107
1110
  end
1108
1111
 
1109
1112
  context "Loading a document from the database with keys that are not defined" do
@@ -14,17 +14,21 @@ class IdentityMapTest < Test::Unit::TestCase
14
14
  context "Document" do
15
15
  setup do
16
16
  @person_class = Doc('Person') do
17
+ set_collection_name 'people'
17
18
  key :name, String
18
- plugin MongoMapper::Plugins::IdentityMap
19
19
  end
20
20
 
21
21
  @post_class = Doc('Post') do
22
+ set_collection_name 'posts'
22
23
  key :title, String
23
- plugin MongoMapper::Plugins::IdentityMap
24
+ key :person_id, ObjectId
24
25
  end
25
26
 
26
- @person_class.identity_map = {}
27
- @post_class.identity_map = {}
27
+ @post_class.belongs_to :person, :class => @person_class
28
+ @person_class.many :posts, :class => @post_class
29
+
30
+ @person_class.identity_map.clear
31
+ @post_class.identity_map.clear
28
32
  end
29
33
 
30
34
  should "default identity map to hash" do
@@ -40,11 +44,11 @@ class IdentityMapTest < Test::Unit::TestCase
40
44
 
41
45
  should "have identity map key that is always unique per document and class" do
42
46
  person = @person_class.new
43
- person.identity_map_key.should == "Person:#{person.id}"
47
+ person.identity_map_key.should == "people:#{person.id}"
44
48
  @person_class.identity_map_key(person.id).should == person.identity_map_key
45
49
 
46
50
  post = @post_class.new
47
- post.identity_map_key.should == "Post:#{post.id}"
51
+ post.identity_map_key.should == "posts:#{post.id}"
48
52
  @post_class.identity_map_key(post.id).should == post.identity_map_key
49
53
 
50
54
  person.identity_map_key.should_not == post.identity_map_key
@@ -56,6 +60,13 @@ class IdentityMapTest < Test::Unit::TestCase
56
60
  person.save.should be_true
57
61
  assert_in_map(person)
58
62
  end
63
+
64
+ should "allow saving with options" do
65
+ person = @person_class.new
66
+ assert_nothing_raised do
67
+ person.save(:validate => false).should be_true
68
+ end
69
+ end
59
70
 
60
71
  should "remove key from map when deleted" do
61
72
  person = @person_class.create(:name => 'Fred')
@@ -64,35 +75,39 @@ class IdentityMapTest < Test::Unit::TestCase
64
75
  assert_not_in_map(person)
65
76
  end
66
77
 
67
- context "#load" do
78
+ context "reload" do
68
79
  setup do
69
- @id = Mongo::ObjectID.new
80
+ @person = @person_class.create(:name => 'Fred')
70
81
  end
71
-
72
- should "add document to map with _id key as symbol" do
73
- loaded = @person_class.load({:_id => @id, :name => 'Frank'})
74
- assert_in_map(loaded)
82
+
83
+ should "remove object from identity and re-query" do
84
+ assert_in_map(@person)
85
+ Mongo::Collection.any_instance.expects(:find_one).once.returns({})
86
+ @person.reload
75
87
  end
76
88
 
77
- should "add document to map with _id key as string" do
78
- loaded = @person_class.load({'_id' => @id, :name => 'Frank'})
79
- assert_in_map(loaded)
89
+ should "add object back into map" do
90
+ assert_in_map(@person)
91
+ object_id = @person.object_id
92
+ @person.reload.object_id.should == object_id
93
+ assert_in_map(@person)
80
94
  end
81
-
82
- should "add document to map with id key as symbol" do
83
- loaded = @person_class.load({:id => @id, :name => 'Frank'})
84
- assert_in_map(loaded)
95
+ end
96
+
97
+ context "#load" do
98
+ setup do
99
+ @id = Mongo::ObjectID.new
85
100
  end
86
-
87
- should "add document to map with id key as string" do
88
- loaded = @person_class.load({'id' => @id, :name => 'Frank'})
101
+
102
+ should "add document to map" do
103
+ loaded = @person_class.load({'_id' => @id, 'name' => 'Frank'})
89
104
  assert_in_map(loaded)
90
105
  end
91
-
106
+
92
107
  should "return document if already in map" do
93
- first_load = @person_class.load({:_id => @id, :name => 'Frank'})
108
+ first_load = @person_class.load({'_id' => @id, 'name' => 'Frank'})
94
109
  @person_class.identity_map.expects(:[]=).never
95
- second_load = @person_class.load({:_id => @id, :name => 'Frank'})
110
+ second_load = @person_class.load({'_id' => @id, 'name' => 'Frank'})
96
111
  first_load.object_id.should == second_load.object_id
97
112
  end
98
113
  end
@@ -132,6 +147,32 @@ class IdentityMapTest < Test::Unit::TestCase
132
147
  found_person = @person_class.find(@person.id)
133
148
  found_person.object_id.should == @person.object_id
134
149
  end
150
+ end
151
+ end
152
+
153
+ context "#find (with one id and options)" do
154
+ setup do
155
+ @person = @person_class.create(:name => 'Fred')
156
+ @post1 = @person.posts.create(:title => 'I Love Mongo')
157
+ @post2 = @person.posts.create(:title => 'Migrations Suck!')
158
+ end
159
+
160
+ # There are times when even though the id matches, other criteria doesn't
161
+ # so we need to do the query to ensure that when criteria doesn't match
162
+ # the document is in fact not found.
163
+ #
164
+ # I'm open to not making this query if someone can figure out reliable
165
+ # way to check if document matches criteria without querying.
166
+ should "query the database" do
167
+ assert_in_map(@post1)
168
+ Mongo::Collection.any_instance.expects(:find_one)
169
+ @person.posts.find(@post1.id)
170
+ end
171
+
172
+ should "return exact object" do
173
+ assert_in_map(@post1)
174
+ @person.posts.find(@post1.id)
175
+ assert_in_map(@post1)
135
176
  end
136
177
  end
137
178
 
@@ -229,5 +270,69 @@ class IdentityMapTest < Test::Unit::TestCase
229
270
  end
230
271
  end
231
272
 
273
+ context "#find_by_id" do
274
+ setup do
275
+ @person = @person_class.create(:name => 'Bill')
276
+ end
277
+
278
+ should "return nil for document id not found in collection" do
279
+ assert_in_map(@person)
280
+ @person_class.find_by_id(1234).should be_nil
281
+ end
282
+ end
283
+
284
+ context "single collection inheritance" do
285
+ setup do
286
+ class ::DocParent
287
+ include MongoMapper::Document
288
+ key :_type, String
289
+ key :name, String
290
+ key :parent_id, ObjectId
291
+
292
+ belongs_to :parent, :class_name => 'DocParent'
293
+ one :child, :class_name => 'DocDaughter'
294
+ end
295
+ DocParent.collection.remove
296
+ DocParent.identity_map.clear
297
+
298
+ class ::DocDaughter < ::DocParent; end
299
+ end
300
+
301
+ teardown do
302
+ Object.send :remove_const, 'DocParent' if defined?(::DocParent)
303
+ Object.send :remove_const, 'DocDaughter' if defined?(::DocDaughter)
304
+ end
305
+
306
+ should "share the same identity map 4eva" do
307
+ @daughter = DocDaughter.create(:name => 'Jill')
308
+ assert_in_map(@daughter)
309
+ DocParent.identity_map_key(@daughter).should == DocDaughter.identity_map_key(@daughter)
310
+ DocParent.identity_map.object_id.should == DocDaughter.identity_map.object_id
311
+ end
312
+
313
+ should "load from map when using parent collection inherited class" do
314
+ @daughter = DocDaughter.create(:name => 'Jill')
315
+ DocParent.find(@daughter.id).object_id.should == @daughter.object_id
316
+ end
317
+
318
+ should "work correctly with belongs to proxy" do
319
+ @parent = DocParent.create(:name => 'Dad')
320
+ assert_in_map(@parent)
321
+
322
+ @daughter = DocDaughter.create(:name => 'Jill', :parent => @parent)
323
+ assert_in_map(@daughter)
324
+ @parent.object_id.should == @daughter.parent.object_id
325
+ end
326
+
327
+ should "work correctly with one proxy" do
328
+ @daughter = DocDaughter.create(:name => 'Jill')
329
+ assert_in_map(@daughter)
330
+
331
+ @parent = DocParent.create(:name => 'Dad', :child => @daughter)
332
+ assert_in_map(@parent)
333
+
334
+ @parent.child.object_id.should == @daughter.object_id
335
+ end
336
+ end
232
337
  end
233
338
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongo_mapper-unstable
3
3
  version: !ruby/object:Gem::Version
4
- version: 2010.1.18
4
+ version: 2010.1.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-18 00:00:00 -05:00
12
+ date: 2010-01-19 00:00:00 -05:00
13
13
  default_executable: mmconsole
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency