lib/mongoo/modifiers.rb in mongoo-0.4.4 vs lib/mongoo/modifiers.rb in mongoo-0.4.5

- old
+ new

@@ -1,153 +1,168 @@ module Mongoo class ModifierUpdateError < Exception; end class UnknownAttributeError < Exception; end - + class ModifierBuilder def initialize(opts, doc) @opts = opts @doc = doc @queue = {} @key_prefix = opts[:key_prefix] || "" end - - def ensure_valid_field!(k) - unless @doc.known_attribute?("#{@key_prefix}#{k}") - raise UnknownAttributeError, "#{@key_prefix}#{k}" - end + + def known_attribute?(k) + @doc.known_attribute?("#{@key_prefix}#{k}") end - + def sanitize_value(k,v) k = "#{@key_prefix}#{k}" - field_type = @doc.class.attributes[k][:type] - Mongoo::AttributeSanitizer.sanitize(field_type, v) + if known_attribute?(k) + field_type = @doc.class.attributes[k][:type] + Mongoo::AttributeSanitizer.sanitize(field_type, v) + else + v + end end - + def inc(k, v=1) - ensure_valid_field!(k) v = sanitize_value(k,v) @queue["$inc"] ||= {} @queue["$inc"]["#{@key_prefix}#{k}"] = v end - + def set(k,v) - ensure_valid_field!(k) v = sanitize_value(k,v) @queue["$set"] ||= {} @queue["$set"]["#{@key_prefix}#{k}"] = v end - + def unset(k) - ensure_valid_field!(k) @queue["$unset"] ||= {} @queue["$unset"]["#{@key_prefix}#{k}"] = 1 end def push(k, v) - ensure_valid_field!(k) @queue["$push"] ||= {} @queue["$push"]["#{@key_prefix}#{k}"] = v end - + def push_all(k, v) - ensure_valid_field!(k) @queue["$pushAll"] ||= {} @queue["$pushAll"]["#{@key_prefix}#{k}"] = v end - + def add_to_set(k,v) - ensure_valid_field!(k) @queue["$addToSet"] ||= {} @queue["$addToSet"]["#{@key_prefix}#{k}"] = v end - + def pop(k) - ensure_valid_field!(k) @queue["$pop"] ||= {} @queue["$pop"]["#{@key_prefix}#{k}"] = 1 end - + def pull(k, v) - ensure_valid_field!(k) @queue["$pull"] ||= {} @queue["$pull"]["#{@key_prefix}#{k}"] = v end - + def pull_all(k, v) - ensure_valid_field!(k) @queue["$pullAll"] ||= {} @queue["$pullAll"]["#{@key_prefix}#{k}"] = v end - + def run! if @queue.blank? raise ModifierUpdateError, "modifier update queue is empty" end - ret = @doc.collection.update({"_id" => @doc.id}, @queue, @opts) - if !ret.is_a?(Hash) || (ret["err"] == nil && ret["n"] == 1) + + update_query = { "_id" => @doc.id } + if @opts[:only_if_current] == true @queue.each do |op, op_queue| - op_queue.each do |k, v| - case op - when "$inc" then - new_val = @doc.persisted_mongohash.dot_get(k).to_i + v - @doc.mongohash.dot_set( k, new_val ) - @doc.persisted_mongohash.dot_set( k, new_val ) - when "$set" then - @doc.mongohash.dot_set( k, v ) - @doc.persisted_mongohash.dot_set( k, v ) - when "$unset" then - @doc.mongohash.dot_delete( k ) - @doc.persisted_mongohash.dot_delete( k ) - when "$push" then - new_val = (@doc.persisted_mongohash.dot_get(k) || []) + [v] - @doc.mongohash.dot_set( k, new_val ) - @doc.persisted_mongohash.dot_set( k, new_val ) - when "$pushAll" then - new_val = (@doc.persisted_mongohash.dot_get(k) || []) + v - @doc.mongohash.dot_set( k, new_val ) - @doc.persisted_mongohash.dot_set( k, new_val ) - when "$addToSet" then - new_val = (@doc.persisted_mongohash.dot_get(k) || []) - new_val << v unless new_val.include?(v) - @doc.mongohash.dot_set(k, new_val) - @doc.persisted_mongohash.dot_set(k, new_val) - when "$pop" then - new_val = (@doc.persisted_mongohash.dot_get(k) || []) - new_val.pop - @doc.mongohash.dot_set(k, new_val) - @doc.persisted_mongohash.dot_set(k, new_val) - when "$pull" then - new_val = (@doc.persisted_mongohash.dot_get(k) || []) - new_val.delete(v) - @doc.mongohash.dot_set(k, new_val) - @doc.persisted_mongohash.dot_set(k, new_val) - when "$pullAll" then - new_val = (@doc.persisted_mongohash.dot_get(k) || []) - v.each do |val| - new_val.delete(val) - end - @doc.mongohash.dot_set(k, new_val) - @doc.persisted_mongohash.dot_set(k, new_val) - end + op_queue.each do |k,v| + update_query[k] = @doc.persisted_mongohash.dot_get(k) end end - true - else - raise ModifierUpdateError, ret.inspect + @opts[:update_opts] ||= {} + @opts[:update_opts][:safe] = true end + + if @opts[:find_and_modify] + ret = @doc.collection.find_and_modify(query: update_query, + update: @queue, + new: true) + @doc.reload(ret) + else + update_opts = @opts.delete(:update_opts) || {} + ret = @doc.collection.update(update_query, @queue, update_opts) + if !ret.is_a?(Hash) || (ret["err"] == nil && ret["n"] == 1) + @queue.each do |op, op_queue| + op_queue.each do |k, v| + case op + when "$inc" then + new_val = @doc.persisted_mongohash.dot_get(k).to_i + v + @doc.mongohash.dot_set( k, new_val ) + @doc.persisted_mongohash.dot_set( k, new_val ) + when "$set" then + @doc.mongohash.dot_set( k, v ) + @doc.persisted_mongohash.dot_set( k, v ) + when "$unset" then + @doc.mongohash.dot_delete( k ) + @doc.persisted_mongohash.dot_delete( k ) + when "$push" then + new_val = (@doc.persisted_mongohash.dot_get(k) || []) + [v] + @doc.mongohash.dot_set( k, new_val ) + @doc.persisted_mongohash.dot_set( k, new_val ) + when "$pushAll" then + new_val = (@doc.persisted_mongohash.dot_get(k) || []) + v + @doc.mongohash.dot_set( k, new_val ) + @doc.persisted_mongohash.dot_set( k, new_val ) + when "$addToSet" then + new_val = (@doc.persisted_mongohash.dot_get(k) || []) + new_val << v unless new_val.include?(v) + @doc.mongohash.dot_set(k, new_val) + @doc.persisted_mongohash.dot_set(k, new_val) + when "$pop" then + new_val = (@doc.persisted_mongohash.dot_get(k) || []) + new_val.pop + @doc.mongohash.dot_set(k, new_val) + @doc.persisted_mongohash.dot_set(k, new_val) + when "$pull" then + new_val = (@doc.persisted_mongohash.dot_get(k) || []) + new_val.delete(v) + @doc.mongohash.dot_set(k, new_val) + @doc.persisted_mongohash.dot_set(k, new_val) + when "$pullAll" then + new_val = (@doc.persisted_mongohash.dot_get(k) || []) + v.each do |val| + new_val.delete(val) + end + @doc.mongohash.dot_set(k, new_val) + @doc.persisted_mongohash.dot_set(k, new_val) + end + end + end # @queue.each + true + else + raise ModifierUpdateError, ret.inspect + end + end # if opts[:find_any_modify] end end - + module Modifiers - + def mod(opts={}, &block) builder = ModifierBuilder.new(opts, self) block.call(builder) builder.run! end - + def mod!(opts={}, &block) - mod(opts.merge(:safe => true), &block) + opts[:update_opts] ||= {} + opts[:update_opts][:safe] = true + mod(opts, &block) end - + end end \ No newline at end of file