mrkurt-versioned 0.1.0 → 0.1.1
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/.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
|