mongo_mapper-unstable 2010.1.6 → 2010.1.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/VERSION +1 -1
  2. data/lib/mongo_mapper/descendant_appends.rb +44 -0
  3. data/lib/mongo_mapper/document.rb +54 -98
  4. data/lib/mongo_mapper/embedded_document.rb +28 -348
  5. data/lib/mongo_mapper/finder_options.rb +15 -33
  6. data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
  7. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +28 -0
  8. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +23 -0
  9. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  10. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +49 -0
  11. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  12. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  13. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  14. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  15. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  16. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  17. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +66 -0
  18. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  19. data/lib/mongo_mapper/plugins/associations.rb +104 -0
  20. data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
  21. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  22. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  23. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  24. data/lib/mongo_mapper/plugins/equality.rb +11 -0
  25. data/lib/mongo_mapper/plugins/identity_map.rb +66 -0
  26. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  27. data/lib/mongo_mapper/plugins/keys.rb +295 -0
  28. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  29. data/lib/mongo_mapper/plugins/pagination.rb +85 -0
  30. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  31. data/lib/mongo_mapper/plugins/serialization.rb +109 -0
  32. data/lib/mongo_mapper/plugins/validations.rb +48 -0
  33. data/lib/mongo_mapper/plugins.rb +19 -0
  34. data/lib/mongo_mapper/support.rb +36 -15
  35. data/lib/mongo_mapper.rb +23 -22
  36. data/performance/read_write.rb +52 -0
  37. data/specs.watchr +23 -2
  38. data/test/functional/associations/test_belongs_to_proxy.rb +1 -1
  39. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +58 -39
  40. data/test/functional/associations/test_many_embedded_proxy.rb +103 -69
  41. data/test/functional/test_dirty.rb +1 -1
  42. data/test/functional/test_document.rb +25 -25
  43. data/test/functional/test_embedded_document.rb +66 -63
  44. data/test/functional/test_identity_map.rb +233 -0
  45. data/test/functional/test_modifiers.rb +14 -0
  46. data/test/functional/test_string_id_compatibility.rb +4 -4
  47. data/test/functional/test_validations.rb +13 -0
  48. data/test/models.rb +0 -39
  49. data/test/test_helper.rb +8 -2
  50. data/test/unit/associations/test_base.rb +1 -1
  51. data/test/unit/associations/test_proxy.rb +3 -3
  52. data/test/unit/test_descendant_appends.rb +71 -0
  53. data/test/unit/test_document.rb +35 -46
  54. data/test/unit/test_embedded_document.rb +218 -271
  55. data/test/unit/{test_key.rb → test_keys.rb} +0 -0
  56. data/test/unit/test_pagination.rb +10 -2
  57. data/test/unit/test_plugins.rb +42 -0
  58. data/test/unit/test_rails.rb +123 -0
  59. data/test/unit/{test_serializations.rb → test_serialization.rb} +0 -0
  60. data/test/unit/test_support.rb +10 -6
  61. data/test/unit/test_time_zones.rb +2 -2
  62. metadata +44 -31
  63. data/lib/mongo_mapper/associations/base.rb +0 -119
  64. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +0 -26
  65. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +0 -21
  66. data/lib/mongo_mapper/associations/collection.rb +0 -19
  67. data/lib/mongo_mapper/associations/in_array_proxy.rb +0 -137
  68. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -26
  69. data/lib/mongo_mapper/associations/many_documents_proxy.rb +0 -115
  70. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +0 -31
  71. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +0 -54
  72. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +0 -11
  73. data/lib/mongo_mapper/associations/one_proxy.rb +0 -64
  74. data/lib/mongo_mapper/associations/proxy.rb +0 -116
  75. data/lib/mongo_mapper/associations.rb +0 -78
  76. data/lib/mongo_mapper/callbacks.rb +0 -61
  77. data/lib/mongo_mapper/dirty.rb +0 -117
  78. data/lib/mongo_mapper/key.rb +0 -36
  79. data/lib/mongo_mapper/mongo_mapper.rb +0 -125
  80. data/lib/mongo_mapper/pagination.rb +0 -66
  81. data/lib/mongo_mapper/rails_compatibility/document.rb +0 -15
  82. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +0 -28
  83. data/lib/mongo_mapper/serialization.rb +0 -54
  84. data/lib/mongo_mapper/serializers/json_serializer.rb +0 -48
  85. data/lib/mongo_mapper/validations.rb +0 -39
  86. data/test/functional/test_rails_compatibility.rb +0 -25
