mongoo 0.4.4 → 0.4.5
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/mongoo/attribute_sanitizer.rb +4 -3
- data/lib/mongoo/modifiers.rb +95 -80
- data/lib/mongoo/persistence.rb +21 -11
- data/mongoo.gemspec +3 -3
- data/test/test_mongoo.rb +70 -8
- metadata +4 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.5
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module Mongoo
|
2
2
|
class InvalidAttributeValue < Exception; end
|
3
|
-
|
3
|
+
|
4
4
|
class AttributeSanitizer
|
5
5
|
class << self
|
6
6
|
def sanitize(field_type, val)
|
7
7
|
return val if val.nil? || field_type.nil?
|
8
|
-
|
8
|
+
|
9
9
|
case field_type.to_sym
|
10
10
|
when :string then
|
11
11
|
val.is_a?(String) ? val : val.to_s
|
@@ -23,7 +23,8 @@ module Mongoo
|
|
23
23
|
val.is_a?(Hash) ? val : raise(InvalidAttributeValue, val.inspect)
|
24
24
|
when :time then
|
25
25
|
Time.parse(val.to_s)
|
26
|
-
|
26
|
+
when :db_ref then
|
27
|
+
val.is_a?(BSON::DBRef) ? val : BSON::DBRef.new(val.collection.name, val.id)
|
27
28
|
when :bool then
|
28
29
|
if [true,false].include?(val)
|
29
30
|
val
|
data/lib/mongoo/modifiers.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Mongoo
|
2
2
|
class ModifierUpdateError < Exception; end
|
3
3
|
class UnknownAttributeError < Exception; end
|
4
|
-
|
4
|
+
|
5
5
|
class ModifierBuilder
|
6
6
|
def initialize(opts, doc)
|
7
7
|
@opts = opts
|
@@ -9,145 +9,160 @@ module Mongoo
|
|
9
9
|
@queue = {}
|
10
10
|
@key_prefix = opts[:key_prefix] || ""
|
11
11
|
end
|
12
|
-
|
13
|
-
def
|
14
|
-
|
15
|
-
raise UnknownAttributeError, "#{@key_prefix}#{k}"
|
16
|
-
end
|
12
|
+
|
13
|
+
def known_attribute?(k)
|
14
|
+
@doc.known_attribute?("#{@key_prefix}#{k}")
|
17
15
|
end
|
18
|
-
|
16
|
+
|
19
17
|
def sanitize_value(k,v)
|
20
18
|
k = "#{@key_prefix}#{k}"
|
21
|
-
|
22
|
-
|
19
|
+
if known_attribute?(k)
|
20
|
+
field_type = @doc.class.attributes[k][:type]
|
21
|
+
Mongoo::AttributeSanitizer.sanitize(field_type, v)
|
22
|
+
else
|
23
|
+
v
|
24
|
+
end
|
23
25
|
end
|
24
|
-
|
26
|
+
|
25
27
|
def inc(k, v=1)
|
26
|
-
ensure_valid_field!(k)
|
27
28
|
v = sanitize_value(k,v)
|
28
29
|
@queue["$inc"] ||= {}
|
29
30
|
@queue["$inc"]["#{@key_prefix}#{k}"] = v
|
30
31
|
end
|
31
|
-
|
32
|
+
|
32
33
|
def set(k,v)
|
33
|
-
ensure_valid_field!(k)
|
34
34
|
v = sanitize_value(k,v)
|
35
35
|
@queue["$set"] ||= {}
|
36
36
|
@queue["$set"]["#{@key_prefix}#{k}"] = v
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def unset(k)
|
40
|
-
ensure_valid_field!(k)
|
41
40
|
@queue["$unset"] ||= {}
|
42
41
|
@queue["$unset"]["#{@key_prefix}#{k}"] = 1
|
43
42
|
end
|
44
43
|
|
45
44
|
def push(k, v)
|
46
|
-
ensure_valid_field!(k)
|
47
45
|
@queue["$push"] ||= {}
|
48
46
|
@queue["$push"]["#{@key_prefix}#{k}"] = v
|
49
47
|
end
|
50
|
-
|
48
|
+
|
51
49
|
def push_all(k, v)
|
52
|
-
ensure_valid_field!(k)
|
53
50
|
@queue["$pushAll"] ||= {}
|
54
51
|
@queue["$pushAll"]["#{@key_prefix}#{k}"] = v
|
55
52
|
end
|
56
|
-
|
53
|
+
|
57
54
|
def add_to_set(k,v)
|
58
|
-
ensure_valid_field!(k)
|
59
55
|
@queue["$addToSet"] ||= {}
|
60
56
|
@queue["$addToSet"]["#{@key_prefix}#{k}"] = v
|
61
57
|
end
|
62
|
-
|
58
|
+
|
63
59
|
def pop(k)
|
64
|
-
ensure_valid_field!(k)
|
65
60
|
@queue["$pop"] ||= {}
|
66
61
|
@queue["$pop"]["#{@key_prefix}#{k}"] = 1
|
67
62
|
end
|
68
|
-
|
63
|
+
|
69
64
|
def pull(k, v)
|
70
|
-
ensure_valid_field!(k)
|
71
65
|
@queue["$pull"] ||= {}
|
72
66
|
@queue["$pull"]["#{@key_prefix}#{k}"] = v
|
73
67
|
end
|
74
|
-
|
68
|
+
|
75
69
|
def pull_all(k, v)
|
76
|
-
ensure_valid_field!(k)
|
77
70
|
@queue["$pullAll"] ||= {}
|
78
71
|
@queue["$pullAll"]["#{@key_prefix}#{k}"] = v
|
79
72
|
end
|
80
|
-
|
73
|
+
|
81
74
|
def run!
|
82
75
|
if @queue.blank?
|
83
76
|
raise ModifierUpdateError, "modifier update queue is empty"
|
84
77
|
end
|
85
|
-
|
86
|
-
|
78
|
+
|
79
|
+
update_query = { "_id" => @doc.id }
|
80
|
+
if @opts[:only_if_current] == true
|
87
81
|
@queue.each do |op, op_queue|
|
88
|
-
op_queue.each do |k,
|
89
|
-
|
90
|
-
when "$inc" then
|
91
|
-
new_val = @doc.persisted_mongohash.dot_get(k).to_i + v
|
92
|
-
@doc.mongohash.dot_set( k, new_val )
|
93
|
-
@doc.persisted_mongohash.dot_set( k, new_val )
|
94
|
-
when "$set" then
|
95
|
-
@doc.mongohash.dot_set( k, v )
|
96
|
-
@doc.persisted_mongohash.dot_set( k, v )
|
97
|
-
when "$unset" then
|
98
|
-
@doc.mongohash.dot_delete( k )
|
99
|
-
@doc.persisted_mongohash.dot_delete( k )
|
100
|
-
when "$push" then
|
101
|
-
new_val = (@doc.persisted_mongohash.dot_get(k) || []) + [v]
|
102
|
-
@doc.mongohash.dot_set( k, new_val )
|
103
|
-
@doc.persisted_mongohash.dot_set( k, new_val )
|
104
|
-
when "$pushAll" then
|
105
|
-
new_val = (@doc.persisted_mongohash.dot_get(k) || []) + v
|
106
|
-
@doc.mongohash.dot_set( k, new_val )
|
107
|
-
@doc.persisted_mongohash.dot_set( k, new_val )
|
108
|
-
when "$addToSet" then
|
109
|
-
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
110
|
-
new_val << v unless new_val.include?(v)
|
111
|
-
@doc.mongohash.dot_set(k, new_val)
|
112
|
-
@doc.persisted_mongohash.dot_set(k, new_val)
|
113
|
-
when "$pop" then
|
114
|
-
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
115
|
-
new_val.pop
|
116
|
-
@doc.mongohash.dot_set(k, new_val)
|
117
|
-
@doc.persisted_mongohash.dot_set(k, new_val)
|
118
|
-
when "$pull" then
|
119
|
-
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
120
|
-
new_val.delete(v)
|
121
|
-
@doc.mongohash.dot_set(k, new_val)
|
122
|
-
@doc.persisted_mongohash.dot_set(k, new_val)
|
123
|
-
when "$pullAll" then
|
124
|
-
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
125
|
-
v.each do |val|
|
126
|
-
new_val.delete(val)
|
127
|
-
end
|
128
|
-
@doc.mongohash.dot_set(k, new_val)
|
129
|
-
@doc.persisted_mongohash.dot_set(k, new_val)
|
130
|
-
end
|
82
|
+
op_queue.each do |k,v|
|
83
|
+
update_query[k] = @doc.persisted_mongohash.dot_get(k)
|
131
84
|
end
|
132
85
|
end
|
133
|
-
|
134
|
-
|
135
|
-
raise ModifierUpdateError, ret.inspect
|
86
|
+
@opts[:update_opts] ||= {}
|
87
|
+
@opts[:update_opts][:safe] = true
|
136
88
|
end
|
89
|
+
|
90
|
+
if @opts[:find_and_modify]
|
91
|
+
ret = @doc.collection.find_and_modify(query: update_query,
|
92
|
+
update: @queue,
|
93
|
+
new: true)
|
94
|
+
@doc.reload(ret)
|
95
|
+
else
|
96
|
+
update_opts = @opts.delete(:update_opts) || {}
|
97
|
+
ret = @doc.collection.update(update_query, @queue, update_opts)
|
98
|
+
if !ret.is_a?(Hash) || (ret["err"] == nil && ret["n"] == 1)
|
99
|
+
@queue.each do |op, op_queue|
|
100
|
+
op_queue.each do |k, v|
|
101
|
+
case op
|
102
|
+
when "$inc" then
|
103
|
+
new_val = @doc.persisted_mongohash.dot_get(k).to_i + v
|
104
|
+
@doc.mongohash.dot_set( k, new_val )
|
105
|
+
@doc.persisted_mongohash.dot_set( k, new_val )
|
106
|
+
when "$set" then
|
107
|
+
@doc.mongohash.dot_set( k, v )
|
108
|
+
@doc.persisted_mongohash.dot_set( k, v )
|
109
|
+
when "$unset" then
|
110
|
+
@doc.mongohash.dot_delete( k )
|
111
|
+
@doc.persisted_mongohash.dot_delete( k )
|
112
|
+
when "$push" then
|
113
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || []) + [v]
|
114
|
+
@doc.mongohash.dot_set( k, new_val )
|
115
|
+
@doc.persisted_mongohash.dot_set( k, new_val )
|
116
|
+
when "$pushAll" then
|
117
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || []) + v
|
118
|
+
@doc.mongohash.dot_set( k, new_val )
|
119
|
+
@doc.persisted_mongohash.dot_set( k, new_val )
|
120
|
+
when "$addToSet" then
|
121
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
122
|
+
new_val << v unless new_val.include?(v)
|
123
|
+
@doc.mongohash.dot_set(k, new_val)
|
124
|
+
@doc.persisted_mongohash.dot_set(k, new_val)
|
125
|
+
when "$pop" then
|
126
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
127
|
+
new_val.pop
|
128
|
+
@doc.mongohash.dot_set(k, new_val)
|
129
|
+
@doc.persisted_mongohash.dot_set(k, new_val)
|
130
|
+
when "$pull" then
|
131
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
132
|
+
new_val.delete(v)
|
133
|
+
@doc.mongohash.dot_set(k, new_val)
|
134
|
+
@doc.persisted_mongohash.dot_set(k, new_val)
|
135
|
+
when "$pullAll" then
|
136
|
+
new_val = (@doc.persisted_mongohash.dot_get(k) || [])
|
137
|
+
v.each do |val|
|
138
|
+
new_val.delete(val)
|
139
|
+
end
|
140
|
+
@doc.mongohash.dot_set(k, new_val)
|
141
|
+
@doc.persisted_mongohash.dot_set(k, new_val)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end # @queue.each
|
145
|
+
true
|
146
|
+
else
|
147
|
+
raise ModifierUpdateError, ret.inspect
|
148
|
+
end
|
149
|
+
end # if opts[:find_any_modify]
|
137
150
|
end
|
138
151
|
end
|
139
|
-
|
152
|
+
|
140
153
|
module Modifiers
|
141
|
-
|
154
|
+
|
142
155
|
def mod(opts={}, &block)
|
143
156
|
builder = ModifierBuilder.new(opts, self)
|
144
157
|
block.call(builder)
|
145
158
|
builder.run!
|
146
159
|
end
|
147
|
-
|
160
|
+
|
148
161
|
def mod!(opts={}, &block)
|
149
|
-
|
162
|
+
opts[:update_opts] ||= {}
|
163
|
+
opts[:update_opts][:safe] = true
|
164
|
+
mod(opts, &block)
|
150
165
|
end
|
151
|
-
|
166
|
+
|
152
167
|
end
|
153
168
|
end
|
data/lib/mongoo/persistence.rb
CHANGED
@@ -205,21 +205,30 @@ module Mongoo
|
|
205
205
|
update_hash = build_update_hash(self.changelog)
|
206
206
|
return true if update_hash.empty?
|
207
207
|
update_query_hash = build_update_query_hash(persisted_mongohash.to_key_value, self.changelog)
|
208
|
+
|
208
209
|
if Mongoo.verbose_debug
|
209
210
|
puts "\n* update_query_hash: #{update_query_hash.inspect}\n update_hash: #{update_hash.inspect}\n opts: #{opts.inspect}\n"
|
210
211
|
end
|
211
|
-
|
212
|
-
if
|
213
|
-
|
214
|
-
|
215
|
-
|
212
|
+
|
213
|
+
if opts.delete(:find_and_modify) == true
|
214
|
+
ret = self.collection.find_and_modify(query: update_query_hash,
|
215
|
+
update: update_hash,
|
216
|
+
new: true)
|
217
|
+
reload(ret)
|
216
218
|
else
|
217
|
-
|
218
|
-
|
219
|
+
ret = self.collection.update(update_query_hash, update_hash, opts)
|
220
|
+
if !ret.is_a?(Hash) || (ret["updatedExisting"] && ret["n"] == 1)
|
221
|
+
set_persisted_mongohash(mongohash)
|
222
|
+
@persisted = true
|
223
|
+
true
|
219
224
|
else
|
220
|
-
|
225
|
+
if opts[:only_if_current]
|
226
|
+
raise StaleUpdateError, ret.inspect
|
227
|
+
else
|
228
|
+
raise UpdateError, ret.inspect
|
229
|
+
end
|
221
230
|
end
|
222
|
-
end
|
231
|
+
end # if opts.delete(:find_and_modify)
|
223
232
|
end
|
224
233
|
end
|
225
234
|
|
@@ -255,8 +264,9 @@ module Mongoo
|
|
255
264
|
remove(opts.merge(:safe => true))
|
256
265
|
end
|
257
266
|
|
258
|
-
def reload
|
259
|
-
|
267
|
+
def reload(new_doc=nil)
|
268
|
+
new_doc ||= collection.find_one(get("_id"))
|
269
|
+
init_from_hash(new_doc)
|
260
270
|
@persisted = true
|
261
271
|
set_persisted_mongohash(mongohash)
|
262
272
|
true
|
data/mongoo.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mongoo}
|
8
|
-
s.version = "0.4.
|
8
|
+
s.version = "0.4.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ben Myles"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-06-06}
|
13
13
|
s.description = %q{Simple object mapper for MongoDB}
|
14
14
|
s.email = %q{ben.myles@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -47,7 +47,7 @@ Gem::Specification.new do |s|
|
|
47
47
|
s.homepage = %q{http://github.com/benmyles/mongoo}
|
48
48
|
s.licenses = ["MIT"]
|
49
49
|
s.require_paths = ["lib"]
|
50
|
-
s.rubygems_version = %q{1.6.
|
50
|
+
s.rubygems_version = %q{1.6.1}
|
51
51
|
s.summary = %q{Object mapper for MongoDB}
|
52
52
|
s.test_files = [
|
53
53
|
"test/helper.rb",
|
data/test/test_mongoo.rb
CHANGED
@@ -229,14 +229,6 @@ class TestMongoo < Test::Unit::TestCase
|
|
229
229
|
assert_equal ["snowboarding", "travelling"], p.interests
|
230
230
|
end
|
231
231
|
|
232
|
-
should "not be able to modify fields that don't exist" do
|
233
|
-
p = Person.new("name" => "Ben", "visits" => 0)
|
234
|
-
p.insert!
|
235
|
-
assert_raise(Mongoo::UnknownAttributeError) do
|
236
|
-
p.mod! { |mod| mod.push("idontexist", "foobar") }
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
232
|
should "be able to access a hash type directly" do
|
241
233
|
p = Person.new("name" => "Ben")
|
242
234
|
p.insert!
|
@@ -351,5 +343,75 @@ class TestMongoo < Test::Unit::TestCase
|
|
351
343
|
p.reload
|
352
344
|
assert_equal ["skydiving", "coding", "swimming"], p.interests
|
353
345
|
end
|
346
|
+
|
347
|
+
should "still do set/unset updates on granular attributes on a hash field" do
|
348
|
+
p = Person.new(name: "Ben", interests: ["skydiving", "coding"], misc: { foo: { bar: 1, zar: 2 } })
|
349
|
+
p.insert!
|
350
|
+
p.misc['foo']['zar'] = 3
|
351
|
+
assert_equal [[:set, "misc.foo.zar", 3]], p.changelog
|
352
|
+
end
|
353
|
+
|
354
|
+
should "be able to apply modifiers on hash attribute values" do
|
355
|
+
p = Person.new(name: "Ben", interests: ["skydiving", "coding"], misc: { foo: { bar: 1, zar: 2 } })
|
356
|
+
p.insert!
|
357
|
+
p.mod { |m| m.inc 'misc.foo.zar', 2 }
|
358
|
+
assert_equal 4, p.misc['foo']['zar']
|
359
|
+
p.reload
|
360
|
+
assert_equal 4, p.misc['foo']['zar']
|
361
|
+
end
|
362
|
+
|
363
|
+
should "be able to abort modifier update if there are stale values" do
|
364
|
+
p = Person.new(name: "Ben", interests: ["skydiving", "coding"], misc: { foo: { bar: 1, zar: 2 } })
|
365
|
+
p.insert!
|
366
|
+
p.mod { |m| m.inc 'misc.foo.zar', 2 }
|
367
|
+
|
368
|
+
p2 = Person.find_one(p.id)
|
369
|
+
p2.mod { |m| m.inc 'misc.foo.zar', 2 }
|
370
|
+
assert_equal 6, p2.misc['foo']['zar']
|
371
|
+
|
372
|
+
assert_raise(Mongoo::ModifierUpdateError) do
|
373
|
+
p.mod(only_if_current: true) { |m| m.inc 'misc.foo.zar', 1 }
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
should "be able to do a find_and_modify when using modifiers" do
|
378
|
+
p = Person.new(name: "Ben", interests: ["skydiving", "coding"], misc: { foo: { bar: 1, zar: 2 } })
|
379
|
+
p.insert!
|
380
|
+
p.mod { |m| m.inc 'misc.foo.zar', 2 }
|
381
|
+
|
382
|
+
p2 = Person.find_one(p.id)
|
383
|
+
p2.mod { |m| m.inc 'misc.foo.zar', 2 }
|
384
|
+
assert_equal 6, p2.misc['foo']['zar']
|
385
|
+
|
386
|
+
p.mod { |m| m.inc 'misc.foo.zar', 1 }
|
387
|
+
assert_equal 5, p.misc['foo']['zar']
|
388
|
+
|
389
|
+
# but if we do a find_and_modify ....
|
390
|
+
|
391
|
+
p = Person.new(name: "Ben", interests: ["skydiving", "coding"], misc: { foo: { bar: 1, zar: 2 } })
|
392
|
+
p.insert!
|
393
|
+
p.mod { |m| m.inc 'misc.foo.zar', 2 }
|
394
|
+
|
395
|
+
p2 = Person.find_one(p.id)
|
396
|
+
p2.mod { |m| m.inc 'misc.foo.zar', 2 }
|
397
|
+
assert_equal 6, p2.misc['foo']['zar']
|
398
|
+
|
399
|
+
p.mod(find_and_modify: true) { |m| m.inc 'misc.foo.zar', 1 }
|
400
|
+
assert_equal 7, p.misc['foo']['zar']
|
401
|
+
end
|
402
|
+
|
403
|
+
should "be able to do an update using find_and_modify" do
|
404
|
+
p = Person.new(name: "Ben", interests: ["skydiving", "coding"])
|
405
|
+
p.insert!
|
406
|
+
|
407
|
+
p2 = Person.find_one(p.id)
|
408
|
+
p2.mod! { |m| m.push "interests", "swimming" }
|
409
|
+
|
410
|
+
assert_equal ["skydiving","coding"], p.interests
|
411
|
+
p.name = "Ben Myles"
|
412
|
+
p.update!(find_and_modify: true)
|
413
|
+
assert_equal "Ben Myles", p.name
|
414
|
+
assert_equal ["skydiving", "coding", "swimming"], p.interests
|
415
|
+
end
|
354
416
|
end
|
355
417
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: mongoo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.4.
|
5
|
+
version: 0.4.5
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ben Myles
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-06-06 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -184,7 +184,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
184
184
|
requirements:
|
185
185
|
- - ">="
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
hash:
|
187
|
+
hash: 728381716729290434
|
188
188
|
segments:
|
189
189
|
- 0
|
190
190
|
version: "0"
|
@@ -197,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
197
197
|
requirements: []
|
198
198
|
|
199
199
|
rubyforge_project:
|
200
|
-
rubygems_version: 1.6.
|
200
|
+
rubygems_version: 1.6.1
|
201
201
|
signing_key:
|
202
202
|
specification_version: 3
|
203
203
|
summary: Object mapper for MongoDB
|