mongo_mapper 0.7.3 → 0.7.4
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/Rakefile +3 -2
- data/lib/mongo_mapper.rb +2 -3
- data/lib/mongo_mapper/plugins/associations.rb +10 -1
- data/lib/mongo_mapper/plugins/associations/base.rb +2 -2
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +12 -3
- data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +41 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +1 -0
- data/lib/mongo_mapper/plugins/associations/proxy.rb +8 -2
- data/lib/mongo_mapper/plugins/callbacks.rb +7 -3
- data/lib/mongo_mapper/plugins/descendants.rb +2 -2
- data/lib/mongo_mapper/plugins/keys.rb +14 -7
- data/lib/mongo_mapper/plugins/modifiers.rb +30 -14
- data/lib/mongo_mapper/plugins/protected.rb +1 -1
- data/lib/mongo_mapper/plugins/serialization.rb +1 -1
- data/lib/mongo_mapper/query.rb +27 -19
- data/lib/mongo_mapper/support.rb +10 -6
- data/lib/mongo_mapper/version.rb +1 -1
- data/mongo_mapper.gemspec +14 -8
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +1 -1
- data/test/functional/associations/test_belongs_to_proxy.rb +1 -1
- data/test/functional/associations/test_many_documents_proxy.rb +100 -17
- data/test/functional/associations/test_one_embedded_proxy.rb +68 -0
- data/test/functional/associations/test_one_proxy.rb +48 -13
- data/test/functional/test_binary.rb +1 -1
- data/test/functional/test_document.rb +7 -7
- data/test/functional/test_embedded_document.rb +8 -0
- data/test/functional/test_identity_map.rb +2 -2
- data/test/functional/test_modifiers.rb +249 -185
- data/test/functional/test_protected.rb +4 -0
- data/test/functional/test_string_id_compatibility.rb +1 -1
- data/test/support/custom_matchers.rb +0 -18
- data/test/test_helper.rb +6 -4
- data/test/unit/associations/test_base.rb +7 -2
- data/test/unit/test_document.rb +5 -5
- data/test/unit/test_embedded_document.rb +7 -7
- data/test/unit/test_query.rb +17 -7
- data/test/unit/test_support.rb +26 -14
- metadata +33 -16
data/Rakefile
CHANGED
@@ -13,9 +13,10 @@ Jeweler::Tasks.new do |gem|
|
|
13
13
|
gem.version = MongoMapper::Version
|
14
14
|
|
15
15
|
gem.add_dependency('activesupport', '>= 2.3.4')
|
16
|
-
gem.add_dependency('mongo', '0.
|
17
|
-
gem.add_dependency('jnunemaker-validatable', '1.8.
|
16
|
+
gem.add_dependency('mongo', '0.20.1')
|
17
|
+
gem.add_dependency('jnunemaker-validatable', '1.8.4')
|
18
18
|
|
19
|
+
gem.add_development_dependency('json', '>= 1.2.3')
|
19
20
|
gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
|
20
21
|
gem.add_development_dependency('shoulda', '2.10.2')
|
21
22
|
gem.add_development_dependency('timecop', '0.3.1')
|
data/lib/mongo_mapper.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# Make sure you have the following libs in your load path or you could have issues:
|
2
2
|
# gem 'activesupport', '>= 2.3.4'
|
3
|
-
# gem 'mongo', '0.
|
4
|
-
# gem 'jnunemaker-validatable', '1.8.
|
5
|
-
# gem 'activesupport', '= 2.3.4'
|
3
|
+
# gem 'mongo', '0.20.1'
|
4
|
+
# gem 'jnunemaker-validatable', '1.8.4'
|
6
5
|
require 'set'
|
7
6
|
require 'uri'
|
8
7
|
require 'mongo'
|
@@ -84,6 +84,14 @@ module MongoMapper
|
|
84
84
|
|
85
85
|
proxy
|
86
86
|
end
|
87
|
+
|
88
|
+
def save_to_collection(options = {})
|
89
|
+
super
|
90
|
+
associations.each do |association_name, association|
|
91
|
+
proxy = get_proxy(association)
|
92
|
+
proxy.save_to_collection(options) if proxy.proxy_respond_to?(:save_to_collection)
|
93
|
+
end
|
94
|
+
end
|
87
95
|
end
|
88
96
|
|
89
97
|
autoload :Base, 'mongo_mapper/plugins/associations/base'
|
@@ -97,9 +105,10 @@ module MongoMapper
|
|
97
105
|
autoload :ManyEmbeddedPolymorphicProxy, 'mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy'
|
98
106
|
autoload :ManyDocumentsAsProxy, 'mongo_mapper/plugins/associations/many_documents_as_proxy'
|
99
107
|
autoload :OneProxy, 'mongo_mapper/plugins/associations/one_proxy'
|
108
|
+
autoload :OneEmbeddedProxy, 'mongo_mapper/plugins/associations/one_embedded_proxy'
|
100
109
|
autoload :InArrayProxy, 'mongo_mapper/plugins/associations/in_array_proxy'
|
101
110
|
end
|
102
111
|
end
|
103
112
|
end
|
104
113
|
|
105
|
-
require 'mongo_mapper/plugins/associations/proxy'
|
114
|
+
require 'mongo_mapper/plugins/associations/proxy'
|
@@ -56,7 +56,7 @@ module MongoMapper
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def embeddable?
|
59
|
-
many? && klass.embeddable?
|
59
|
+
(one? || many?) && klass.embeddable?
|
60
60
|
end
|
61
61
|
|
62
62
|
def type_key_name
|
@@ -95,7 +95,7 @@ module MongoMapper
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
elsif one?
|
98
|
-
OneProxy
|
98
|
+
klass.embeddable? ? OneEmbeddedProxy : OneProxy
|
99
99
|
else
|
100
100
|
polymorphic? ? BelongsToPolymorphicProxy : BelongsToProxy
|
101
101
|
end
|
@@ -37,13 +37,13 @@ module MongoMapper
|
|
37
37
|
def replace(docs)
|
38
38
|
load_target
|
39
39
|
target.map(&:destroy)
|
40
|
-
docs.each { |doc|
|
40
|
+
docs.each { |doc| prepare(doc).save }
|
41
41
|
reset
|
42
42
|
end
|
43
43
|
|
44
44
|
def <<(*docs)
|
45
45
|
ensure_owner_saved
|
46
|
-
flatten_deeper(docs).each { |doc|
|
46
|
+
flatten_deeper(docs).each { |doc| prepare(doc).save }
|
47
47
|
reset
|
48
48
|
end
|
49
49
|
alias_method :push, :<<
|
@@ -52,7 +52,8 @@ module MongoMapper
|
|
52
52
|
def build(attrs={})
|
53
53
|
doc = klass.new(attrs)
|
54
54
|
apply_scope(doc)
|
55
|
-
|
55
|
+
@target ||= [] unless loaded?
|
56
|
+
@target << doc
|
56
57
|
doc
|
57
58
|
end
|
58
59
|
|
@@ -87,6 +88,10 @@ module MongoMapper
|
|
87
88
|
end
|
88
89
|
reset
|
89
90
|
end
|
91
|
+
|
92
|
+
def save_to_collection(options = {})
|
93
|
+
@target.each { |doc| doc.save(options) } if @target
|
94
|
+
end
|
90
95
|
|
91
96
|
protected
|
92
97
|
def scoped_conditions
|
@@ -105,6 +110,10 @@ module MongoMapper
|
|
105
110
|
owner.save if owner.new?
|
106
111
|
end
|
107
112
|
|
113
|
+
def prepare(doc)
|
114
|
+
klass === doc ? apply_scope(doc) : build(doc)
|
115
|
+
end
|
116
|
+
|
108
117
|
def apply_scope(doc)
|
109
118
|
ensure_owner_saved
|
110
119
|
doc[foreign_key] = owner.id
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Associations
|
4
|
+
class OneEmbeddedProxy < Proxy
|
5
|
+
undef_method :object_id
|
6
|
+
|
7
|
+
def build(attributes={})
|
8
|
+
@target = klass.new(attributes)
|
9
|
+
assign_references(@target)
|
10
|
+
loaded
|
11
|
+
@target
|
12
|
+
end
|
13
|
+
|
14
|
+
def replace(doc)
|
15
|
+
if doc.respond_to?(:attributes)
|
16
|
+
@target = klass.load(doc.attributes)
|
17
|
+
else
|
18
|
+
@target = klass.load(doc)
|
19
|
+
end
|
20
|
+
assign_references(@target)
|
21
|
+
loaded
|
22
|
+
@target
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def find_target
|
28
|
+
if @value
|
29
|
+
klass.load(@value).tap do |child|
|
30
|
+
assign_references(child)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def assign_references(doc)
|
36
|
+
doc._parent_document = owner
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -96,8 +96,14 @@ module MongoMapper
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def load_target
|
99
|
-
|
100
|
-
|
99
|
+
unless loaded?
|
100
|
+
if @target.is_a?(Array) && @target.any?
|
101
|
+
@target = find_target + @target.find_all { |record| record.new? }
|
102
|
+
else
|
103
|
+
@target = find_target
|
104
|
+
end
|
105
|
+
loaded
|
106
|
+
end
|
101
107
|
@target
|
102
108
|
rescue MongoMapper::DocumentNotFound
|
103
109
|
reset
|
@@ -81,8 +81,12 @@ module MongoMapper
|
|
81
81
|
return unless self.class.respond_to?(callback_chain_method)
|
82
82
|
self.class.send(callback_chain_method).run(self, options, &block)
|
83
83
|
self.embedded_associations.each do |association|
|
84
|
-
|
85
|
-
|
84
|
+
if association.one?
|
85
|
+
self.send(association.name).run_callbacks(kind, options, &block)
|
86
|
+
else
|
87
|
+
self.send(association.name).each do |document|
|
88
|
+
document.run_callbacks(kind, options, &block)
|
89
|
+
end
|
86
90
|
end
|
87
91
|
end
|
88
92
|
end
|
@@ -233,4 +237,4 @@ module MongoMapper
|
|
233
237
|
end
|
234
238
|
end
|
235
239
|
end
|
236
|
-
end
|
240
|
+
end
|
@@ -3,12 +3,12 @@ module MongoMapper
|
|
3
3
|
module Descendants
|
4
4
|
module ClassMethods
|
5
5
|
def inherited(descendant)
|
6
|
-
|
6
|
+
descendants << descendant
|
7
7
|
super
|
8
8
|
end
|
9
9
|
|
10
10
|
def descendants
|
11
|
-
@descendants
|
11
|
+
@descendants ||= []
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -95,7 +95,6 @@ module MongoMapper
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def create_key_in_descendants(*args)
|
98
|
-
return if descendants.blank?
|
99
98
|
descendants.each { |descendant| descendant.key(*args) }
|
100
99
|
end
|
101
100
|
|
@@ -188,7 +187,11 @@ module MongoMapper
|
|
188
187
|
|
189
188
|
embedded_associations.each do |association|
|
190
189
|
if documents = instance_variable_get(association.ivar)
|
191
|
-
|
190
|
+
if association.one?
|
191
|
+
attrs[association.name] = documents.to_mongo
|
192
|
+
else
|
193
|
+
attrs[association.name] = documents.map { |document| document.to_mongo }
|
194
|
+
end
|
192
195
|
end
|
193
196
|
end
|
194
197
|
|
@@ -252,7 +255,7 @@ module MongoMapper
|
|
252
255
|
unless attrs.nil?
|
253
256
|
provided_keys = attrs.keys.map { |k| k.to_s }
|
254
257
|
unless provided_keys.include?('_id') || provided_keys.include?('id')
|
255
|
-
write_key :_id,
|
258
|
+
write_key :_id, BSON::ObjectID.new
|
256
259
|
end
|
257
260
|
end
|
258
261
|
end
|
@@ -265,10 +268,17 @@ module MongoMapper
|
|
265
268
|
self.class.key(name) unless respond_to?("#{name}=")
|
266
269
|
end
|
267
270
|
|
271
|
+
def set_parent_document(key, value)
|
272
|
+
if key.embeddable? && value.is_a?(key.type)
|
273
|
+
value._parent_document = self
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
268
277
|
def read_key(name)
|
269
278
|
if key = keys[name]
|
270
279
|
var_name = "@#{name}"
|
271
280
|
value = key.get(instance_variable_get(var_name))
|
281
|
+
set_parent_document(key, value)
|
272
282
|
instance_variable_set(var_name, value)
|
273
283
|
else
|
274
284
|
raise KeyNotFound, "Could not find key: #{name.inspect}"
|
@@ -282,10 +292,7 @@ module MongoMapper
|
|
282
292
|
def write_key(name, value)
|
283
293
|
key = keys[name]
|
284
294
|
|
285
|
-
|
286
|
-
value._parent_document = self
|
287
|
-
end
|
288
|
-
|
295
|
+
set_parent_document(key, value)
|
289
296
|
instance_variable_set "@#{name}_before_typecast", value
|
290
297
|
instance_variable_set "@#{name}", key.set(value)
|
291
298
|
end
|
@@ -17,6 +17,19 @@ module MongoMapper
|
|
17
17
|
modifier_update('$set', args)
|
18
18
|
end
|
19
19
|
|
20
|
+
def unset(*args)
|
21
|
+
if args[0].is_a?(Hash)
|
22
|
+
criteria, keys = args.shift, args
|
23
|
+
else
|
24
|
+
keys, ids = args.partition { |arg| arg.is_a?(Symbol) }
|
25
|
+
criteria = {:id => ids}
|
26
|
+
end
|
27
|
+
|
28
|
+
criteria = to_criteria(criteria)
|
29
|
+
modifiers = keys.inject({}) { |hash, key| hash[key] = 1; hash }
|
30
|
+
collection.update(criteria, {'$unset' => modifiers}, :multi => true)
|
31
|
+
end
|
32
|
+
|
20
33
|
def push(*args)
|
21
34
|
modifier_update('$push', args)
|
22
35
|
end
|
@@ -25,11 +38,10 @@ module MongoMapper
|
|
25
38
|
modifier_update('$pushAll', args)
|
26
39
|
end
|
27
40
|
|
28
|
-
def
|
29
|
-
|
30
|
-
keys.each { |key, value | criteria[key] = {'$ne' => value} }
|
31
|
-
collection.update(criteria, {'$push' => keys}, :multi => true)
|
41
|
+
def add_to_set(*args)
|
42
|
+
modifier_update('$addToSet', args)
|
32
43
|
end
|
44
|
+
alias push_uniq add_to_set
|
33
45
|
|
34
46
|
def pull(*args)
|
35
47
|
modifier_update('$pull', args)
|
@@ -46,8 +58,7 @@ module MongoMapper
|
|
46
58
|
private
|
47
59
|
def modifier_update(modifier, args)
|
48
60
|
criteria, keys = criteria_and_keys_from_args(args)
|
49
|
-
|
50
|
-
collection.update(criteria, modifiers, :multi => true)
|
61
|
+
collection.update(criteria, {modifier => keys}, :multi => true)
|
51
62
|
end
|
52
63
|
|
53
64
|
def criteria_and_keys_from_args(args)
|
@@ -58,32 +69,37 @@ module MongoMapper
|
|
58
69
|
end
|
59
70
|
|
60
71
|
module InstanceMethods
|
72
|
+
def unset(*keys)
|
73
|
+
self.class.unset(id, *keys)
|
74
|
+
end
|
75
|
+
|
61
76
|
def increment(hash)
|
62
|
-
self.class.increment(
|
77
|
+
self.class.increment(id, hash)
|
63
78
|
end
|
64
79
|
|
65
80
|
def decrement(hash)
|
66
|
-
self.class.decrement(
|
81
|
+
self.class.decrement(id, hash)
|
67
82
|
end
|
68
83
|
|
69
84
|
def set(hash)
|
70
|
-
self.class.set(
|
85
|
+
self.class.set(id, hash)
|
71
86
|
end
|
72
87
|
|
73
88
|
def push(hash)
|
74
|
-
self.class.push(
|
89
|
+
self.class.push(id, hash)
|
75
90
|
end
|
76
91
|
|
77
92
|
def pull(hash)
|
78
|
-
self.class.pull(
|
93
|
+
self.class.pull(id, hash)
|
79
94
|
end
|
80
95
|
|
81
|
-
def
|
82
|
-
self.class.push_uniq(
|
96
|
+
def add_to_set(hash)
|
97
|
+
self.class.push_uniq(id, hash)
|
83
98
|
end
|
99
|
+
alias push_uniq add_to_set
|
84
100
|
|
85
101
|
def pop(hash)
|
86
|
-
self.class.pop(
|
102
|
+
self.class.pop(id, hash)
|
87
103
|
end
|
88
104
|
end
|
89
105
|
end
|
@@ -36,7 +36,7 @@ module MongoMapper
|
|
36
36
|
|
37
37
|
protected
|
38
38
|
def filter_protected_attrs(attrs)
|
39
|
-
return attrs if protected_attributes.blank?
|
39
|
+
return attrs if protected_attributes.blank? || attrs.blank?
|
40
40
|
attrs.dup.delete_if { |key, val| protected_attributes.include?(key.to_sym) }
|
41
41
|
end
|
42
42
|
end
|
@@ -51,7 +51,7 @@ module MongoMapper
|
|
51
51
|
hash[key] = value.map do |item|
|
52
52
|
item.respond_to?(:as_json) ? item.as_json(options) : item
|
53
53
|
end
|
54
|
-
elsif value.is_a?
|
54
|
+
elsif value.is_a? BSON::ObjectID
|
55
55
|
hash[key] = value.to_s
|
56
56
|
elsif value.respond_to?(:as_json)
|
57
57
|
hash[key] = value.as_json(options)
|
data/lib/mongo_mapper/query.rb
CHANGED
@@ -68,49 +68,52 @@ module MongoMapper
|
|
68
68
|
if model.object_id_key?(key)
|
69
69
|
case value
|
70
70
|
when String
|
71
|
-
value =
|
71
|
+
value = ObjectId.to_mongo(value)
|
72
72
|
when Array
|
73
73
|
value.map! { |id| ObjectId.to_mongo(id) }
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
77
|
if symbol_operator?(key)
|
78
|
-
value = {"$#{key.operator}" => value}
|
79
|
-
key = normalized_key(key.field)
|
78
|
+
key, value = normalized_key(key.field), {"$#{key.operator}" => value}
|
80
79
|
end
|
81
80
|
|
82
|
-
criteria[key] = normalized_value(key, value)
|
81
|
+
criteria[key] = normalized_value(criteria, key, value)
|
83
82
|
end
|
84
83
|
|
85
84
|
criteria
|
86
85
|
end
|
87
86
|
|
88
|
-
def to_fields(
|
89
|
-
return if
|
87
|
+
def to_fields(keys)
|
88
|
+
return keys if keys.is_a?(Hash)
|
89
|
+
return nil if keys.blank?
|
90
90
|
|
91
|
-
if
|
92
|
-
|
91
|
+
if keys.respond_to?(:flatten, :compact)
|
92
|
+
keys.flatten.compact
|
93
93
|
else
|
94
|
-
|
94
|
+
keys.split(',').map { |key| key.strip }
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
|
-
def to_order(
|
99
|
-
direction
|
100
|
-
direction = direction.upcase == 'ASC' ? 1 : -1
|
101
|
-
[normalized_key(field).to_s, direction]
|
98
|
+
def to_order(key, direction=nil)
|
99
|
+
[normalized_key(key).to_s, normalized_direction(direction)]
|
102
100
|
end
|
103
101
|
|
104
|
-
def normalized_key(
|
105
|
-
|
102
|
+
def normalized_key(key)
|
103
|
+
key.to_s == 'id' ? :_id : key
|
106
104
|
end
|
107
105
|
|
108
|
-
|
106
|
+
# TODO: this is getting heavy enough to move to a class
|
107
|
+
def normalized_value(criteria, key, value)
|
109
108
|
case value
|
110
109
|
when Array, Set
|
111
|
-
modifier?(
|
110
|
+
modifier?(key) ? value.to_a : {'$in' => value.to_a}
|
112
111
|
when Hash
|
113
|
-
|
112
|
+
if criteria[key].kind_of?(Hash)
|
113
|
+
criteria[key].dup.merge(to_criteria(value, key))
|
114
|
+
else
|
115
|
+
to_criteria(value, key)
|
116
|
+
end
|
114
117
|
when Time
|
115
118
|
value.utc
|
116
119
|
else
|
@@ -118,6 +121,11 @@ module MongoMapper
|
|
118
121
|
end
|
119
122
|
end
|
120
123
|
|
124
|
+
def normalized_direction(direction)
|
125
|
+
direction ||= 'asc'
|
126
|
+
direction.downcase == 'asc' ? Mongo::ASCENDING : Mongo::DESCENDING
|
127
|
+
end
|
128
|
+
|
121
129
|
def normalized_sort(sort)
|
122
130
|
return if sort.blank?
|
123
131
|
|
@@ -132,4 +140,4 @@ module MongoMapper
|
|
132
140
|
end
|
133
141
|
end
|
134
142
|
end
|
135
|
-
end
|
143
|
+
end
|