mongo_mapper-unstable 2010.1.6 → 2010.1.12
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/descendant_appends.rb +44 -0
- data/lib/mongo_mapper/document.rb +54 -98
- data/lib/mongo_mapper/embedded_document.rb +28 -348
- data/lib/mongo_mapper/finder_options.rb +15 -33
- data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +28 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +23 -0
- data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +49 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
- data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +66 -0
- data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
- data/lib/mongo_mapper/plugins/associations.rb +104 -0
- data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
- data/lib/mongo_mapper/plugins/clone.rb +13 -0
- data/lib/mongo_mapper/plugins/descendants.rb +16 -0
- data/lib/mongo_mapper/plugins/dirty.rb +119 -0
- data/lib/mongo_mapper/plugins/equality.rb +11 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +66 -0
- data/lib/mongo_mapper/plugins/inspect.rb +14 -0
- data/lib/mongo_mapper/plugins/keys.rb +295 -0
- data/lib/mongo_mapper/plugins/logger.rb +17 -0
- data/lib/mongo_mapper/plugins/pagination.rb +85 -0
- data/lib/mongo_mapper/plugins/rails.rb +45 -0
- data/lib/mongo_mapper/plugins/serialization.rb +109 -0
- data/lib/mongo_mapper/plugins/validations.rb +48 -0
- data/lib/mongo_mapper/plugins.rb +19 -0
- data/lib/mongo_mapper/support.rb +36 -15
- data/lib/mongo_mapper.rb +23 -22
- data/performance/read_write.rb +52 -0
- data/specs.watchr +23 -2
- data/test/functional/associations/test_belongs_to_proxy.rb +1 -1
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +58 -39
- data/test/functional/associations/test_many_embedded_proxy.rb +103 -69
- data/test/functional/test_dirty.rb +1 -1
- data/test/functional/test_document.rb +25 -25
- data/test/functional/test_embedded_document.rb +66 -63
- data/test/functional/test_identity_map.rb +233 -0
- data/test/functional/test_modifiers.rb +14 -0
- data/test/functional/test_string_id_compatibility.rb +4 -4
- data/test/functional/test_validations.rb +13 -0
- data/test/models.rb +0 -39
- data/test/test_helper.rb +8 -2
- data/test/unit/associations/test_base.rb +1 -1
- data/test/unit/associations/test_proxy.rb +3 -3
- data/test/unit/test_descendant_appends.rb +71 -0
- data/test/unit/test_document.rb +35 -46
- data/test/unit/test_embedded_document.rb +218 -271
- data/test/unit/{test_key.rb → test_keys.rb} +0 -0
- data/test/unit/test_pagination.rb +10 -2
- data/test/unit/test_plugins.rb +42 -0
- data/test/unit/test_rails.rb +123 -0
- data/test/unit/{test_serializations.rb → test_serialization.rb} +0 -0
- data/test/unit/test_support.rb +10 -6
- data/test/unit/test_time_zones.rb +2 -2
- metadata +44 -31
- data/lib/mongo_mapper/associations/base.rb +0 -119
- data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +0 -26
- data/lib/mongo_mapper/associations/belongs_to_proxy.rb +0 -21
- data/lib/mongo_mapper/associations/collection.rb +0 -19
- data/lib/mongo_mapper/associations/in_array_proxy.rb +0 -137
- data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -26
- data/lib/mongo_mapper/associations/many_documents_proxy.rb +0 -115
- data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +0 -31
- data/lib/mongo_mapper/associations/many_embedded_proxy.rb +0 -54
- data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +0 -11
- data/lib/mongo_mapper/associations/one_proxy.rb +0 -64
- data/lib/mongo_mapper/associations/proxy.rb +0 -116
- data/lib/mongo_mapper/associations.rb +0 -78
- data/lib/mongo_mapper/callbacks.rb +0 -61
- data/lib/mongo_mapper/dirty.rb +0 -117
- data/lib/mongo_mapper/key.rb +0 -36
- data/lib/mongo_mapper/mongo_mapper.rb +0 -125
- data/lib/mongo_mapper/pagination.rb +0 -66
- data/lib/mongo_mapper/rails_compatibility/document.rb +0 -15
- data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +0 -28
- data/lib/mongo_mapper/serialization.rb +0 -54
- data/lib/mongo_mapper/serializers/json_serializer.rb +0 -48
- data/lib/mongo_mapper/validations.rb +0 -39
- data/test/functional/test_rails_compatibility.rb +0 -25
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2010.01.
|
1
|
+
2010.01.12
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module DescendantAppends
|
3
|
+
def included(model)
|
4
|
+
extra_extensions.each { |extension| model.extend(extension) }
|
5
|
+
extra_inclusions.each { |inclusion| model.send(:include, inclusion) }
|
6
|
+
descendants << model
|
7
|
+
end
|
8
|
+
|
9
|
+
# @api public
|
10
|
+
def descendants
|
11
|
+
@descendants ||= Set.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api public
|
15
|
+
def append_extensions(*extensions)
|
16
|
+
extra_extensions.concat extensions
|
17
|
+
|
18
|
+
# Add the extension to existing descendants
|
19
|
+
descendants.each do |model|
|
20
|
+
extensions.each { |extension| model.extend(extension) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @api public
|
25
|
+
def append_inclusions(*inclusions)
|
26
|
+
extra_inclusions.concat inclusions
|
27
|
+
|
28
|
+
# Add the inclusion to existing descendants
|
29
|
+
descendants.each do |model|
|
30
|
+
inclusions.each { |inclusion| model.send(:include, inclusion) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def extra_extensions
|
36
|
+
@extra_extensions ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
# @api private
|
40
|
+
def extra_inclusions
|
41
|
+
@extra_inclusions ||= []
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,66 +1,38 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
1
|
module MongoMapper
|
4
2
|
module Document
|
3
|
+
extend DescendantAppends
|
4
|
+
|
5
5
|
def self.included(model)
|
6
6
|
model.class_eval do
|
7
|
-
include EmbeddedDocument
|
8
7
|
include InstanceMethods
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
extend
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@descendants ||= Set.new
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.append_extensions(*extensions)
|
32
|
-
extra_extensions.concat extensions
|
33
|
-
|
34
|
-
# Add the extension to existing descendants
|
35
|
-
descendants.each do |model|
|
36
|
-
extensions.each { |extension| model.extend(extension) }
|
8
|
+
extend ClassMethods
|
9
|
+
extend Finders
|
10
|
+
|
11
|
+
extend Plugins
|
12
|
+
plugin Plugins::Associations
|
13
|
+
plugin Plugins::Clone
|
14
|
+
plugin Plugins::Descendants
|
15
|
+
plugin Plugins::Equality
|
16
|
+
plugin Plugins::Inspect
|
17
|
+
plugin Plugins::Keys
|
18
|
+
plugin Plugins::Dirty # for now dirty needs to be after keys
|
19
|
+
plugin Plugins::Logger
|
20
|
+
plugin Plugins::Pagination
|
21
|
+
plugin Plugins::Rails
|
22
|
+
plugin Plugins::Serialization
|
23
|
+
plugin Plugins::Validations
|
24
|
+
plugin Plugins::Callbacks # for now callbacks needs to be after validations
|
25
|
+
|
26
|
+
extend Plugins::Validations::DocumentMacros
|
37
27
|
end
|
38
|
-
|
39
|
-
|
40
|
-
# @api private
|
41
|
-
def self.extra_extensions
|
42
|
-
@extra_extensions ||= []
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.append_inclusions(*inclusions)
|
46
|
-
extra_inclusions.concat inclusions
|
47
|
-
|
48
|
-
# Add the inclusion to existing descendants
|
49
|
-
descendants.each do |model|
|
50
|
-
inclusions.each { |inclusion| model.send :include, inclusion }
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# @api private
|
55
|
-
def self.extra_inclusions
|
56
|
-
@extra_inclusions ||= []
|
28
|
+
|
29
|
+
super
|
57
30
|
end
|
58
31
|
|
59
32
|
module ClassMethods
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
key
|
33
|
+
def inherited(subclass)
|
34
|
+
subclass.set_collection_name(collection_name)
|
35
|
+
super
|
64
36
|
end
|
65
37
|
|
66
38
|
def ensure_index(name_or_array, options={})
|
@@ -98,17 +70,6 @@ module MongoMapper
|
|
98
70
|
nil
|
99
71
|
end
|
100
72
|
|
101
|
-
def paginate(options)
|
102
|
-
per_page = options.delete(:per_page) || self.per_page
|
103
|
-
page = options.delete(:page)
|
104
|
-
total_entries = count(options)
|
105
|
-
pagination = Pagination::PaginationProxy.new(total_entries, page, per_page)
|
106
|
-
|
107
|
-
options.merge!(:limit => pagination.limit, :skip => pagination.skip)
|
108
|
-
pagination.subject = find_every(options)
|
109
|
-
pagination
|
110
|
-
end
|
111
|
-
|
112
73
|
def first(options={})
|
113
74
|
find_one(options)
|
114
75
|
end
|
@@ -204,6 +165,10 @@ module MongoMapper
|
|
204
165
|
modifier_update('$pullAll', args)
|
205
166
|
end
|
206
167
|
|
168
|
+
def pop(*args)
|
169
|
+
modifier_update('$pop', args)
|
170
|
+
end
|
171
|
+
|
207
172
|
def modifier_update(modifier, args)
|
208
173
|
criteria, keys = criteria_and_keys_from_args(args)
|
209
174
|
modifiers = {modifier => keys}
|
@@ -218,6 +183,10 @@ module MongoMapper
|
|
218
183
|
end
|
219
184
|
private :criteria_and_keys_from_args
|
220
185
|
|
186
|
+
def embeddable?
|
187
|
+
false
|
188
|
+
end
|
189
|
+
|
221
190
|
def connection(mongo_connection=nil)
|
222
191
|
if mongo_connection.nil?
|
223
192
|
@connection ||= MongoMapper.connection
|
@@ -269,23 +238,19 @@ module MongoMapper
|
|
269
238
|
end
|
270
239
|
|
271
240
|
def single_collection_inherited?
|
272
|
-
keys.
|
241
|
+
keys.key?(:_type) && single_collection_inherited_superclass?
|
273
242
|
end
|
274
243
|
|
275
244
|
def single_collection_inherited_superclass?
|
276
|
-
superclass.respond_to?(:keys) && superclass.keys.
|
245
|
+
superclass.respond_to?(:keys) && superclass.keys.key?(:_type)
|
277
246
|
end
|
278
247
|
|
279
248
|
private
|
280
|
-
def create_indexes_for(key)
|
281
|
-
ensure_index key.name if key.options[:index]
|
282
|
-
end
|
283
|
-
|
284
249
|
def initialize_each(*docs)
|
285
250
|
instances = []
|
286
251
|
docs = [{}] if docs.blank?
|
287
252
|
docs.flatten.each do |attrs|
|
288
|
-
doc =
|
253
|
+
doc = new(attrs)
|
289
254
|
yield(doc)
|
290
255
|
instances << doc
|
291
256
|
end
|
@@ -295,7 +260,7 @@ module MongoMapper
|
|
295
260
|
def find_every(options)
|
296
261
|
criteria, options = to_finder_options(options)
|
297
262
|
collection.find(criteria, options).to_a.map do |doc|
|
298
|
-
|
263
|
+
load(doc)
|
299
264
|
end
|
300
265
|
end
|
301
266
|
|
@@ -313,7 +278,7 @@ module MongoMapper
|
|
313
278
|
def find_one(options={})
|
314
279
|
criteria, options = to_finder_options(options)
|
315
280
|
if doc = collection.find_one(criteria, options)
|
316
|
-
|
281
|
+
load(doc)
|
317
282
|
end
|
318
283
|
end
|
319
284
|
|
@@ -366,20 +331,12 @@ module MongoMapper
|
|
366
331
|
def collection
|
367
332
|
self.class.collection
|
368
333
|
end
|
369
|
-
|
334
|
+
|
370
335
|
def database
|
371
336
|
self.class.database
|
372
337
|
end
|
373
338
|
|
374
|
-
def new?
|
375
|
-
read_attribute('_id').blank? || using_custom_id?
|
376
|
-
end
|
377
|
-
|
378
339
|
def save(options={})
|
379
|
-
if options === false
|
380
|
-
ActiveSupport::Deprecation.warn "save with true/false is deprecated. You should now use :validate => true/false."
|
381
|
-
options = {:validate => false}
|
382
|
-
end
|
383
340
|
options.reverse_merge!(:validate => true)
|
384
341
|
perform_validations = options.delete(:validate)
|
385
342
|
!perform_validations || valid? ? create_or_update(options) : false
|
@@ -388,9 +345,19 @@ module MongoMapper
|
|
388
345
|
def save!
|
389
346
|
save || raise(DocumentNotValid.new(self))
|
390
347
|
end
|
348
|
+
|
349
|
+
def update_attributes(attrs={})
|
350
|
+
self.attributes = attrs
|
351
|
+
save
|
352
|
+
end
|
353
|
+
|
354
|
+
def update_attributes!(attrs={})
|
355
|
+
self.attributes = attrs
|
356
|
+
save!
|
357
|
+
end
|
391
358
|
|
392
359
|
def destroy
|
393
|
-
|
360
|
+
delete
|
394
361
|
end
|
395
362
|
|
396
363
|
def delete
|
@@ -411,34 +378,23 @@ module MongoMapper
|
|
411
378
|
end
|
412
379
|
|
413
380
|
def create(options={})
|
414
|
-
assign_id
|
415
381
|
save_to_collection(options)
|
416
382
|
end
|
417
383
|
|
418
|
-
def assign_id
|
419
|
-
if read_attribute(:_id).blank?
|
420
|
-
write_attribute :_id, Mongo::ObjectID.new
|
421
|
-
end
|
422
|
-
end
|
423
|
-
|
424
384
|
def update(options={})
|
425
385
|
save_to_collection(options)
|
426
386
|
end
|
427
387
|
|
428
388
|
def save_to_collection(options={})
|
429
|
-
clear_custom_id_flag
|
430
389
|
safe = options.delete(:safe) || false
|
390
|
+
@new = false
|
431
391
|
collection.save(to_mongo, :safe => safe)
|
432
392
|
end
|
433
393
|
|
434
394
|
def update_timestamps
|
435
395
|
now = Time.now.utc
|
436
|
-
|
437
|
-
|
438
|
-
end
|
439
|
-
|
440
|
-
def clear_custom_id_flag
|
441
|
-
@using_custom_id = nil
|
396
|
+
self[:created_at] = now if new? && !created_at?
|
397
|
+
self[:updated_at] = now
|
442
398
|
end
|
443
399
|
end
|
444
400
|
end # Document
|
@@ -1,380 +1,60 @@
|
|
1
1
|
module MongoMapper
|
2
2
|
module EmbeddedDocument
|
3
|
+
extend DescendantAppends
|
4
|
+
|
3
5
|
def self.included(model)
|
4
6
|
model.class_eval do
|
5
|
-
extend ClassMethods
|
6
7
|
include InstanceMethods
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
extend ClassMethods
|
9
|
+
|
10
|
+
extend Plugins
|
11
|
+
plugin Plugins::Associations
|
12
|
+
plugin Plugins::Clone
|
13
|
+
plugin Plugins::Descendants
|
14
|
+
plugin Plugins::Equality
|
15
|
+
plugin Plugins::Inspect
|
16
|
+
plugin Plugins::Keys
|
17
|
+
plugin Plugins::Logger
|
18
|
+
plugin Plugins::Rails
|
19
|
+
plugin Plugins::Serialization
|
20
|
+
plugin Plugins::Validations
|
14
21
|
|
15
|
-
extend Validations::Macros
|
16
|
-
|
17
|
-
key :_id, ObjectId
|
18
22
|
attr_accessor :_root_document
|
19
23
|
end
|
24
|
+
|
25
|
+
super
|
20
26
|
end
|
21
27
|
|
22
28
|
module ClassMethods
|
23
|
-
def logger
|
24
|
-
MongoMapper.logger
|
25
|
-
end
|
26
|
-
|
27
|
-
def inherited(subclass)
|
28
|
-
unless subclass.embeddable?
|
29
|
-
subclass.set_collection_name(collection_name)
|
30
|
-
end
|
31
|
-
|
32
|
-
(@subclasses ||= []) << subclass
|
33
|
-
end
|
34
|
-
|
35
|
-
def subclasses
|
36
|
-
@subclasses
|
37
|
-
end
|
38
|
-
|
39
|
-
def keys
|
40
|
-
@keys ||= if parent = parent_model
|
41
|
-
parent.keys.dup
|
42
|
-
else
|
43
|
-
HashWithIndifferentAccess.new
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def key(*args)
|
48
|
-
key = Key.new(*args)
|
49
|
-
keys[key.name] = key
|
50
|
-
|
51
|
-
create_accessors_for(key)
|
52
|
-
create_key_in_subclasses(*args)
|
53
|
-
create_validations_for(key)
|
54
|
-
|
55
|
-
key
|
56
|
-
end
|
57
|
-
|
58
|
-
def using_object_id?
|
59
|
-
object_id_key?(:_id)
|
60
|
-
end
|
61
|
-
|
62
|
-
def object_id_key?(name)
|
63
|
-
key = keys[name.to_s]
|
64
|
-
key && key.type == ObjectId
|
65
|
-
end
|
66
|
-
|
67
29
|
def embeddable?
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
def parent_model
|
72
|
-
(ancestors - [self,EmbeddedDocument]).find do |parent_class|
|
73
|
-
parent_class.ancestors.include?(EmbeddedDocument)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def to_mongo(instance)
|
78
|
-
return nil if instance.nil?
|
79
|
-
instance.to_mongo
|
80
|
-
end
|
81
|
-
|
82
|
-
def from_mongo(value)
|
83
|
-
return nil if value.nil?
|
84
|
-
value.is_a?(self) ? value : initialize_doc(value)
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
def initialize_doc(doc)
|
89
|
-
begin
|
90
|
-
klass = doc['_type'].present? ? doc['_type'].constantize : self
|
91
|
-
klass.new(doc)
|
92
|
-
rescue NameError
|
93
|
-
new(doc)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def accessors_module
|
98
|
-
module_defined = if method(:const_defined?).arity == 1 # Ruby 1.9 compat check
|
99
|
-
const_defined?('MongoMapperKeys')
|
100
|
-
else
|
101
|
-
const_defined?('MongoMapperKeys', false)
|
102
|
-
end
|
103
|
-
|
104
|
-
if module_defined
|
105
|
-
const_get 'MongoMapperKeys'
|
106
|
-
else
|
107
|
-
const_set 'MongoMapperKeys', Module.new
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def create_accessors_for(key)
|
112
|
-
accessors_module.module_eval <<-end_eval
|
113
|
-
def #{key.name}
|
114
|
-
read_attribute(:'#{key.name}')
|
115
|
-
end
|
116
|
-
|
117
|
-
def #{key.name}_before_typecast
|
118
|
-
read_attribute_before_typecast(:'#{key.name}')
|
119
|
-
end
|
120
|
-
|
121
|
-
def #{key.name}=(value)
|
122
|
-
write_attribute(:'#{key.name}', value)
|
123
|
-
end
|
124
|
-
|
125
|
-
def #{key.name}?
|
126
|
-
read_attribute(:#{key.name}).present?
|
127
|
-
end
|
128
|
-
end_eval
|
129
|
-
include accessors_module
|
130
|
-
end
|
131
|
-
|
132
|
-
def create_key_in_subclasses(*args)
|
133
|
-
return if subclasses.blank?
|
134
|
-
|
135
|
-
subclasses.each do |subclass|
|
136
|
-
subclass.key(*args)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
def create_validations_for(key)
|
141
|
-
attribute = key.name.to_sym
|
142
|
-
|
143
|
-
if key.options[:required]
|
144
|
-
validates_presence_of(attribute)
|
145
|
-
end
|
146
|
-
|
147
|
-
if key.options[:unique]
|
148
|
-
validates_uniqueness_of(attribute)
|
149
|
-
end
|
150
|
-
|
151
|
-
if key.options[:numeric]
|
152
|
-
number_options = key.type == Integer ? {:only_integer => true} : {}
|
153
|
-
validates_numericality_of(attribute, number_options)
|
154
|
-
end
|
155
|
-
|
156
|
-
if key.options[:format]
|
157
|
-
validates_format_of(attribute, :with => key.options[:format])
|
158
|
-
end
|
159
|
-
|
160
|
-
if key.options[:length]
|
161
|
-
length_options = case key.options[:length]
|
162
|
-
when Integer
|
163
|
-
{:minimum => 0, :maximum => key.options[:length]}
|
164
|
-
when Range
|
165
|
-
{:within => key.options[:length]}
|
166
|
-
when Hash
|
167
|
-
key.options[:length]
|
168
|
-
end
|
169
|
-
validates_length_of(attribute, length_options)
|
170
|
-
end
|
30
|
+
true
|
171
31
|
end
|
172
32
|
end
|
173
33
|
|
174
34
|
module InstanceMethods
|
175
|
-
def initialize(attrs={})
|
176
|
-
unless attrs.nil?
|
177
|
-
associations.each do |name, association|
|
178
|
-
if collection = attrs.delete(name)
|
179
|
-
if association.many? && association.klass.embeddable?
|
180
|
-
root_document = attrs[:_root_document] || self
|
181
|
-
collection.each do |doc|
|
182
|
-
doc[:_root_document] = root_document
|
183
|
-
end
|
184
|
-
end
|
185
|
-
send("#{association.name}=", collection)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
self.attributes = attrs
|
190
|
-
|
191
|
-
if respond_to?(:_type=) && self['_type'].blank?
|
192
|
-
self._type = self.class.name
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
if self.class.embeddable?
|
197
|
-
if read_attribute(:_id).blank?
|
198
|
-
write_attribute :_id, Mongo::ObjectID.new
|
199
|
-
@new_document = true
|
200
|
-
else
|
201
|
-
@new_document = false
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
def new?
|
207
|
-
!!@new_document
|
208
|
-
end
|
209
|
-
|
210
|
-
def to_param
|
211
|
-
id.to_s
|
212
|
-
end
|
213
|
-
|
214
|
-
def attributes=(attrs)
|
215
|
-
return if attrs.blank?
|
216
|
-
attrs.each_pair do |name, value|
|
217
|
-
writer_method = "#{name}="
|
218
|
-
|
219
|
-
if respond_to?(writer_method)
|
220
|
-
self.send(writer_method, value)
|
221
|
-
else
|
222
|
-
self[name.to_s] = value
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def attributes
|
228
|
-
attrs = HashWithIndifferentAccess.new
|
229
|
-
|
230
|
-
embedded_keys.each do |key|
|
231
|
-
attrs[key.name] = read_attribute(key.name).try(:attributes)
|
232
|
-
end
|
233
|
-
|
234
|
-
non_embedded_keys.each do |key|
|
235
|
-
attrs[key.name] = read_attribute(key.name)
|
236
|
-
end
|
237
|
-
|
238
|
-
embedded_associations.each do |association|
|
239
|
-
documents = instance_variable_get(association.ivar)
|
240
|
-
next if documents.nil?
|
241
|
-
attrs[association.name] = documents.collect { |doc| doc.attributes }
|
242
|
-
end
|
243
|
-
|
244
|
-
attrs
|
245
|
-
end
|
246
|
-
|
247
|
-
def to_mongo
|
248
|
-
attrs = HashWithIndifferentAccess.new
|
249
|
-
|
250
|
-
_keys.each_pair do |name, key|
|
251
|
-
value = key.set(read_attribute(key.name))
|
252
|
-
attrs[name] = value unless value.nil?
|
253
|
-
end
|
254
|
-
|
255
|
-
embedded_associations.each do |association|
|
256
|
-
if documents = instance_variable_get(association.ivar)
|
257
|
-
attrs[association.name] = documents.map { |document| document.to_mongo }
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
attrs
|
262
|
-
end
|
263
|
-
|
264
|
-
def clone
|
265
|
-
clone_attributes = self.attributes
|
266
|
-
clone_attributes.delete("_id")
|
267
|
-
self.class.new(clone_attributes)
|
268
|
-
end
|
269
|
-
|
270
|
-
def [](name)
|
271
|
-
read_attribute(name)
|
272
|
-
end
|
273
|
-
|
274
|
-
def []=(name, value)
|
275
|
-
ensure_key_exists(name)
|
276
|
-
write_attribute(name, value)
|
277
|
-
end
|
278
|
-
|
279
|
-
def ==(other)
|
280
|
-
other.is_a?(self.class) && _id == other._id
|
281
|
-
end
|
282
|
-
|
283
|
-
def id
|
284
|
-
self[:_id]
|
285
|
-
end
|
286
|
-
|
287
|
-
def id=(value)
|
288
|
-
if self.class.using_object_id?
|
289
|
-
value = MongoMapper.normalize_object_id(value)
|
290
|
-
else
|
291
|
-
@using_custom_id = true
|
292
|
-
end
|
293
|
-
|
294
|
-
self[:_id] = value
|
295
|
-
end
|
296
|
-
|
297
|
-
def using_custom_id?
|
298
|
-
!!@using_custom_id
|
299
|
-
end
|
300
|
-
|
301
|
-
def inspect
|
302
|
-
attributes_as_nice_string = key_names.collect do |name|
|
303
|
-
"#{name}: #{read_attribute(name).inspect}"
|
304
|
-
end.join(", ")
|
305
|
-
"#<#{self.class} #{attributes_as_nice_string}>"
|
306
|
-
end
|
307
|
-
|
308
35
|
def save(options={})
|
309
|
-
_root_document.try(:save, options)
|
36
|
+
if result = _root_document.try(:save, options)
|
37
|
+
@new = false
|
38
|
+
end
|
39
|
+
result
|
310
40
|
end
|
311
41
|
|
312
42
|
def save!(options={})
|
313
|
-
_root_document.try(:save!, options)
|
43
|
+
if result = _root_document.try(:save!, options)
|
44
|
+
@new = false
|
45
|
+
end
|
46
|
+
result
|
314
47
|
end
|
315
48
|
|
316
49
|
def update_attributes(attrs={})
|
317
50
|
self.attributes = attrs
|
318
|
-
save
|
51
|
+
self.save
|
319
52
|
end
|
320
53
|
|
321
54
|
def update_attributes!(attrs={})
|
322
55
|
self.attributes = attrs
|
323
|
-
save!
|
56
|
+
self.save!
|
324
57
|
end
|
325
|
-
|
326
|
-
def logger
|
327
|
-
self.class.logger
|
328
|
-
end
|
329
|
-
|
330
|
-
private
|
331
|
-
def _keys
|
332
|
-
self.metaclass.keys
|
333
|
-
end
|
334
|
-
|
335
|
-
def key_names
|
336
|
-
_keys.keys
|
337
|
-
end
|
338
|
-
|
339
|
-
def non_embedded_keys
|
340
|
-
_keys.values.select { |key| !key.embeddable? }
|
341
|
-
end
|
342
|
-
|
343
|
-
def embedded_keys
|
344
|
-
_keys.values.select { |key| key.embeddable? }
|
345
|
-
end
|
346
|
-
|
347
|
-
def ensure_key_exists(name)
|
348
|
-
self.metaclass.key(name) unless respond_to?("#{name}=")
|
349
|
-
end
|
350
|
-
|
351
|
-
def read_attribute(name)
|
352
|
-
if key = _keys[name]
|
353
|
-
value = key.get(instance_variable_get("@#{name}"))
|
354
|
-
instance_variable_set "@#{name}", value
|
355
|
-
value
|
356
|
-
else
|
357
|
-
raise KeyNotFound, "Could not find key: #{name.inspect}"
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
|
-
def read_attribute_before_typecast(name)
|
362
|
-
instance_variable_get("@#{name}_before_typecast")
|
363
|
-
end
|
364
|
-
|
365
|
-
def write_attribute(name, value)
|
366
|
-
key = _keys[name]
|
367
|
-
instance_variable_set "@#{name}_before_typecast", value
|
368
|
-
instance_variable_set "@#{name}", key.set(value)
|
369
|
-
end
|
370
|
-
|
371
|
-
def embedded_associations
|
372
|
-
associations.select do |name, association|
|
373
|
-
association.embeddable?
|
374
|
-
end.map do |name, association|
|
375
|
-
association
|
376
|
-
end
|
377
|
-
end
|
378
58
|
end # InstanceMethods
|
379
59
|
end # EmbeddedDocument
|
380
60
|
end # MongoMapper
|