lib/versioned.rb in mrkurt-versioned-0.1.0 vs lib/versioned.rb in mrkurt-versioned-0.1.1
- old
+ new
@@ -1,16 +1,68 @@
require 'version'
module Versioned
+ class StaleDocumentError < MongoMapper::MongoMapperError; end
def self.included(base)
base.extend ClassMethods
base.class_eval do
versioned
end
end
+ module LockingInstanceMethods
+ private
+ #new? isn't working
+ def is_new_document?
+ (read_attribute(self.version_lock_key).blank? && changes[self.version_lock_key.to_s].blank?) ||
+ (changes[self.version_lock_key.to_s] && changes[self.version_lock_key.to_s].first.blank?)
+ end
+ def prep_lock_version
+ old = read_attribute(self.version_lock_key)
+ if !is_new_document? || old.blank?
+ v = (Time.now.to_f * 1000).ceil.to_s
+ write_attribute self.version_lock_key, v
+ end
+
+ old
+ end
+
+ def save_to_collection(options = {})
+ current_version = prep_lock_version
+ if is_new_document?
+ collection.insert(to_mongo, :safe => true)
+ else
+ selector = { :_id => read_attribute(:_id), self.version_lock_key => current_version }
+ #can't upsert, safe must be true for this to work
+ result = collection.update(selector, to_mongo, :upsert => false, :safe => true)
+
+ if result.is_a?(Array) && result[0][0]['updatedExisting'] == false
+ write_attribute self.version_lock_key, current_version
+ raise StaleDocumentError.new
+ elsif !result.is_a?(Array)
+ #wtf?
+ write_attribute self.version_lock_key, current_version
+ raise "Unexpected result from mongo"
+ end
+
+ selector[:_id]
+ end
+ end
+ end
module ClassMethods
+ def locking!(options = {})
+ include(LockingInstanceMethods)
+ class_inheritable_accessor :version_lock_key
+ self.version_lock_key = options[:key] || :lock_version
+ key self.version_lock_key, Integer
+
+ if self.respond_to?(:version_use_key)
+ self.version_use_key = self.version_lock_key
+ (self.version_except_columns ||= []) << self.version_lock_key.to_s #don't version the lock key
+ end
+ end
+
def versioned(options = {})
class_inheritable_accessor :version_only_columns
self.version_only_columns = Array(options[:only]).map(&:to_s).uniq if options[:only]
class_inheritable_accessor :version_except_columns
self.version_except_columns = Array(options[:except]).map(&:to_s).uniq if options[:except]
@@ -57,10 +109,11 @@
after_update :create_version, :if => :needs_version?
include InstanceMethods
alias_method_chain :reload, :versions
end
+
end
module InstanceMethods
private
def versioned_columns
@@ -135,11 +188,11 @@
changes
end
end
def revert
- revert_to self.version -1
+ revert_to self.versions.at(self.version).previous
end
def retrieve_version n
versions.find_by_number(n).changes.each do |n,v|
self.send("#{n.to_sym}=",v.first)
@@ -163,10 +216,10 @@
reset_version if saved = save
saved
end
def latest_changes
- return {} if version.nil? || version == 1
+ return {} if version.nil?
versions.at(version).changes
end
end
end