@@ -17,15 +17,17 @@ module MongoMapper
17
17
 
18
18
  def initialize(model, options)
19
19
  raise ArgumentError, "Options must be a hash" unless options.is_a?(Hash)
20
- options = options.symbolize_keys
21
20
 
22
21
  @model = model
23
22
  @options = {}
24
- @conditions = options.delete(:conditions) || {}
23
+ @conditions = {}
25
24
 
26
25
  options.each_pair do |key, value|
26
+ key = key.respond_to?(:to_sym) ? key.to_sym : key
27
27
  if OptionKeys.include?(key)
28
28
  @options[key] = value
29
+ elsif key == :conditions
30
+ @conditions.merge!(value)
29
31
  else
30
32
  @conditions[key] = value
31
33
  end
@@ -39,10 +41,10 @@ module MongoMapper
39
41
  end
40
42
 
41
43
  def options
42
- fields = @options.delete(:fields) || @options.delete(:select)
43
- skip = @options.delete(:skip) || @options.delete(:offset) || 0
44
- limit = @options.delete(:limit) || 0
45
- sort = @options.delete(:sort) || convert_order_to_sort(@options.delete(:order))
44
+ fields = @options[:fields] || @options[:select]
45
+ skip = @options[:skip] || @options[:offset] || 0
46
+ limit = @options[:limit] || 0
47
+ sort = @options[:sort] || convert_order_to_sort(@options[:order])
46
48
 
47
49
  {:fields => to_mongo_fields(fields), :skip => skip.to_i, :limit => limit.to_i, :sort => sort}
48
50
  end
@@ -62,8 +64,8 @@ module MongoMapper
62
64
  value = Mongo::ObjectID.from_string(value)
63
65
  end
64
66
 
65
- if field.is_a?(FinderOperator)
66
- criteria.update(field.to_criteria(value))
67
+ if field.is_a?(SymbolOperator)
68
+ criteria.update(field.to_mm_criteria(value))
67
69
  next
68
70
  end
69
71
 
@@ -106,10 +108,10 @@ module MongoMapper
106
108
  def convert_order_to_sort(sort)
107
109
  return if sort.blank?
108
110
 
109
- if sort.respond_to?(:all?) && sort.all? { |s| s.respond_to?(:to_order) }
110
- sort.map { |s| s.to_order }
111
- elsif sort.respond_to?(:to_order)
112
- [sort.to_order]
111
+ if sort.respond_to?(:all?) && sort.all? { |s| s.respond_to?(:to_mm_order) }
112
+ sort.map { |s| s.to_mm_order }
113
+ elsif sort.respond_to?(:to_mm_order)
114
+ [sort.to_mm_order]
113
115
  else
114
116
  pieces = sort.split(',')
115
117
  pieces.map { |s| to_mongo_sort_piece(s) }
@@ -122,24 +124,4 @@ module MongoMapper
122
124
  [field, direction]
123
125
  end
124
126
  end
