mrkurt-versioned 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/VERSION +1 -1
- data/lib/version.rb +16 -0
- data/lib/versioned.rb +55 -2
- data/mrkurt-versioned.gemspec +67 -0
- data/test/lock_test.rb +91 -0
- data/test/schema.rb +19 -0
- data/test/specified_version_key_test.rb +3 -2
- metadata +6 -2
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/lib/version.rb
CHANGED
@@ -17,4 +17,20 @@ class Version
|
|
17
17
|
def <=>(other)
|
18
18
|
number <=> other.number
|
19
19
|
end
|
20
|
+
|
21
|
+
def previous
|
22
|
+
find_related(:first, :number => {:$lt => number}, :order => 'number.desc')
|
23
|
+
end
|
24
|
+
|
25
|
+
def next
|
26
|
+
find_related(:first, :number => {:$gt => number}, :order => 'number.asc')
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def find_related(*args)
|
32
|
+
options = args.extract_options!
|
33
|
+
params = options.merge(:versioned_id => versioned_id, :versioned_type => versioned_type)
|
34
|
+
self.class.find(args.first, params)
|
35
|
+
end
|
20
36
|
end
|
data/lib/versioned.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'version'
|
2
2
|
|
3
3
|
module Versioned
|
4
|
+
class StaleDocumentError < MongoMapper::MongoMapperError; end
|
4
5
|
def self.included(base)
|
5
6
|
base.extend ClassMethods
|
6
7
|
base.class_eval do
|
@@ -8,7 +9,58 @@ module Versioned
|
|
8
9
|
end
|
9
10
|
end
|
10
11
|
|
12
|
+
module LockingInstanceMethods
|
13
|
+
private
|
14
|
+
#new? isn't working
|
15
|
+
def is_new_document?
|
16
|
+
(read_attribute(self.version_lock_key).blank? && changes[self.version_lock_key.to_s].blank?) ||
|
17
|
+
(changes[self.version_lock_key.to_s] && changes[self.version_lock_key.to_s].first.blank?)
|
18
|
+
end
|
19
|
+
def prep_lock_version
|
20
|
+
old = read_attribute(self.version_lock_key)
|
21
|
+
if !is_new_document? || old.blank?
|
22
|
+
v = (Time.now.to_f * 1000).ceil.to_s
|
23
|
+
write_attribute self.version_lock_key, v
|
24
|
+
end
|
25
|
+
|
26
|
+
old
|
27
|
+
end
|
28
|
+
|
29
|
+
def save_to_collection(options = {})
|
30
|
+
current_version = prep_lock_version
|
31
|
+
if is_new_document?
|
32
|
+
collection.insert(to_mongo, :safe => true)
|
33
|
+
else
|
34
|
+
selector = { :_id => read_attribute(:_id), self.version_lock_key => current_version }
|
35
|
+
#can't upsert, safe must be true for this to work
|
36
|
+
result = collection.update(selector, to_mongo, :upsert => false, :safe => true)
|
37
|
+
|
38
|
+
if result.is_a?(Array) && result[0][0]['updatedExisting'] == false
|
39
|
+
write_attribute self.version_lock_key, current_version
|
40
|
+
raise StaleDocumentError.new
|
41
|
+
elsif !result.is_a?(Array)
|
42
|
+
#wtf?
|
43
|
+
write_attribute self.version_lock_key, current_version
|
44
|
+
raise "Unexpected result from mongo"
|
45
|
+
end
|
46
|
+
|
47
|
+
selector[:_id]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
11
51
|
module ClassMethods
|
52
|
+
def locking!(options = {})
|
53
|
+
include(LockingInstanceMethods)
|
54
|
+
class_inheritable_accessor :version_lock_key
|
55
|
+
self.version_lock_key = options[:key] || :lock_version
|
56
|
+
key self.version_lock_key, Integer
|
57
|
+
|
58
|
+
if self.respond_to?(:version_use_key)
|
59
|
+
self.version_use_key = self.version_lock_key
|
60
|
+
(self.version_except_columns ||= []) << self.version_lock_key.to_s #don't version the lock key
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
12
64
|
def versioned(options = {})
|
13
65
|
class_inheritable_accessor :version_only_columns
|
14
66
|
self.version_only_columns = Array(options[:only]).map(&:to_s).uniq if options[:only]
|
@@ -59,6 +111,7 @@ module Versioned
|
|
59
111
|
include InstanceMethods
|
60
112
|
alias_method_chain :reload, :versions
|
61
113
|
end
|
114
|
+
|
62
115
|
end
|
63
116
|
|
64
117
|
module InstanceMethods
|
@@ -137,7 +190,7 @@ module Versioned
|
|
137
190
|
end
|
138
191
|
|
139
192
|
def revert
|
140
|
-
revert_to self.version
|
193
|
+
revert_to self.versions.at(self.version).previous
|
141
194
|
end
|
142
195
|
|
143
196
|
def retrieve_version n
|
@@ -165,7 +218,7 @@ module Versioned
|
|
165
218
|
end
|
166
219
|
|
167
220
|
def latest_changes
|
168
|
-
return {} if version.nil?
|
221
|
+
return {} if version.nil?
|
169
222
|
versions.at(version).changes
|
170
223
|
end
|
171
224
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{mrkurt-versioned}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["twoism", "toastyapps", "jacqui", "mrkurt"]
|
12
|
+
s.date = %q{2010-01-16}
|
13
|
+
s.description = %q{Versioning for MongoMapper}
|
14
|
+
s.email = %q{mrkurt@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"lib/version.rb",
|
24
|
+
"lib/versioned.rb",
|
25
|
+
"mrkurt-versioned.gemspec",
|
26
|
+
"pkg/versioned-0.1.0.gem",
|
27
|
+
"test/between_test.rb",
|
28
|
+
"test/changes_test.rb",
|
29
|
+
"test/comparable_test.rb",
|
30
|
+
"test/creation_test.rb",
|
31
|
+
"test/latest_changes_test.rb",
|
32
|
+
"test/lock_test.rb",
|
33
|
+
"test/revert_test.rb",
|
34
|
+
"test/schema.rb",
|
35
|
+
"test/specified_version_key_test.rb",
|
36
|
+
"test/test_helper.rb",
|
37
|
+
"versioned.gemspec"
|
38
|
+
]
|
39
|
+
s.homepage = %q{http://github.com/mrkurt/versioned}
|
40
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
41
|
+
s.require_paths = ["lib"]
|
42
|
+
s.rubygems_version = %q{1.3.5}
|
43
|
+
s.summary = %q{Versioning for MongoMapper}
|
44
|
+
s.test_files = [
|
45
|
+
"test/test_helper.rb",
|
46
|
+
"test/between_test.rb",
|
47
|
+
"test/comparable_test.rb",
|
48
|
+
"test/revert_test.rb",
|
49
|
+
"test/creation_test.rb",
|
50
|
+
"test/latest_changes_test.rb",
|
51
|
+
"test/specified_version_key_test.rb",
|
52
|
+
"test/schema.rb",
|
53
|
+
"test/lock_test.rb",
|
54
|
+
"test/changes_test.rb"
|
55
|
+
]
|
56
|
+
|
57
|
+
if s.respond_to? :specification_version then
|
58
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
59
|
+
s.specification_version = 3
|
60
|
+
|
61
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
62
|
+
else
|
63
|
+
end
|
64
|
+
else
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
data/test/lock_test.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class LockTest < Test::Unit::TestCase
|
4
|
+
context 'An unversioned model with locks' do
|
5
|
+
setup do
|
6
|
+
@user = UnversionedLockableUser.create(:name => 'Kurt')
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'have a lock_version field' do
|
10
|
+
assert_not_nil @user.lock_version
|
11
|
+
end
|
12
|
+
|
13
|
+
should 'save just fine when no conflicts' do
|
14
|
+
@user.name = 'Bob'
|
15
|
+
assert @user.save
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'save just fine when given the proper lock version' do
|
19
|
+
u = UnversionedLockableUser.find(@user.id)
|
20
|
+
@user.update_attributes(:name => 'Bill')
|
21
|
+
|
22
|
+
assert u.update_attributes(:name => 'Jose', :lock_version => @user.lock_version)
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'not save when given the wrong version' do
|
26
|
+
assert_raise Versioned::StaleDocumentError do
|
27
|
+
@user.update_attributes(:name => 'Bob', :lock_version => 1111)
|
28
|
+
end
|
29
|
+
|
30
|
+
# lock_version should match what we passed in
|
31
|
+
assert_equal 1111, @user.lock_version
|
32
|
+
end
|
33
|
+
end
|
34
|
+
context 'A versioned model with locks' do
|
35
|
+
setup do
|
36
|
+
@user = LockableUser.create(:name => 'Kurt', :required_field => 'woo!')
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'have a lock_version field' do
|
40
|
+
assert_not_nil @user.lock_version
|
41
|
+
assert_equal @user.version, @user.lock_version
|
42
|
+
end
|
43
|
+
|
44
|
+
should 'save just fine when no conflicts' do
|
45
|
+
@user.name = 'Bob'
|
46
|
+
assert @user.save
|
47
|
+
end
|
48
|
+
|
49
|
+
should 'save just fine when given the proper lock version' do
|
50
|
+
u = LockableUser.find(@user.id)
|
51
|
+
@user.update_attributes(:name => 'Bill')
|
52
|
+
|
53
|
+
assert u.update_attributes(:name => 'Jose', :lock_version => @user.lock_version)
|
54
|
+
end
|
55
|
+
|
56
|
+
should 'not save when given the wrong version' do
|
57
|
+
assert_raise Versioned::StaleDocumentError do
|
58
|
+
@user.update_attributes(:name => 'Bob', :lock_version => 1111)
|
59
|
+
end
|
60
|
+
|
61
|
+
# lock_version should match what we passed in
|
62
|
+
assert_equal 1111, @user.lock_version
|
63
|
+
end
|
64
|
+
|
65
|
+
should 'be revertable with the lock version' do
|
66
|
+
v = @user.lock_version
|
67
|
+
name = @user.name
|
68
|
+
@user.update_attributes(:name => "Schlub")
|
69
|
+
|
70
|
+
assert_not_equal v, @user.lock_version
|
71
|
+
|
72
|
+
@user.revert_to(v)
|
73
|
+
|
74
|
+
assert_equal name, @user.name
|
75
|
+
assert_not_equal v, @user.lock_version #shouldn't have reverted version
|
76
|
+
end
|
77
|
+
|
78
|
+
should 'accept a specified version on create' do
|
79
|
+
u = LockableUser.create(:name => 'Burt', :required_field => 'woo!', :lock_version => 1111)
|
80
|
+
assert_equal 1111, u.lock_version
|
81
|
+
end
|
82
|
+
|
83
|
+
should "have same lock_version when validation fails" do
|
84
|
+
@user.required_field = nil
|
85
|
+
v = @user.lock_version
|
86
|
+
result = @user.save
|
87
|
+
assert !result
|
88
|
+
assert_equal v, @user.lock_version
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/test/schema.rb
CHANGED
@@ -32,5 +32,24 @@ class Loser
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
class LockableUser
|
36
|
+
include MongoMapper::Document
|
37
|
+
include Versioned
|
38
|
+
locking!
|
39
|
+
|
40
|
+
key :name, String
|
41
|
+
key :required_field, String
|
42
|
+
validates_presence_of :required_field
|
43
|
+
end
|
44
|
+
|
45
|
+
class UnversionedLockableUser
|
46
|
+
include MongoMapper::Document
|
47
|
+
extend Versioned::ClassMethods
|
48
|
+
locking!
|
49
|
+
|
50
|
+
key :name, String
|
51
|
+
end
|
52
|
+
|
35
53
|
User.destroy_all
|
54
|
+
Loser.destroy_all
|
36
55
|
Version.destroy_all
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class SpecifiedVersionKey < Test::Unit::TestCase
|
4
|
-
context 'A specified version key' do
|
4
|
+
context 'A model with a specified version key' do
|
5
5
|
setup do
|
6
6
|
@name = "Blah"
|
7
7
|
@loser = Loser.create(:name => @name)
|
@@ -38,7 +38,8 @@ class SpecifiedVersionKey < Test::Unit::TestCase
|
|
38
38
|
end
|
39
39
|
|
40
40
|
should 'revert properly' do
|
41
|
-
@loser.
|
41
|
+
@loser.revert
|
42
|
+
@loser.save!
|
42
43
|
assert_equal @initial_name, @loser.name
|
43
44
|
assert_equal @count + 1, @loser.versions.count
|
44
45
|
assert_not_equal @version, @loser.version
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mrkurt-versioned
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- twoism
|
@@ -12,7 +12,7 @@ autorequire:
|
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
14
|
|
15
|
-
date: 2010-01-
|
15
|
+
date: 2010-01-16 00:00:00 -06:00
|
16
16
|
default_executable:
|
17
17
|
dependencies: []
|
18
18
|
|
@@ -25,17 +25,20 @@ extensions: []
|
|
25
25
|
extra_rdoc_files:
|
26
26
|
- README.rdoc
|
27
27
|
files:
|
28
|
+
- .gitignore
|
28
29
|
- README.rdoc
|
29
30
|
- Rakefile
|
30
31
|
- VERSION
|
31
32
|
- lib/version.rb
|
32
33
|
- lib/versioned.rb
|
34
|
+
- mrkurt-versioned.gemspec
|
33
35
|
- pkg/versioned-0.1.0.gem
|
34
36
|
- test/between_test.rb
|
35
37
|
- test/changes_test.rb
|
36
38
|
- test/comparable_test.rb
|
37
39
|
- test/creation_test.rb
|
38
40
|
- test/latest_changes_test.rb
|
41
|
+
- test/lock_test.rb
|
39
42
|
- test/revert_test.rb
|
40
43
|
- test/schema.rb
|
41
44
|
- test/specified_version_key_test.rb
|
@@ -78,4 +81,5 @@ test_files:
|
|
78
81
|
- test/latest_changes_test.rb
|
79
82
|
- test/specified_version_key_test.rb
|
80
83
|
- test/schema.rb
|
84
|
+
- test/lock_test.rb
|
81
85
|
- test/changes_test.rb
|