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 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