mongoo 0.4.4 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.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
- # val.is_a?(Time) ? val : Time.parse(val)
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
@@ -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 ensure_valid_field!(k)
14
- unless @doc.known_attribute?("#{@key_prefix}#{k}")
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
- field_type = @doc.class.attributes[k][:type]
22
- Mongoo::AttributeSanitizer.sanitize(field_type, v)
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
- ret = @doc.collection.update({"_id" => @doc.id}, @queue, @opts)
86
- if !ret.is_a?(Hash) || (ret["err"] == nil && ret["n"] == 1)
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, v|
89
- case op
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
- true
134
- else
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
- mod(opts.merge(:safe => true), &block)
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
@@ -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
- ret = self.collection.update(update_query_hash, update_hash, opts)
212
- if !ret.is_a?(Hash) || (ret["updatedExisting"] && ret["n"] == 1)
213
- set_persisted_mongohash(mongohash)
214
- @persisted = true
215
- true
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
- if opts[:only_if_current]
218
- raise StaleUpdateError, ret.inspect
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
- raise UpdateError, ret.inspect
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
- init_from_hash(collection.find_one(get("_id")))
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.3"
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-05-29}
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.2}
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.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-05-29 00:00:00 -07:00
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: 2962169118481187052
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.2
200
+ rubygems_version: 1.6.1
201
201
  signing_key:
202
202
  specification_version: 3
203
203
  summary: Object mapper for MongoDB