mongoid 3.0.0.rc → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +109 -4
- data/README.md +1 -1
- data/Rakefile +1 -0
- data/lib/config/locales/en.yml +15 -1
- data/lib/mongoid.rb +17 -2
- data/lib/mongoid/atomic.rb +54 -7
- data/lib/mongoid/attributes.rb +1 -1
- data/lib/mongoid/attributes/processing.rb +1 -1
- data/lib/mongoid/callbacks.rb +6 -1
- data/lib/mongoid/components.rb +2 -1
- data/lib/mongoid/config.rb +42 -17
- data/lib/mongoid/config/environment.rb +3 -1
- data/lib/mongoid/contextual/aggregable/memory.rb +21 -10
- data/lib/mongoid/contextual/find_and_modify.rb +14 -12
- data/lib/mongoid/contextual/memory.rb +24 -1
- data/lib/mongoid/contextual/mongo.rb +148 -29
- data/lib/mongoid/copyable.rb +6 -24
- data/lib/mongoid/criteria.rb +116 -34
- data/lib/mongoid/document.rb +7 -7
- data/lib/mongoid/errors.rb +1 -0
- data/lib/mongoid/errors/no_metadata.rb +21 -0
- data/lib/mongoid/evolvable.rb +19 -0
- data/lib/mongoid/extensions.rb +1 -1
- data/lib/mongoid/extensions/array.rb +38 -1
- data/lib/mongoid/extensions/big_decimal.rb +1 -1
- data/lib/mongoid/extensions/date_time.rb +6 -1
- data/lib/mongoid/extensions/false_class.rb +12 -0
- data/lib/mongoid/extensions/float.rb +12 -0
- data/lib/mongoid/extensions/hash.rb +33 -1
- data/lib/mongoid/extensions/integer.rb +12 -0
- data/lib/mongoid/extensions/object.rb +51 -1
- data/lib/mongoid/extensions/object_id.rb +2 -1
- data/lib/mongoid/extensions/range.rb +24 -0
- data/lib/mongoid/extensions/string.rb +31 -5
- data/lib/mongoid/extensions/true_class.rb +12 -0
- data/lib/mongoid/fields.rb +20 -21
- data/lib/mongoid/fields/foreign_key.rb +23 -7
- data/lib/mongoid/fields/standard.rb +3 -3
- data/lib/mongoid/finders.rb +3 -7
- data/lib/mongoid/hierarchy.rb +19 -1
- data/lib/mongoid/identity_map.rb +20 -4
- data/lib/mongoid/indexes/validators/options.rb +1 -1
- data/lib/mongoid/multi_parameter_attributes.rb +1 -1
- data/lib/mongoid/paranoia.rb +3 -32
- data/lib/mongoid/persistence.rb +33 -15
- data/lib/mongoid/persistence/atomic/operation.rb +1 -1
- data/lib/mongoid/persistence/operations.rb +16 -0
- data/lib/mongoid/persistence/operations/remove.rb +1 -1
- data/lib/mongoid/persistence/operations/upsert.rb +28 -0
- data/lib/mongoid/persistence/upsertion.rb +30 -0
- data/lib/mongoid/relations.rb +16 -0
- data/lib/mongoid/relations/accessors.rb +1 -1
- data/lib/mongoid/relations/bindings/referenced/in.rb +1 -1
- data/lib/mongoid/relations/builder.rb +1 -1
- data/lib/mongoid/relations/builders/nested_attributes/one.rb +1 -1
- data/lib/mongoid/relations/builders/referenced/many.rb +1 -1
- data/lib/mongoid/relations/cascading.rb +4 -3
- data/lib/mongoid/relations/constraint.rb +1 -1
- data/lib/mongoid/relations/conversions.rb +1 -1
- data/lib/mongoid/relations/embedded/batchable.rb +3 -2
- data/lib/mongoid/relations/embedded/many.rb +4 -4
- data/lib/mongoid/relations/embedded/one.rb +1 -1
- data/lib/mongoid/relations/metadata.rb +67 -23
- data/lib/mongoid/relations/nested_builder.rb +2 -2
- data/lib/mongoid/relations/proxy.rb +9 -7
- data/lib/mongoid/relations/referenced/many.rb +69 -25
- data/lib/mongoid/relations/referenced/many_to_many.rb +14 -13
- data/lib/mongoid/scoping.rb +0 -17
- data/lib/mongoid/serialization.rb +95 -26
- data/lib/mongoid/sessions.rb +30 -6
- data/lib/mongoid/sessions/factory.rb +2 -0
- data/lib/mongoid/threaded.rb +52 -0
- data/lib/mongoid/timestamps/created.rb +1 -1
- data/lib/mongoid/timestamps/updated.rb +2 -1
- data/lib/mongoid/validations/uniqueness.rb +3 -2
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +8 -0
- data/lib/rails/mongoid.rb +8 -5
- metadata +30 -13
- data/lib/mongoid/collections/retry.rb +0 -58
- data/lib/mongoid/javascript.rb +0 -20
- data/lib/mongoid/javascript/functions.yml +0 -63
@@ -8,11 +8,13 @@ module Mongoid
|
|
8
8
|
|
9
9
|
# Get the name of the environment that we are running under. This first
|
10
10
|
# looks for Rails, then Sinatra, then a RACK_ENV environment variable,
|
11
|
-
# and if none of those are found
|
11
|
+
# and if none of those are found raises an error.
|
12
12
|
#
|
13
13
|
# @example Get the env name.
|
14
14
|
# Environment.env_name
|
15
15
|
#
|
16
|
+
# @raise [ Errors::NoEnvironment ] If no environment was set.
|
17
|
+
#
|
16
18
|
# @return [ String ] The name of the current environment.
|
17
19
|
#
|
18
20
|
# @since 2.3.0
|
@@ -38,11 +38,7 @@ module Mongoid
|
|
38
38
|
#
|
39
39
|
# @since 3.0.0
|
40
40
|
def max(field = nil)
|
41
|
-
|
42
|
-
super()
|
43
|
-
else
|
44
|
-
count > 0 ? max_by { |doc| doc.send(field) }.send(field) : nil
|
45
|
-
end
|
41
|
+
block_given? ? super() : aggregate_by(field, :max_by)
|
46
42
|
end
|
47
43
|
|
48
44
|
# Get the min value of the provided field. If provided a block, will
|
@@ -64,11 +60,7 @@ module Mongoid
|
|
64
60
|
#
|
65
61
|
# @since 3.0.0
|
66
62
|
def min(field = nil)
|
67
|
-
|
68
|
-
super()
|
69
|
-
else
|
70
|
-
count > 0 ? min_by { |doc| doc.send(field) }.send(field) : nil
|
71
|
-
end
|
63
|
+
block_given? ? super() : aggregate_by(field, :min_by)
|
72
64
|
end
|
73
65
|
|
74
66
|
# Get the sum value of the provided field. If provided a block, will
|
@@ -92,6 +84,25 @@ module Mongoid
|
|
92
84
|
count > 0 ? super(0) { |doc| doc.send(field) } : nil
|
93
85
|
end
|
94
86
|
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Aggregate by the provided field and method.
|
91
|
+
#
|
92
|
+
# @api private
|
93
|
+
#
|
94
|
+
# @example Aggregate by the field and method.
|
95
|
+
# aggregable.aggregate_by(:name, :min_by)
|
96
|
+
#
|
97
|
+
# @param [ Symbol ] field The field to aggregate on.
|
98
|
+
# @param [ Symbol ] method The method (min_by or max_by).
|
99
|
+
#
|
100
|
+
# @return [ Integer ] The aggregate.
|
101
|
+
#
|
102
|
+
# @since 3.0.0
|
103
|
+
def aggregate_by(field, method)
|
104
|
+
count > 0 ? send(method) { |doc| doc.send(field) }.send(field) : nil
|
105
|
+
end
|
95
106
|
end
|
96
107
|
end
|
97
108
|
end
|
@@ -4,6 +4,12 @@ module Mongoid
|
|
4
4
|
class FindAndModify
|
5
5
|
include Command
|
6
6
|
|
7
|
+
# @attribute [r] criteria The criteria for the context.
|
8
|
+
# @attribute [r] options The command options.
|
9
|
+
# @attribute [r] update The updates.
|
10
|
+
# @attribute [r] query The Moped query.
|
11
|
+
attr_reader :criteria, :options, :update, :query
|
12
|
+
|
7
13
|
# Initialize the find and modify command, used for MongoDB's
|
8
14
|
# $findAndModify.
|
9
15
|
#
|
@@ -16,13 +22,12 @@ module Mongoid
|
|
16
22
|
#
|
17
23
|
# @option options [ true, false ] :new Return the updated document.
|
18
24
|
# @option options [ true, false ] :remove Delete the first document.
|
25
|
+
# @option options [ true, false ] :upsert Create the document if it doesn't exist.
|
19
26
|
#
|
20
27
|
# @since 3.0.0
|
21
28
|
def initialize(criteria, update, options = {})
|
22
|
-
@criteria = criteria
|
23
|
-
|
24
|
-
command[:update] = update unless options[:remove]
|
25
|
-
command.merge!(options)
|
29
|
+
@criteria, @options, @update = criteria, options, update
|
30
|
+
@query = criteria.klass.collection.find(criteria.selector)
|
26
31
|
apply_criteria_options
|
27
32
|
end
|
28
33
|
|
@@ -35,9 +40,7 @@ module Mongoid
|
|
35
40
|
#
|
36
41
|
# @since 3.0.0
|
37
42
|
def result
|
38
|
-
|
39
|
-
session.command(command)["value"]
|
40
|
-
end
|
43
|
+
query.modify(update, options)
|
41
44
|
end
|
42
45
|
|
43
46
|
private
|
@@ -53,12 +56,11 @@ module Mongoid
|
|
53
56
|
#
|
54
57
|
# @since 3.0.0
|
55
58
|
def apply_criteria_options
|
56
|
-
|
57
|
-
|
58
|
-
command[:sort] = sort
|
59
|
+
if spec = criteria.options[:sort]
|
60
|
+
query.sort(spec)
|
59
61
|
end
|
60
|
-
if
|
61
|
-
|
62
|
+
if spec = criteria.options[:fields]
|
63
|
+
query.select(spec)
|
62
64
|
end
|
63
65
|
end
|
64
66
|
end
|
@@ -345,6 +345,27 @@ module Mongoid
|
|
345
345
|
end
|
346
346
|
end
|
347
347
|
|
348
|
+
# Compare two values, checking for nil.
|
349
|
+
#
|
350
|
+
# @api private
|
351
|
+
#
|
352
|
+
# @example Compare the two objects.
|
353
|
+
# context.compare(a, b)
|
354
|
+
#
|
355
|
+
# @param [ Object ] a The first object.
|
356
|
+
# @param [ Object ] b The first object.
|
357
|
+
#
|
358
|
+
# @return [ Integer ] The comparison value.
|
359
|
+
#
|
360
|
+
# @since 3.0.0
|
361
|
+
def compare(a, b)
|
362
|
+
case
|
363
|
+
when a.nil? then b.nil? ? 0 : 1
|
364
|
+
when b.nil? then -1
|
365
|
+
else a <=> b
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
348
369
|
# Sort the documents in place.
|
349
370
|
#
|
350
371
|
# @example Sort the documents.
|
@@ -356,7 +377,9 @@ module Mongoid
|
|
356
377
|
def in_place_sort(values)
|
357
378
|
values.each_pair do |field, dir|
|
358
379
|
documents.sort! do |a, b|
|
359
|
-
|
380
|
+
a_value, b_value = a[field], b[field]
|
381
|
+
value = compare(a_value.__sortable__, b_value.__sortable__)
|
382
|
+
dir < 0 ? value * -1 : value
|
360
383
|
end
|
361
384
|
end
|
362
385
|
end
|
@@ -33,6 +33,18 @@ module Mongoid
|
|
33
33
|
end
|
34
34
|
alias :empty? :blank?
|
35
35
|
|
36
|
+
# Is the context cached?
|
37
|
+
#
|
38
|
+
# @example Is the context cached?
|
39
|
+
# context.cached?
|
40
|
+
#
|
41
|
+
# @return [ true, false ] If the context is cached.
|
42
|
+
#
|
43
|
+
# @since 3.0.0
|
44
|
+
def cached?
|
45
|
+
!!@cache
|
46
|
+
end
|
47
|
+
|
36
48
|
# Get the number of documents matching the query.
|
37
49
|
#
|
38
50
|
# @example Get the number of matching documents.
|
@@ -114,25 +126,15 @@ module Mongoid
|
|
114
126
|
# @return [ Enumerator ] The enumerator.
|
115
127
|
#
|
116
128
|
# @since 3.0.0
|
117
|
-
def each
|
129
|
+
def each(&block)
|
118
130
|
if block_given?
|
119
131
|
reset_length
|
120
132
|
selecting do
|
121
|
-
|
122
|
-
|
123
|
-
eager_load(docs)
|
124
|
-
docs.each do |doc|
|
125
|
-
yield doc
|
126
|
-
increment_length
|
127
|
-
end
|
128
|
-
docs
|
129
|
-
else
|
130
|
-
query.each do |doc|
|
131
|
-
yield Factory.from_db(klass, doc)
|
132
|
-
increment_length
|
133
|
-
end
|
134
|
-
self
|
133
|
+
documents_for_iteration.each do |doc|
|
134
|
+
yield_and_increment(doc, &block)
|
135
135
|
end
|
136
|
+
@cache_loaded = true
|
137
|
+
eager_loadable? ? docs : self
|
136
138
|
end
|
137
139
|
else
|
138
140
|
to_enum
|
@@ -174,6 +176,7 @@ module Mongoid
|
|
174
176
|
#
|
175
177
|
# @option options [ true, false ] :new Return the updated document.
|
176
178
|
# @option options [ true, false ] :remove Delete the first document.
|
179
|
+
# @option options [ true, false ] :upsert Create the document if it doesn't exist.
|
177
180
|
#
|
178
181
|
# @return [ Document ] The result of the command.
|
179
182
|
#
|
@@ -207,7 +210,7 @@ module Mongoid
|
|
207
210
|
#
|
208
211
|
# @since 3.0.0
|
209
212
|
def initialize(criteria)
|
210
|
-
@criteria, @klass = criteria, criteria.klass
|
213
|
+
@criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
|
211
214
|
add_type_selection
|
212
215
|
@query = klass.collection.find(criteria.selector)
|
213
216
|
apply_options
|
@@ -304,7 +307,7 @@ module Mongoid
|
|
304
307
|
# Update all the matching documents atomically.
|
305
308
|
#
|
306
309
|
# @example Update all the matching documents.
|
307
|
-
# context.update(name: "Smiths")
|
310
|
+
# context.update({ "$set" => { name: "Smiths" }})
|
308
311
|
#
|
309
312
|
# @param [ Hash ] attributes The new attributes for each document.
|
310
313
|
#
|
@@ -313,7 +316,7 @@ module Mongoid
|
|
313
316
|
# @since 3.0.0
|
314
317
|
def update(attributes = nil)
|
315
318
|
return false unless attributes
|
316
|
-
query.update_all(
|
319
|
+
query.update_all(attributes.__consolidate__)
|
317
320
|
end
|
318
321
|
alias :update_all :update
|
319
322
|
|
@@ -388,6 +391,18 @@ module Mongoid
|
|
388
391
|
end
|
389
392
|
end
|
390
393
|
|
394
|
+
# Apply the hint option
|
395
|
+
#
|
396
|
+
# @example Apply the hint params.
|
397
|
+
# context.apply_hint
|
398
|
+
#
|
399
|
+
# @since 3.0.0
|
400
|
+
def apply_hint
|
401
|
+
if spec = criteria.options[:hint]
|
402
|
+
query.hint(spec)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
391
406
|
# Map the inverse sort symbols to the correct MongoDB values.
|
392
407
|
#
|
393
408
|
# @example Apply the inverse sorting params.
|
@@ -402,6 +417,77 @@ module Mongoid
|
|
402
417
|
end
|
403
418
|
end
|
404
419
|
|
420
|
+
# Is the cache able to be added to?
|
421
|
+
#
|
422
|
+
# @api private
|
423
|
+
#
|
424
|
+
# @example Is the context cacheable?
|
425
|
+
# context.cacheable?
|
426
|
+
#
|
427
|
+
# @return [ true, false ] If caching, and the cache isn't loaded.
|
428
|
+
#
|
429
|
+
# @since 3.0.0
|
430
|
+
def cacheable?
|
431
|
+
cached? && !cache_loaded?
|
432
|
+
end
|
433
|
+
|
434
|
+
# Is the cache fully loaded? Will be true if caching after one full
|
435
|
+
# iteration.
|
436
|
+
#
|
437
|
+
# @api private
|
438
|
+
#
|
439
|
+
# @example Is the cache loaded?
|
440
|
+
# context.cache_loaded?
|
441
|
+
#
|
442
|
+
# @return [ true, false ] If the cache is loaded.
|
443
|
+
#
|
444
|
+
# @since 3.0.0
|
445
|
+
def cache_loaded?
|
446
|
+
!!@cache_loaded
|
447
|
+
end
|
448
|
+
|
449
|
+
# Get the documents for cached queries.
|
450
|
+
#
|
451
|
+
# @api private
|
452
|
+
#
|
453
|
+
# @example Get the cached documents.
|
454
|
+
# context.documents
|
455
|
+
#
|
456
|
+
# @return [ Array<Document> ] The documents.
|
457
|
+
#
|
458
|
+
# @since 3.0.0
|
459
|
+
def documents
|
460
|
+
@documents ||= []
|
461
|
+
end
|
462
|
+
|
463
|
+
# Get the documents the context should iterate. This follows 3 rules:
|
464
|
+
#
|
465
|
+
# 1. If the query is cached, and we already have documents loaded, use
|
466
|
+
# them.
|
467
|
+
# 2. If we are eager loading, then eager load the documents and use
|
468
|
+
# those.
|
469
|
+
# 3. Use the query.
|
470
|
+
#
|
471
|
+
# @api private
|
472
|
+
#
|
473
|
+
# @example Get the documents for iteration.
|
474
|
+
# context.documents_for_iteration
|
475
|
+
#
|
476
|
+
# @return [ Array<Document>, Moped::Query ] The docs to iterate.
|
477
|
+
#
|
478
|
+
# @since 3.0.0
|
479
|
+
def documents_for_iteration
|
480
|
+
if cached? && !documents.empty?
|
481
|
+
documents
|
482
|
+
elsif eager_loadable?
|
483
|
+
docs = query.map{ |doc| Factory.from_db(klass, doc) }
|
484
|
+
eager_load(docs)
|
485
|
+
docs
|
486
|
+
else
|
487
|
+
query
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
405
491
|
# Eager load the inclusions for the provided documents.
|
406
492
|
#
|
407
493
|
# @example Eager load the inclusions.
|
@@ -414,19 +500,32 @@ module Mongoid
|
|
414
500
|
# @since 3.0.0
|
415
501
|
def eager_load(docs)
|
416
502
|
criteria.inclusions.reject! do |metadata|
|
417
|
-
|
418
|
-
if metadata.stores_foreign_key?
|
419
|
-
child_ids = load_ids(metadata.foreign_key).flatten
|
420
|
-
metadata.eager_load(child_ids)
|
421
|
-
else
|
422
|
-
parent_ids = docs.map(&:id)
|
423
|
-
metadata.eager_load(parent_ids)
|
424
|
-
end
|
425
|
-
end
|
503
|
+
metadata.eager_load(eager_loaded_ids(docs, metadata)) if !docs.empty?
|
426
504
|
end
|
427
505
|
self.eager_loaded = true
|
428
506
|
end
|
429
507
|
|
508
|
+
# Get the ids that to be used to eager load documents.
|
509
|
+
#
|
510
|
+
# @api private
|
511
|
+
#
|
512
|
+
# @example Get the ids.
|
513
|
+
# context.eager_load(docs, metadata)
|
514
|
+
#
|
515
|
+
# @param [ Array<Document> ] docs The pre-loaded documents.
|
516
|
+
# @param [ Metadata ] metadata The relation metadata.
|
517
|
+
#
|
518
|
+
# @return [ Array<Object> ] The ids.
|
519
|
+
#
|
520
|
+
# @since 3.0.0
|
521
|
+
def eager_loaded_ids(docs, metadata)
|
522
|
+
if metadata.stores_foreign_key?
|
523
|
+
load_ids(metadata.foreign_key).flatten
|
524
|
+
else
|
525
|
+
docs.map(&:id)
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
430
529
|
# Is this context able to be eager loaded?
|
431
530
|
#
|
432
531
|
# @example Is the context eager loadable?
|
@@ -436,7 +535,7 @@ module Mongoid
|
|
436
535
|
#
|
437
536
|
# @since 3.0.0
|
438
537
|
def eager_loadable?
|
439
|
-
!eager_loaded && criteria.inclusions.
|
538
|
+
!eager_loaded && !criteria.inclusions.empty?
|
440
539
|
end
|
441
540
|
|
442
541
|
# Increment the length of the results.
|
@@ -475,7 +574,7 @@ module Mongoid
|
|
475
574
|
#
|
476
575
|
# @param [ String ] key The id or foriegn key string.
|
477
576
|
#
|
478
|
-
# @return [ Array<String, BSON::ObjectId> ] The ids to load.
|
577
|
+
# @return [ Array<String, Moped::BSON::ObjectId> ] The ids to load.
|
479
578
|
#
|
480
579
|
# @since 3.0.0
|
481
580
|
def load_ids(key)
|
@@ -495,6 +594,7 @@ module Mongoid
|
|
495
594
|
apply_limit
|
496
595
|
apply_skip
|
497
596
|
apply_sorting
|
597
|
+
apply_hint
|
498
598
|
end
|
499
599
|
|
500
600
|
# If we are limiting results, we need to set the field limitations on a
|
@@ -538,6 +638,25 @@ module Mongoid
|
|
538
638
|
doc
|
539
639
|
end
|
540
640
|
end
|
641
|
+
|
642
|
+
# Yield to the document and increment the length.
|
643
|
+
#
|
644
|
+
# @api private
|
645
|
+
#
|
646
|
+
# @example Yield and increment.
|
647
|
+
# context.yield_and_increment(doc) do |doc|
|
648
|
+
# ...
|
649
|
+
# end
|
650
|
+
#
|
651
|
+
# @param [ Document ] document The document to yield to.
|
652
|
+
#
|
653
|
+
# @since 3.0.0
|
654
|
+
def yield_and_increment(document, &block)
|
655
|
+
doc = document.respond_to?(:_id) ? document : Factory.from_db(klass, document)
|
656
|
+
yield(doc)
|
657
|
+
increment_length
|
658
|
+
documents.push(doc) if cacheable?
|
659
|
+
end
|
541
660
|
end
|
542
661
|
end
|
543
662
|
end
|
data/lib/mongoid/copyable.rb
CHANGED
@@ -5,15 +5,6 @@ module Mongoid
|
|
5
5
|
module Copyable
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
|
-
COPYABLES = [
|
9
|
-
:attributes,
|
10
|
-
:metadata,
|
11
|
-
:changed_attributes,
|
12
|
-
:previous_changes
|
13
|
-
]
|
14
|
-
|
15
|
-
protected
|
16
|
-
|
17
8
|
# Clone or dup the current +Document+. This will return all attributes with
|
18
9
|
# the exception of the document's id and versions, and will reset all the
|
19
10
|
# instance variables.
|
@@ -23,25 +14,16 @@ module Mongoid
|
|
23
14
|
# @example Clone the document.
|
24
15
|
# document.clone
|
25
16
|
#
|
26
|
-
# @example Dup the document.
|
27
|
-
# document.dup
|
28
|
-
#
|
29
17
|
# @param [ Document ] other The document getting cloned.
|
30
18
|
#
|
31
19
|
# @return [ Document ] The new document.
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
value = other.send(name)
|
37
|
-
instance_variable_set(:"@#{name}", value ? value.dup : nil)
|
38
|
-
end
|
39
|
-
attributes.delete("_id")
|
40
|
-
if attributes.delete("versions")
|
41
|
-
attributes["version"] = 1
|
20
|
+
def clone
|
21
|
+
attrs = as_document.except("_id")
|
22
|
+
if attrs.delete("versions")
|
23
|
+
attrs["version"] = 1
|
42
24
|
end
|
43
|
-
|
44
|
-
apply_defaults
|
25
|
+
self.class.new(attrs)
|
45
26
|
end
|
27
|
+
alias :dup :clone
|
46
28
|
end
|
47
29
|
end
|