125
-
126
- class FinderOperator
127
- def initialize(field, operator)
128
- @field, @operator = field, operator
129
- end
130
-
131
- def to_criteria(value)
132
- {FinderOptions.normalized_field(@field) => {@operator => value}}
133
- end
134
- end
135
-
136
- class OrderOperator
137
- def initialize(field, direction)
138
- @field, @direction = field, direction
139
- end
140
-
141
- def to_order
142
- [@field.to_s, FinderOptions.normalized_order_direction(@direction)]
143
- end
144
- end
145
- end
127
+ end
@@ -0,0 +1,121 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class Base
5
+ attr_reader :type, :name, :options, :finder_options
6
+
7
+ # Options that should not be considered MongoDB query options/criteria
8
+ AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic]
9
+
10
+ def initialize(type, name, options={}, &extension)
11
+ @type, @name, @options, @finder_options = type, name, {}, {}
12
+ options.symbolize_keys!
13
+
14
+ options[:extend] = modulized_extensions(extension, options[:extend])
15
+
16
+ options.each_pair do |key, value|
17
+ if AssociationOptions.include?(key)
18
+ @options[key] = value
19
+ else
20
+ @finder_options[key] = value
21
+ end
22
+ end
23
+ end
24
+
25
+ def class_name
26
+ @class_name ||= begin
27
+ if cn = options[:class_name]
28
+ cn
29
+ elsif many?
30
+ name.to_s.singularize.camelize
31
+ else
32
+ name.to_s.camelize
33
+ end
34
+ end
35
+ end
36
+
37
+ def klass
38
+ @klass ||= options[:class] || class_name.constantize
39
+ end
40
+
41
+ def many?
42
+ @many_type ||= @type == :many
43
+ end
44
+
45
+ def belongs_to?
46
+ @belongs_to_type ||= @type == :belongs_to
47
+ end
48
+
49
+ def one?
50
+ @one_type ||= @type == :one
51
+ end
52
+
53
+ def polymorphic?
54
+ !!@options[:polymorphic]
55
+ end
56
+
57
+ def as?
58
+ !!@options[:as]
59
+ end
60
+
61
+ def in_array?
62
+ !!@options[:in]
63
+ end
64
+
65
+ def embeddable?
66
+ many? && klass.embeddable?
67
+ end
68
+
69
+ def type_key_name
70
+ @type_key_name ||= many? ? '_type' : "#{as}_type"
71
+ end
72
+
73
+ def as
74
+ @options[:as] || self.name
75
+ end
76
+
77
+ def foreign_key
78
+ @options[:foreign_key] || "#{name}_id"
79
+ end
80
+
81
+ def ivar
82
+ @ivar ||= "@_#{name}"
83
+ end
84
+
85
+ def proxy_class
86
+ @proxy_class ||= begin
87
+ if many?
88
+ if self.klass.embeddable?
89
+ polymorphic? ? ManyEmbeddedPolymorphicProxy : ManyEmbeddedProxy
90
+ else
91
+ if polymorphic?
92
+ ManyPolymorphicProxy
93
+ elsif as?
94
+ ManyDocumentsAsProxy
95
+ elsif in_array?
96
+ InArrayProxy
97
+ else
98
+ ManyDocumentsProxy
99
+ end
100
+ end
101
+ elsif one?
102
+ OneProxy
103
+ else
104
+ polymorphic? ? BelongsToPolymorphicProxy : BelongsToProxy
105
+ end
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ # @param [Array<Module, Proc>] extensions a collection of Modules or
112
+ # Procs that extend the behaviour of this association.
113
+ def modulized_extensions(*extensions)
114
+ extensions.flatten.compact.map do |extension|
115
+ Proc === extension ? Module.new(&extension) : extension
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,28 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class BelongsToPolymorphicProxy < Proxy
5
+ def replace(doc)
6
+ if doc
7
+ doc.save if doc.new?
8
+ id, type = doc.id, doc.class.name
9
+ end
10
+
11
+ owner[reflection.foreign_key] = id
12
+ owner[reflection.type_key_name] = type
13
+ reset
14
+ end
15
+
16
+ protected
17
+ def find_target
18
+ return nil if association_class.nil? || owner[reflection.foreign_key].nil?
19
+ association_class.first(:id => owner[reflection.foreign_key])
20
+ end
21
+
22
+ def association_class
23
+ proxy_owner[reflection.type_key_name] ? proxy_owner[reflection.type_key_name].constantize : nil
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class BelongsToProxy < Proxy
5
+ def replace(doc)
6
+ if doc
7
+ doc.save if doc.new?
8
+ id = doc.id
9
+ end
10
+
11
+ owner[reflection.foreign_key] = id
12
+ reset
13
+ end
14
+
15
+ protected
16
+ def find_target
17
+ return nil if owner[reflection.foreign_key].nil?
18
+ klass.first(:id => owner[reflection.foreign_key])
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class Collection < Proxy
5
+ def to_ary
6
+ load_target
7
+ if target.is_a?(Array)
8
+ target.to_ary
9
+ else
10
+ Array(target)
11
+ end
12
+ end
13
+
14
+ def reset
15
+ super
16
+ target = []
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class EmbeddedCollection < Collection
5
+ def build(attributes={})
6
+ doc = klass.new(attributes)
7
+ assign_root_document(doc)
8
+ self << doc
9
+ doc
10
+ end
11
+
12
+ def find(id)
13
+ load_target
14
+ target.detect { |item| item.id.to_s == id || item.id == id }
15
+ end
16
+
17
+ def count
18
+ load_target
19
+ target.size
20
+ end
21
+
22
+ def <<(*docs)
23
+ load_target
24
+ docs.each do |doc|
25
+ assign_root_document(doc)
26
+ target << doc
27
+ end
28
+ end
29
+ alias_method :push, :<<
30
+ alias_method :concat, :<<
31
+
32
+ private
33
+ def _root_document
34
+ if owner.respond_to?(:_root_document)
35
+ owner._root_document
36
+ else
37
+ owner
38
+ end
39
+ end
40
+
41
+ def assign_root_document(*docs)
42
+ docs.each do |doc|
43
+ doc._root_document = _root_document
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,139 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class InArrayProxy < Collection
5
+ include ::MongoMapper::Finders
6
+
7
+ def find(*args)
8
+ options = args.extract_options!
9
+
10
+ case args.first
11
+ when :first
12
+ first(options)
13
+ when :last
14
+ last(options)
15
+ when :all
16
+ all(options)
17
+ else
18
+ klass.find(*scoped_ids(args) << scoped_options(options))
19
+ end
20
+ end
21
+
22
+ def find!(*args)
23
+ options = args.extract_options!
24
+
25
+ case args.first
26
+ when :first
27
+ first(options)
28
+ when :last
29
+ last(options)
30
+ when :all
31
+ all(options)
32
+ else
33
+ klass.find!(*scoped_ids(args) << scoped_options(options))
34
+ end
35
+ end
36
+
37
+ def paginate(options)
38
+ klass.paginate(scoped_options(options))
39
+ end
40
+
41
+ def all(options={})
42
+ klass.all(scoped_options(options))
43
+ end
44
+
45
+ def first(options={})
46
+ klass.first(scoped_options(options))
47
+ end
48
+
49
+ def last(options={})
50
+ klass.last(scoped_options(options))
51
+ end
52
+
53
+ def count(options={})
54
+ options.blank? ? ids.size : klass.count(scoped_options(options))
55
+ end
56
+
57
+ def destroy_all(options={})
58
+ all(options).each do |doc|
59
+ ids.delete(doc.id)
60
+ doc.destroy
61
+ end
62
+ reset
63
+ end
64
+
65
+ def delete_all(options={})
66
+ docs = all(options.merge(:select => ['_id']))
67
+ docs.each { |doc| ids.delete(doc.id) }
68
+ klass.delete(docs.map(&:id))
69
+ reset
70
+ end
71
+
72
+ def nullify
73
+ replace([])
74
+ reset
75
+ end
76
+
77
+ def create(attrs={})
78
+ doc = klass.create(attrs)
79
+ unless doc.new?
80
+ ids << doc.id
81
+ owner.save
82
+ end
83
+ doc
84
+ end
85
+
86
+ def create!(attrs={})
87
+ doc = klass.create!(attrs)
88
+ unless doc.new?
89
+ ids << doc.id
90
+ owner.save
91
+ end
92
+ doc
93
+ end
94
+
95
+ def <<(*docs)
96
+ flatten_deeper(docs).each do |doc|
97
+ doc.save if doc.new?
98
+ unless ids.include?(doc.id)
99
+ ids << doc.id
100
+ end
101
+ end
102
+ reset
103
+ end
104
+ alias_method :push, :<<
105
+ alias_method :concat, :<<
106
+
107
+ def replace(docs)
108
+ doc_ids = docs.map do |doc|
109
+ doc.save if doc.new?
110
+ doc.id
111
+ end
112
+ ids.replace(doc_ids.uniq)
113
+ reset
114
+ end
115
+
116
+ private
117
+ def scoped_conditions
118
+ {:_id => ids}
119
+ end
120
+
121
+ def scoped_options(options)
122
+ reflection.finder_options.merge(options).merge(scoped_conditions)
123
+ end
124
+
125
+ def scoped_ids(args)
126
+ args.flatten.reject { |id| !ids.include?(id) }
127
+ end
128
+
129
+ def find_target
130
+ ids.blank? ? [] : all
131
+ end
132
+
133
+ def ids
134
+ owner[options[:in]]
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,28 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyDocumentsAsProxy < ManyDocumentsProxy
5
+ protected
6
+ def scoped_conditions
7
+ {type_key_name => owner.class.name, id_key_name => owner.id}
8
+ end
9
+
10
+ def apply_scope(doc)
11
+ ensure_owner_saved
12
+ doc[type_key_name] = owner.class.name
13
+ doc[id_key_name] = owner.id
14
+ doc
15
+ end
16
+
17
+ private
18
+ def type_key_name
19
+ "#{options[:as]}_type"
20
+ end
21
+
22
+ def id_key_name
23
+ "#{options[:as]}_id"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,117 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyDocumentsProxy < Collection
5
+ include ::MongoMapper::Finders
6
+
7
+ def find(*args)
8
+ options = args.extract_options!
9
+ klass.find(*args << scoped_options(options))
10
+ end
11
+
12
+ def find!(*args)
13
+ options = args.extract_options!
14
+ klass.find!(*args << scoped_options(options))
15
+ end
16
+
17
+ def paginate(options)
18
+ klass.paginate(scoped_options(options))
19
+ end
20
+
21
+ def all(options={})
22
+ klass.all(scoped_options(options))
23
+ end
24
+
25
+ def first(options={})
26
+ klass.first(scoped_options(options))
27
+ end
28
+
29
+ def last(options={})
30
+ klass.last(scoped_options(options))
31
+ end
32
+
33
+ def count(options={})
34
+ klass.count(scoped_options(options))
35
+ end
36
+
37
+ def replace(docs)
38
+ load_target
39
+ target.map(&:destroy)
40
+ docs.each { |doc| apply_scope(doc).save }
41
+ reset
42
+ end
43
+
44
+ def <<(*docs)
45
+ ensure_owner_saved
46
+ flatten_deeper(docs).each { |doc| apply_scope(doc).save }
47
+ reset
48
+ end
49
+ alias_method :push, :<<
50
+ alias_method :concat, :<<
51
+
52
+ def build(attrs={})
53
+ doc = klass.new(attrs)
54
+ apply_scope(doc)
55
+ doc
56
+ end
57
+
58
+ def create(attrs={})
59
+ doc = klass.new(attrs)
60
+ apply_scope(doc).save
61
+ doc
62
+ end
63
+
64
+ def create!(attrs={})
65
+ doc = klass.new(attrs)
66
+ apply_scope(doc).save!
67
+ doc
68
+ end
69
+
70
+ def destroy_all(options={})
71
+ all(options).map(&:destroy)
72
+ reset
73
+ end
74
+
75
+ def delete_all(options={})
76
+ klass.delete_all(options.merge(scoped_conditions))
77
+ reset
78
+ end
79
+
80
+ def nullify
81
+ criteria = FinderOptions.new(klass, scoped_conditions).criteria
82
+ all(criteria).each do |doc|
83
+ doc.update_attributes(self.foreign_key => nil)
84
+ end
85
+ reset
86
+ end
87
+
88
+ protected
89
+ def scoped_conditions
90
+ {self.foreign_key => owner.id}
91
+ end
92
+
93
+ def scoped_options(options)
94
+ reflection.finder_options.merge(options).merge(scoped_conditions)
95
+ end
96
+
97
+ def find_target
98
+ all
99
+ end
100
+
101
+ def ensure_owner_saved
102
+ owner.save if owner.new?
103
+ end
104
+
105
+ def apply_scope(doc)
106
+ ensure_owner_saved
107
+ doc[foreign_key] = owner.id
108
+ doc
109
+ end
110
+
111
+ def foreign_key
112
+ options[:foreign_key] || owner.class.name.underscore.gsub("/", "_") + "_id"
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,31 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyEmbeddedPolymorphicProxy < EmbeddedCollection
5
+ def replace(values)
6
+ @_values = values.map do |v|
7
+ v.respond_to?(:attributes) ? v.attributes.merge(reflection.type_key_name => v.class.name) : v
8
+ end
9
+ reset
10
+ end
11
+
12
+ protected
13
+ def find_target
14
+ (@_values || []).map do |hash|
15
+ child = polymorphic_class(hash).new(hash)
16
+ assign_root_document(child)
17
+ child
18
+ end
19
+ end
20
+
21
+ def polymorphic_class(doc)
22
+ if class_name = doc[reflection.type_key_name]
23
+ class_name.constantize
24
+ else
25
+ klass
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyEmbeddedProxy < EmbeddedCollection
5
+ def replace(values)
6
+ @_values = values.map do |v|
7
+ v.respond_to?(:attributes) ? v.attributes : v
8
+ end
9
+ reset
10
+ end
11
+
12
+ private
13
+ def find_target
14
+ (@_values || []).map do |v|
15
+ child = klass.new(v)
16
+ assign_root_document(child)
17
+ child
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyPolymorphicProxy < ManyDocumentsProxy
5
+ private
6
+ def apply_scope(doc)
7
+ doc[reflection.type_key_name] = doc.class.name
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end