mongo_mapper 0.8.6 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/UPGRADES +10 -0
- data/bin/mmconsole +0 -1
- data/examples/identity_map/automatic.rb +1 -7
- data/examples/plugins.rb +9 -9
- data/examples/safe.rb +43 -0
- data/lib/mongo_mapper.rb +46 -33
- data/lib/mongo_mapper/document.rb +33 -32
- data/lib/mongo_mapper/embedded_document.rb +22 -22
- data/lib/mongo_mapper/locale/en.yml +5 -0
- data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
- data/lib/mongo_mapper/plugins.rb +16 -3
- data/lib/mongo_mapper/plugins/accessible.rb +2 -0
- data/lib/mongo_mapper/plugins/active_model.rb +18 -0
- data/lib/mongo_mapper/plugins/associations.rb +37 -42
- data/lib/mongo_mapper/plugins/associations/base.rb +14 -50
- data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +58 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +6 -1
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +30 -2
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +4 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +12 -6
- data/lib/mongo_mapper/plugins/associations/many_association.rb +67 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +5 -5
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/one_association.rb +20 -0
- data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +5 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +7 -7
- data/lib/mongo_mapper/plugins/associations/proxy.rb +2 -2
- data/lib/mongo_mapper/plugins/caching.rb +3 -1
- data/lib/mongo_mapper/plugins/callbacks.rb +12 -221
- data/lib/mongo_mapper/plugins/clone.rb +3 -1
- data/lib/mongo_mapper/plugins/dirty.rb +38 -91
- data/lib/mongo_mapper/plugins/document.rb +4 -2
- data/lib/mongo_mapper/plugins/dynamic_querying.rb +2 -0
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +43 -0
- data/lib/mongo_mapper/plugins/embedded_document.rb +16 -9
- data/lib/mongo_mapper/plugins/equality.rb +2 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +4 -2
- data/lib/mongo_mapper/plugins/indexes.rb +2 -0
- data/lib/mongo_mapper/plugins/inspect.rb +3 -1
- data/lib/mongo_mapper/plugins/keys.rb +28 -22
- data/lib/mongo_mapper/plugins/keys/key.rb +12 -6
- data/lib/mongo_mapper/plugins/logger.rb +2 -0
- data/lib/mongo_mapper/plugins/modifiers.rb +3 -1
- data/lib/mongo_mapper/plugins/pagination.rb +2 -0
- data/lib/mongo_mapper/plugins/persistence.rb +2 -0
- data/lib/mongo_mapper/plugins/protected.rb +2 -0
- data/lib/mongo_mapper/plugins/querying.rb +5 -4
- data/lib/mongo_mapper/plugins/rails.rb +3 -5
- data/lib/mongo_mapper/plugins/safe.rb +2 -0
- data/lib/mongo_mapper/plugins/sci.rb +2 -0
- data/lib/mongo_mapper/plugins/scopes.rb +2 -0
- data/lib/mongo_mapper/plugins/serialization.rb +67 -46
- data/lib/mongo_mapper/plugins/timestamps.rb +3 -1
- data/lib/mongo_mapper/plugins/userstamps.rb +2 -0
- data/lib/mongo_mapper/plugins/validations.rb +40 -24
- data/lib/mongo_mapper/railtie.rb +49 -0
- data/lib/mongo_mapper/railtie/database.rake +60 -0
- data/lib/mongo_mapper/support/descendant_appends.rb +11 -11
- data/lib/mongo_mapper/translation.rb +10 -0
- data/lib/mongo_mapper/version.rb +1 -1
- data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
- data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
- data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
- data/lib/rails/generators/mongo_mapper/model/templates/model.rb +11 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +1 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +131 -1
- data/test/functional/associations/test_in_array_proxy.rb +30 -0
- data/test/functional/associations/test_many_documents_proxy.rb +30 -2
- data/test/functional/associations/test_many_embedded_proxy.rb +33 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +1 -0
- data/test/functional/associations/test_one_embedded_proxy.rb +21 -2
- data/test/functional/associations/test_one_proxy.rb +49 -9
- data/test/functional/test_associations.rb +2 -0
- data/test/functional/test_caching.rb +3 -2
- data/test/functional/test_callbacks.rb +25 -18
- data/test/functional/test_dirty.rb +123 -1
- data/test/functional/test_document.rb +26 -2
- data/test/functional/test_embedded_document.rb +68 -2
- data/test/functional/test_identity_map.rb +3 -4
- data/test/functional/test_querying.rb +11 -0
- data/test/functional/test_userstamps.rb +2 -2
- data/test/functional/test_validations.rb +31 -29
- data/test/models.rb +10 -0
- data/test/test_active_model_lint.rb +1 -1
- data/test/test_helper.rb +9 -10
- data/test/unit/associations/test_base.rb +24 -100
- data/test/unit/associations/test_belongs_to_association.rb +29 -0
- data/test/unit/associations/test_many_association.rb +63 -0
- data/test/unit/associations/test_one_association.rb +18 -0
- data/test/unit/serializers/test_json_serializer.rb +0 -1
- data/test/unit/test_descendant_appends.rb +8 -16
- data/test/unit/test_document.rb +4 -9
- data/test/unit/test_dynamic_finder.rb +1 -1
- data/test/unit/test_embedded_document.rb +51 -18
- data/test/unit/test_identity_map_middleware.rb +34 -0
- data/test/unit/test_inspect.rb +22 -0
- data/test/unit/test_key.rb +21 -1
- data/test/unit/test_keys.rb +0 -2
- data/test/unit/test_plugins.rb +106 -20
- data/test/unit/test_rails.rb +8 -8
- data/test/unit/test_serialization.rb +116 -1
- data/test/unit/test_translation.rb +27 -0
- data/test/unit/test_validations.rb +66 -81
- metadata +103 -43
- data/examples/identity_map/middleware.rb +0 -14
- data/lib/mongo_mapper/plugins/descendants.rb +0 -17
- data/rails/init.rb +0 -19
@@ -2,6 +2,8 @@
|
|
2
2
|
module MongoMapper
|
3
3
|
module Plugins
|
4
4
|
module Document
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
5
7
|
module ClassMethods
|
6
8
|
def embeddable?
|
7
9
|
false
|
@@ -20,8 +22,8 @@ module MongoMapper
|
|
20
22
|
def reload
|
21
23
|
if doc = collection.find_one(:_id => id)
|
22
24
|
tap do |instance|
|
23
|
-
instance.class.associations.
|
24
|
-
|
25
|
+
instance.class.associations.each_value do |association|
|
26
|
+
get_proxy(association).reset
|
25
27
|
end
|
26
28
|
instance.attributes = doc
|
27
29
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module MongoMapper
|
3
|
+
module Plugins
|
4
|
+
module EmbeddedCallbacks
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
extend ::ActiveModel::Callbacks
|
9
|
+
include ::ActiveModel::Validations::Callbacks
|
10
|
+
|
11
|
+
define_model_callbacks :validation, :save, :create, :update, :destroy, :only => [:before, :after]
|
12
|
+
end
|
13
|
+
|
14
|
+
module InstanceMethods
|
15
|
+
def run_callbacks(callback, &block)
|
16
|
+
embedded_docs = []
|
17
|
+
|
18
|
+
embedded_associations.each do |association|
|
19
|
+
embedded_docs += Array(get_proxy(association).send(:load_target))
|
20
|
+
end
|
21
|
+
|
22
|
+
block = embedded_docs.inject(block) do |chain, doc|
|
23
|
+
if doc.class.respond_to?("_#{callback}_callbacks")
|
24
|
+
lambda { doc.run_callbacks(callback, &chain) }
|
25
|
+
else
|
26
|
+
chain
|
27
|
+
end
|
28
|
+
end
|
29
|
+
super callback, &block
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Need to monkey patch ActiveModel for now since it uses the internal
|
37
|
+
# _run_validation_callbacks, which is impossible to override due to the
|
38
|
+
# way ActiveSupport::Callbacks is implemented.
|
39
|
+
ActiveModel::Validations::Callbacks.class_eval do
|
40
|
+
def run_validations!
|
41
|
+
run_callbacks(:validation) { super }
|
42
|
+
end
|
43
|
+
end
|
@@ -2,10 +2,10 @@
|
|
2
2
|
module MongoMapper
|
3
3
|
module Plugins
|
4
4
|
module EmbeddedDocument
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
attr_accessor :_parent_document
|
9
9
|
end
|
10
10
|
|
11
11
|
module ClassMethods
|
@@ -14,7 +14,7 @@ module MongoMapper
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def embedded_in(owner_name)
|
17
|
-
|
17
|
+
alias_method owner_name, :_parent_document
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -29,20 +29,27 @@ module MongoMapper
|
|
29
29
|
|
30
30
|
def save(options={})
|
31
31
|
_root_document.try(:save, options).tap do |result|
|
32
|
-
|
32
|
+
persist(options) if result
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
def save!(options={})
|
37
|
-
|
38
|
-
|
37
|
+
valid? || raise(DocumentNotValid.new(self))
|
38
|
+
_root_document.try(:save!, options).tap do |result|
|
39
|
+
persist(options) if result
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
43
|
+
def persist(options={})
|
44
|
+
@_new = false
|
45
|
+
clear_changes if respond_to?(:clear_changes)
|
46
|
+
save_to_collection(options)
|
47
|
+
end
|
48
|
+
|
42
49
|
def _root_document
|
43
50
|
@_root_document ||= _parent_document.try(:_root_document)
|
44
51
|
end
|
45
52
|
end
|
46
53
|
end
|
47
54
|
end
|
48
|
-
end
|
55
|
+
end
|
@@ -4,6 +4,8 @@ require 'set'
|
|
4
4
|
module MongoMapper
|
5
5
|
module Plugins
|
6
6
|
module IdentityMap
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
7
9
|
def self.models
|
8
10
|
@models ||= Set.new
|
9
11
|
end
|
@@ -12,8 +14,8 @@ module MongoMapper
|
|
12
14
|
models.each { |m| m.identity_map.clear }
|
13
15
|
end
|
14
16
|
|
15
|
-
|
16
|
-
IdentityMap.models <<
|
17
|
+
included do
|
18
|
+
IdentityMap.models << self
|
17
19
|
end
|
18
20
|
|
19
21
|
module ClassMethods
|
@@ -2,9 +2,11 @@
|
|
2
2
|
module MongoMapper
|
3
3
|
module Plugins
|
4
4
|
module Inspect
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
5
7
|
module InstanceMethods
|
6
8
|
def inspect
|
7
|
-
attributes_as_nice_string = key_names.collect do |name|
|
9
|
+
attributes_as_nice_string = key_names.sort.collect do |name|
|
8
10
|
"#{name}: #{self[name].inspect}"
|
9
11
|
end.join(", ")
|
10
12
|
"#<#{self.class} #{attributes_as_nice_string}>"
|
@@ -4,8 +4,11 @@ require 'mongo_mapper/plugins/keys/key'
|
|
4
4
|
module MongoMapper
|
5
5
|
module Plugins
|
6
6
|
module Keys
|
7
|
-
|
8
|
-
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
extend ActiveSupport::DescendantsTracker
|
11
|
+
key :_id, ObjectId
|
9
12
|
end
|
10
13
|
|
11
14
|
module ClassMethods
|
@@ -15,7 +18,7 @@ module MongoMapper
|
|
15
18
|
end
|
16
19
|
|
17
20
|
def keys
|
18
|
-
@keys ||=
|
21
|
+
@keys ||= {}
|
19
22
|
end
|
20
23
|
|
21
24
|
def key(*args)
|
@@ -37,7 +40,7 @@ module MongoMapper
|
|
37
40
|
end
|
38
41
|
|
39
42
|
def object_id_keys
|
40
|
-
keys.keys.select { |key| keys[key].type == ObjectId }.map
|
43
|
+
keys.keys.select { |key| keys[key].type == ObjectId }.map { |k| k.to_sym }
|
41
44
|
end
|
42
45
|
|
43
46
|
def object_id_key?(name)
|
@@ -92,8 +95,8 @@ module MongoMapper
|
|
92
95
|
read_key(:#{key.name})
|
93
96
|
end
|
94
97
|
|
95
|
-
def #{key.name}
|
96
|
-
|
98
|
+
def #{key.name}_before_type_cast
|
99
|
+
read_key_before_type_cast(:#{key.name})
|
97
100
|
end
|
98
101
|
|
99
102
|
def #{key.name}=(value)
|
@@ -137,11 +140,11 @@ module MongoMapper
|
|
137
140
|
end
|
138
141
|
|
139
142
|
if key.options[:in]
|
140
|
-
validates_inclusion_of(attribute, :
|
143
|
+
validates_inclusion_of(attribute, :in => key.options[:in])
|
141
144
|
end
|
142
145
|
|
143
146
|
if key.options[:not_in]
|
144
|
-
validates_exclusion_of(attribute, :
|
147
|
+
validates_exclusion_of(attribute, :in => key.options[:not_in])
|
145
148
|
end
|
146
149
|
|
147
150
|
if key.options[:length]
|
@@ -168,6 +171,7 @@ module MongoMapper
|
|
168
171
|
def initialize_from_database(attrs={})
|
169
172
|
@_new = false
|
170
173
|
load_from_database(attrs)
|
174
|
+
default_id_value(attrs)
|
171
175
|
self
|
172
176
|
end
|
173
177
|
|
@@ -196,7 +200,7 @@ module MongoMapper
|
|
196
200
|
|
197
201
|
embedded_associations.each do |association|
|
198
202
|
if documents = instance_variable_get(association.ivar)
|
199
|
-
if association.
|
203
|
+
if association.is_a?(Associations::OneAssociation)
|
200
204
|
attrs[association.name] = documents.to_mongo
|
201
205
|
else
|
202
206
|
attrs[association.name] = documents.map { |document| document.to_mongo }
|
@@ -221,6 +225,10 @@ module MongoMapper
|
|
221
225
|
save!
|
222
226
|
end
|
223
227
|
|
228
|
+
def update_attribute(name, value)
|
229
|
+
update_attributes(name.to_sym => value)
|
230
|
+
end
|
231
|
+
|
224
232
|
def id
|
225
233
|
_id
|
226
234
|
end
|
@@ -258,6 +266,13 @@ module MongoMapper
|
|
258
266
|
keys.values.select { |key| key.embeddable? }
|
259
267
|
end
|
260
268
|
|
269
|
+
def default_id_value(attrs={})
|
270
|
+
id_provided = !attrs.nil? && attrs.keys.map { |k| k.to_s }.detect { |k| k == 'id' || k == '_id' }
|
271
|
+
if !id_provided && self.class.can_default_id?
|
272
|
+
write_key :_id, BSON::ObjectId.new
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
261
276
|
private
|
262
277
|
def load_from_database(attrs)
|
263
278
|
return if attrs.blank?
|
@@ -270,15 +285,6 @@ module MongoMapper
|
|
270
285
|
end
|
271
286
|
end
|
272
287
|
|
273
|
-
def default_id_value(attrs)
|
274
|
-
unless attrs.nil?
|
275
|
-
id_provided = attrs.keys.map { |k| k.to_s }.detect { |k| k == 'id' || k == '_id' }
|
276
|
-
if !id_provided && self.class.can_default_id?
|
277
|
-
write_key :_id, BSON::ObjectId.new
|
278
|
-
end
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
288
|
def ensure_key_exists(name)
|
283
289
|
self.class.key(name) unless respond_to?("#{name}=")
|
284
290
|
end
|
@@ -290,21 +296,21 @@ module MongoMapper
|
|
290
296
|
end
|
291
297
|
|
292
298
|
def read_key(key_name)
|
293
|
-
if key = keys[key_name]
|
299
|
+
if key = keys[key_name.to_s]
|
294
300
|
value = key.get(instance_variable_get(:"@#{key_name}"))
|
295
301
|
set_parent_document(key, value)
|
296
302
|
instance_variable_set(:"@#{key_name}", value)
|
297
303
|
end
|
298
304
|
end
|
299
305
|
|
300
|
-
def
|
301
|
-
instance_variable_get(:"@#{name}
|
306
|
+
def read_key_before_type_cast(name)
|
307
|
+
instance_variable_get(:"@#{name}_before_type_cast")
|
302
308
|
end
|
303
309
|
|
304
310
|
def write_key(name, value)
|
305
311
|
key = keys[name.to_s]
|
306
312
|
set_parent_document(key, value)
|
307
|
-
instance_variable_set :"@#{name}
|
313
|
+
instance_variable_set :"@#{name}_before_type_cast", value
|
308
314
|
instance_variable_set :"@#{name}", key.set(value)
|
309
315
|
end
|
310
316
|
end
|
@@ -22,11 +22,11 @@ module MongoMapper
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def can_default_id?
|
25
|
-
type &&
|
25
|
+
type && (type == ObjectId || type == BSON::ObjectId || type == String)
|
26
26
|
end
|
27
27
|
|
28
28
|
def number?
|
29
|
-
|
29
|
+
type == Integer || type == Float
|
30
30
|
end
|
31
31
|
|
32
32
|
def get(value)
|
@@ -34,11 +34,17 @@ module MongoMapper
|
|
34
34
|
if default_value.respond_to?(:call)
|
35
35
|
return default_value.call
|
36
36
|
else
|
37
|
-
|
37
|
+
# Using Marshal is easiest way to get a copy of mutable objects
|
38
|
+
# without getting an error on immutable objects
|
39
|
+
return Marshal.load(Marshal.dump(default_value))
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
|
-
|
43
|
+
if options[:typecast].present?
|
44
|
+
type.from_mongo(value).map! { |v| typecast_class.from_mongo(v) }
|
45
|
+
else
|
46
|
+
type.from_mongo(value)
|
47
|
+
end
|
42
48
|
end
|
43
49
|
|
44
50
|
def set(value)
|
@@ -48,7 +54,7 @@ module MongoMapper
|
|
48
54
|
end
|
49
55
|
end
|
50
56
|
end
|
51
|
-
|
57
|
+
|
52
58
|
private
|
53
59
|
def typecast_class
|
54
60
|
@typecast_class ||= options[:typecast].constantize
|
@@ -56,4 +62,4 @@ module MongoMapper
|
|
56
62
|
end
|
57
63
|
end
|
58
64
|
end
|
59
|
-
end
|
65
|
+
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
module MongoMapper
|
3
3
|
module Plugins
|
4
4
|
module Modifiers
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
5
7
|
module ClassMethods
|
6
8
|
def increment(*args)
|
7
9
|
modifier_update('$inc', args)
|
@@ -17,7 +19,7 @@ module MongoMapper
|
|
17
19
|
def set(*args)
|
18
20
|
criteria, updates = criteria_and_keys_from_args(args)
|
19
21
|
updates.each do |key, value|
|
20
|
-
updates[key] = keys[key].set(value) if key?(key)
|
22
|
+
updates[key] = keys[key.to_s].set(value) if key?(key)
|
21
23
|
end
|
22
24
|
collection.update(criteria, {'$set' => updates}, :multi => true)
|
23
25
|
end
|
@@ -5,6 +5,8 @@ require 'mongo_mapper/plugins/querying/plucky_methods'
|
|
5
5
|
module MongoMapper
|
6
6
|
module Plugins
|
7
7
|
module Querying
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
8
10
|
module ClassMethods
|
9
11
|
include PluckyMethods
|
10
12
|
|
@@ -50,7 +52,7 @@ module MongoMapper
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def destroy(*ids)
|
53
|
-
find_some!(ids.flatten).each
|
55
|
+
find_some!(ids.flatten).each { |doc| doc.destroy }
|
54
56
|
end
|
55
57
|
|
56
58
|
def destroy_all(options={})
|
@@ -148,13 +150,12 @@ module MongoMapper
|
|
148
150
|
end
|
149
151
|
|
150
152
|
def delete
|
151
|
-
@_destroyed = true
|
152
|
-
self.class.delete(id) unless new?
|
153
|
+
self.class.delete(id).tap { @_destroyed = true } if persisted?
|
153
154
|
end
|
154
155
|
|
155
156
|
private
|
156
157
|
def create_or_update(options={})
|
157
|
-
result =
|
158
|
+
result = persisted? ? update(options) : create(options)
|
158
159
|
result != false
|
159
160
|
end
|
160
161
|
|