mongo_mapper-unstable 2010.1.18 → 2010.1.19
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/VERSION +1 -1
- data/lib/mongo_mapper/document.rb +57 -49
- data/lib/mongo_mapper/dynamic_finder.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +3 -1
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +3 -1
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +2 -0
- data/lib/mongo_mapper/plugins/dirty.rb +2 -2
- data/lib/mongo_mapper/plugins/identity_map.rb +16 -11
- data/lib/mongo_mapper/plugins/keys.rb +5 -8
- data/lib/mongo_mapper/plugins/pagination.rb +1 -1
- data/test/functional/associations/test_many_documents_as_proxy.rb +4 -21
- data/test/functional/associations/test_many_documents_proxy.rb +2 -8
- data/test/functional/associations/test_many_polymorphic_proxy.rb +2 -40
- data/test/functional/test_dirty.rb +26 -19
- data/test/functional/test_document.rb +37 -34
- data/test/functional/test_identity_map.rb +130 -25
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2010.01.
|
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
|
49
|
+
def find(*args)
|
50
|
+
find_all_first_last_error(args)
|
49
51
|
options = args.extract_options!
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
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
|
261
|
-
criteria,
|
262
|
-
|
263
|
-
|
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
|
269
|
-
|
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
|
286
|
-
|
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
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
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
|
@@ -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.
|
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.
|
20
|
+
klass.find_by_id(owner[reflection.foreign_key])
|
19
21
|
end
|
20
22
|
end
|
21
23
|
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(
|
41
|
+
def initialize(*args)
|
42
42
|
super
|
43
|
-
changed_keys.clear if
|
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
|
-
|
14
|
+
IdentityMap.identity_map
|
7
15
|
end
|
8
16
|
|
9
17
|
def identity_map=(v)
|
10
|
-
|
18
|
+
IdentityMap.identity_map = v
|
11
19
|
end
|
12
20
|
|
13
21
|
def identity_map_key(id)
|
14
|
-
"#{
|
22
|
+
"#{collection.name}:#{id}"
|
15
23
|
end
|
16
24
|
|
17
25
|
def find_one(options={})
|
18
|
-
criteria,
|
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
|
-
|
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
|
-
|
49
|
-
doc.instance_variable_set("@new", false)
|
50
|
-
doc
|
49
|
+
klass.new(attrs, true)
|
51
50
|
rescue NameError
|
52
|
-
|
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 =
|
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
|
-
|
157
|
+
assert_raises(MongoMapper::DocumentNotFound) do
|
175
158
|
@post.comments.find!(@comment5._id)
|
176
|
-
|
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
|
-
|
170
|
+
assert_raises(MongoMapper::DocumentNotFound) do
|
188
171
|
@post.comments.find!(@comment1._id, @comment2._id, @comment4._id)
|
189
|
-
|
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
|
-
|
292
|
+
assert_raises(MongoMapper::DocumentNotFound) do
|
299
293
|
@project1.statuses.find!(@brand_new.id, @complete.id, @archived.id)
|
300
|
-
|
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
|
-
|
250
|
+
assert_raises(MongoMapper::DocumentNotFound) do
|
289
251
|
@lounge.messages.find!(@lm1._id, @lm2._id, @hm2._id)
|
290
|
-
|
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
|
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
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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
|
-
|
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
|
-
|
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 "
|
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 "
|
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 "
|
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 "
|
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 "
|
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 "
|
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
|
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.
|
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
|
-
|
24
|
+
key :person_id, ObjectId
|
24
25
|
end
|
25
26
|
|
26
|
-
@
|
27
|
-
@
|
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 == "
|
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 == "
|
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 "
|
78
|
+
context "reload" do
|
68
79
|
setup do
|
69
|
-
@
|
80
|
+
@person = @person_class.create(:name => 'Fred')
|
70
81
|
end
|
71
|
-
|
72
|
-
should "
|
73
|
-
|
74
|
-
|
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
|
78
|
-
|
79
|
-
|
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
|
-
|
83
|
-
|
84
|
-
|
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
|
88
|
-
loaded = @person_class.load({'
|
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({
|
108
|
+
first_load = @person_class.load({'_id' => @id, 'name' => 'Frank'})
|
94
109
|
@person_class.identity_map.expects(:[]=).never
|
95
|
-
second_load = @person_class.load({
|
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.
|
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-
|
12
|
+
date: 2010-01-19 00:00:00 -05:00
|
13
13
|
default_executable: mmconsole
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|