mongoid_versioning 0.0.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.
- checksums.yaml +7 -0
- data/.gitignore +34 -0
- data/.travis.yml +15 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +106 -0
- data/Guardfile +8 -0
- data/LICENSE +22 -0
- data/README.md +94 -0
- data/Rakefile +9 -0
- data/lib/mongoid_versioning/version.rb +3 -0
- data/lib/mongoid_versioning/versioned.rb +123 -0
- data/lib/mongoid_versioning.rb +5 -0
- data/mongoid_versioning.gemspec +30 -0
- data/test/mongoid_versioning/versioned_test.rb +299 -0
- data/test/test_helper.rb +45 -0
- metadata +172 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 1541712ab768cbdfe3e5feff620d363e15f26c36
|
|
4
|
+
data.tar.gz: 502a9f2582215937f32dc231a1bfe92bebe4d68f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b36237f72a53a2d07d660c65a3bcfa67e41c9d665b6a4e8616795f070f44be2c06cdc41f6306b02650612afd5407ecc179c615a8e43cfe5f8b6eada0744794f6
|
|
7
|
+
data.tar.gz: 73460dbb43b06e4235288c944ac2d1d62411d726bab2afedeb7fd5136528018f6aaf2b6a4bce9f2ab8201075b507339da1cc13a93c42983c88ff3f4c84d80439
|
data/.gitignore
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/test/tmp/
|
|
9
|
+
/test/version_tmp/
|
|
10
|
+
/tmp/
|
|
11
|
+
|
|
12
|
+
## Specific to RubyMotion:
|
|
13
|
+
.dat*
|
|
14
|
+
.repl_history
|
|
15
|
+
build/
|
|
16
|
+
|
|
17
|
+
## Documentation cache and generated files:
|
|
18
|
+
/.yardoc/
|
|
19
|
+
/_yardoc/
|
|
20
|
+
/doc/
|
|
21
|
+
/rdoc/
|
|
22
|
+
|
|
23
|
+
## Environment normalisation:
|
|
24
|
+
/.bundle/
|
|
25
|
+
/lib/bundler/man/
|
|
26
|
+
|
|
27
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
28
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
29
|
+
# Gemfile.lock
|
|
30
|
+
# .ruby-version
|
|
31
|
+
# .ruby-gemset
|
|
32
|
+
|
|
33
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
34
|
+
.rvmrc
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
mongoid_versioning (0.0.1)
|
|
5
|
+
mongoid (~> 4.0)
|
|
6
|
+
|
|
7
|
+
GEM
|
|
8
|
+
remote: https://rubygems.org/
|
|
9
|
+
specs:
|
|
10
|
+
activemodel (4.1.6)
|
|
11
|
+
activesupport (= 4.1.6)
|
|
12
|
+
builder (~> 3.1)
|
|
13
|
+
activesupport (4.1.6)
|
|
14
|
+
i18n (~> 0.6, >= 0.6.9)
|
|
15
|
+
json (~> 1.7, >= 1.7.7)
|
|
16
|
+
minitest (~> 5.1)
|
|
17
|
+
thread_safe (~> 0.1)
|
|
18
|
+
tzinfo (~> 1.1)
|
|
19
|
+
bson (2.3.0)
|
|
20
|
+
builder (3.2.2)
|
|
21
|
+
celluloid (0.16.0)
|
|
22
|
+
timers (~> 4.0.0)
|
|
23
|
+
coderay (1.1.0)
|
|
24
|
+
connection_pool (2.0.0)
|
|
25
|
+
coveralls (0.7.1)
|
|
26
|
+
multi_json (~> 1.3)
|
|
27
|
+
rest-client
|
|
28
|
+
simplecov (>= 0.7)
|
|
29
|
+
term-ansicolor
|
|
30
|
+
thor
|
|
31
|
+
database_cleaner (1.3.0)
|
|
32
|
+
docile (1.1.5)
|
|
33
|
+
ffi (1.9.5)
|
|
34
|
+
formatador (0.2.5)
|
|
35
|
+
guard (2.6.1)
|
|
36
|
+
formatador (>= 0.2.4)
|
|
37
|
+
listen (~> 2.7)
|
|
38
|
+
lumberjack (~> 1.0)
|
|
39
|
+
pry (>= 0.9.12)
|
|
40
|
+
thor (>= 0.18.1)
|
|
41
|
+
guard-minitest (2.3.2)
|
|
42
|
+
guard (~> 2.0)
|
|
43
|
+
minitest (>= 3.0)
|
|
44
|
+
hitimes (1.2.2)
|
|
45
|
+
i18n (0.6.11)
|
|
46
|
+
json (1.8.1)
|
|
47
|
+
listen (2.7.11)
|
|
48
|
+
celluloid (>= 0.15.2)
|
|
49
|
+
rb-fsevent (>= 0.9.3)
|
|
50
|
+
rb-inotify (>= 0.9)
|
|
51
|
+
lumberjack (1.0.9)
|
|
52
|
+
method_source (0.8.2)
|
|
53
|
+
mime-types (2.4.1)
|
|
54
|
+
minitest (5.4.2)
|
|
55
|
+
mongoid (4.0.0)
|
|
56
|
+
activemodel (~> 4.0)
|
|
57
|
+
moped (~> 2.0.0)
|
|
58
|
+
origin (~> 2.1)
|
|
59
|
+
tzinfo (>= 0.3.37)
|
|
60
|
+
moped (2.0.0)
|
|
61
|
+
bson (~> 2.2)
|
|
62
|
+
connection_pool (~> 2.0)
|
|
63
|
+
optionable (~> 0.2.0)
|
|
64
|
+
multi_json (1.10.1)
|
|
65
|
+
netrc (0.7.7)
|
|
66
|
+
optionable (0.2.0)
|
|
67
|
+
origin (2.1.1)
|
|
68
|
+
pry (0.10.1)
|
|
69
|
+
coderay (~> 1.1.0)
|
|
70
|
+
method_source (~> 0.8.1)
|
|
71
|
+
slop (~> 3.4)
|
|
72
|
+
rake (10.3.2)
|
|
73
|
+
rb-fsevent (0.9.4)
|
|
74
|
+
rb-inotify (0.9.5)
|
|
75
|
+
ffi (>= 0.5.0)
|
|
76
|
+
rest-client (1.7.2)
|
|
77
|
+
mime-types (>= 1.16, < 3.0)
|
|
78
|
+
netrc (~> 0.7)
|
|
79
|
+
simplecov (0.9.1)
|
|
80
|
+
docile (~> 1.1.0)
|
|
81
|
+
multi_json (~> 1.0)
|
|
82
|
+
simplecov-html (~> 0.8.0)
|
|
83
|
+
simplecov-html (0.8.0)
|
|
84
|
+
slop (3.6.0)
|
|
85
|
+
term-ansicolor (1.3.0)
|
|
86
|
+
tins (~> 1.0)
|
|
87
|
+
thor (0.19.1)
|
|
88
|
+
thread_safe (0.3.4)
|
|
89
|
+
timers (4.0.1)
|
|
90
|
+
hitimes
|
|
91
|
+
tins (1.3.3)
|
|
92
|
+
tzinfo (1.2.2)
|
|
93
|
+
thread_safe (~> 0.1)
|
|
94
|
+
|
|
95
|
+
PLATFORMS
|
|
96
|
+
ruby
|
|
97
|
+
|
|
98
|
+
DEPENDENCIES
|
|
99
|
+
bundler (~> 1.3)
|
|
100
|
+
coveralls
|
|
101
|
+
database_cleaner
|
|
102
|
+
guard
|
|
103
|
+
guard-minitest
|
|
104
|
+
minitest
|
|
105
|
+
mongoid_versioning!
|
|
106
|
+
rake
|
data/Guardfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Tomas Celizna
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Mongoid Versioning
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/tomasc/mongoid_versioning) [](http://badge.fury.io/rb/mongoid_versioning) [](https://coveralls.io/r/tomasc/mongoid_versioning)
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'mongoid_versioning'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
$ bundle
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or install it yourself as:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
$ gem install mongoid_versioning
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
Include the `MongoidVersioning::Versioned` module into your model:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
class MyVersionedDocument
|
|
31
|
+
include Mongoid::Document
|
|
32
|
+
include MongoidVersioning::Versioned
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Your class will then have:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
field :_version, type: Integer
|
|
40
|
+
field :_based_on_version, type: Integer
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Creating versions
|
|
44
|
+
|
|
45
|
+
To create new version of your document:
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
doc = MyVersionedDocument.new
|
|
49
|
+
doc.revise # => true
|
|
50
|
+
doc._version # => 1
|
|
51
|
+
doc._based_on_version # => nil
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The `#revise` method validates the document and runs `:revise`, `:save` and `:update` callbacks (resp. `:revise`, `:save` and `:create` for new record).
|
|
55
|
+
|
|
56
|
+
### Retrieving versions
|
|
57
|
+
|
|
58
|
+
To access all previous versions:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
doc.previous_versions # => Mongoid::Criteria
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
These versions are stored in separate collection, by default named by appending `.versions` to name of the source collection. In the above example it is `my_versioned_documents.versions`.
|
|
65
|
+
|
|
66
|
+
To access latest version (as stored in the db):
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
doc.latest_version # => MyVersionedDocument
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
To retrieve all versions of a document:
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
doc.versions # => Array
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
To retrieve specific version:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
doc.version(2) # => MyVersionedDocument
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Further Reading
|
|
85
|
+
|
|
86
|
+
See [Further Thoughts on How to Track Versions with MongoDB](http://askasya.com/post/revisitversions).
|
|
87
|
+
|
|
88
|
+
## Contributing
|
|
89
|
+
|
|
90
|
+
1. Fork it ( https://github.com/tomasc/mongoid_versioning/fork )
|
|
91
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
92
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
93
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
94
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
module MongoidVersioning
|
|
2
|
+
module Versioned
|
|
3
|
+
|
|
4
|
+
def self.included base
|
|
5
|
+
base.extend ClassMethods
|
|
6
|
+
base.class_eval do
|
|
7
|
+
define_model_callbacks :revise, only: [:before, :after]
|
|
8
|
+
|
|
9
|
+
field :_version, type: Integer
|
|
10
|
+
field :_based_on_version, type: Integer
|
|
11
|
+
|
|
12
|
+
collection.database[versions_collection_name].indexes.create(
|
|
13
|
+
{ _orig_id: 1, _version: 1 }, { unique: true }
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
after_initialize :revert_id
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# =====================================================================
|
|
21
|
+
|
|
22
|
+
module ClassMethods
|
|
23
|
+
def versions_collection_name
|
|
24
|
+
[collection.name, 'versions'].join('.')
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# =====================================================================
|
|
29
|
+
|
|
30
|
+
def revise options={}
|
|
31
|
+
if new_record?
|
|
32
|
+
!_create_revised(options).new_record?
|
|
33
|
+
else
|
|
34
|
+
_update_revised(options)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# ---------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
def versions
|
|
41
|
+
[latest_version].concat(previous_versions)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def latest_version
|
|
45
|
+
self.class.where(_id: id).first
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def previous_versions
|
|
49
|
+
self.class.with(collection: self.class.versions_collection_name).
|
|
50
|
+
where(_orig_id: id).
|
|
51
|
+
lt(_version: _version).
|
|
52
|
+
desc(:_version)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def version v
|
|
56
|
+
return latest_version if v == _version
|
|
57
|
+
previous_versions.where(_version: v).first
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private # =============================================================
|
|
61
|
+
|
|
62
|
+
def revert_id
|
|
63
|
+
return unless self['_orig_id']
|
|
64
|
+
self._id = self['_orig_id']
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# these mirror the #create and #save methods from Mongoid
|
|
68
|
+
def _create_revised options={}
|
|
69
|
+
return self if performing_validations?(options) && invalid?(:create)
|
|
70
|
+
result = run_callbacks(:revise) do
|
|
71
|
+
run_callbacks(:save) do
|
|
72
|
+
run_callbacks(:create) do
|
|
73
|
+
_revise
|
|
74
|
+
true
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
post_process_persist(result, options) and self
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def _update_revised options={}
|
|
82
|
+
return false if performing_validations?(options) && invalid?(:update)
|
|
83
|
+
process_flagged_destroys
|
|
84
|
+
result = run_callbacks(:revise) do
|
|
85
|
+
run_callbacks(:save) do
|
|
86
|
+
run_callbacks(:update) do
|
|
87
|
+
_revise
|
|
88
|
+
true
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
post_process_persist(result, options) and self
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def _revise
|
|
96
|
+
previous_version = nil
|
|
97
|
+
|
|
98
|
+
# 1. get the latest version as stored in the db
|
|
99
|
+
if previous_doc = self.class.collection.find({ _id: id }).first
|
|
100
|
+
|
|
101
|
+
previous_version = previous_doc["_version"] || 1
|
|
102
|
+
|
|
103
|
+
previous_doc['_orig_id'] = previous_doc['_id']
|
|
104
|
+
previous_doc['_id'] = BSON::ObjectId.new
|
|
105
|
+
previous_doc['_version'] = previous_version
|
|
106
|
+
|
|
107
|
+
# 2. upsert the latest version into the .versions collection
|
|
108
|
+
self.class.collection.database[self.class.versions_collection_name].where(_orig_id: id, _version: previous_version).upsert(previous_doc)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# 3. insert new version
|
|
112
|
+
self._based_on_version = _version || previous_version
|
|
113
|
+
self._version = previous_version.to_i+1
|
|
114
|
+
|
|
115
|
+
self.class.collection.where(_id: id).upsert(self.as_document)
|
|
116
|
+
|
|
117
|
+
# TODO
|
|
118
|
+
# if (result.nModified != 1) {
|
|
119
|
+
# print("Someone got there first, replay flow to try again");
|
|
120
|
+
# }
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'mongoid_versioning/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "mongoid_versioning"
|
|
8
|
+
spec.version = MongoidVersioning::VERSION
|
|
9
|
+
spec.authors = ["Tomas Celizna"]
|
|
10
|
+
spec.email = ["tomas.celizna@gmail.com"]
|
|
11
|
+
spec.description = %q{Versioning Mongoid documents by means of separate collection.}
|
|
12
|
+
spec.summary = %q{Versioning Mongoid documents by means of separate collection.}
|
|
13
|
+
spec.homepage = "https://github.com/tomasc/mongoid_versioning"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files`.split($/)
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_dependency "mongoid", "~> 4.0"
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
|
24
|
+
spec.add_development_dependency "coveralls"
|
|
25
|
+
spec.add_development_dependency "database_cleaner"
|
|
26
|
+
spec.add_development_dependency "guard"
|
|
27
|
+
spec.add_development_dependency "guard-minitest"
|
|
28
|
+
spec.add_development_dependency "minitest"
|
|
29
|
+
spec.add_development_dependency "rake"
|
|
30
|
+
end
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class TestDocument
|
|
4
|
+
include Mongoid::Document
|
|
5
|
+
include MongoidVersioning::Versioned
|
|
6
|
+
|
|
7
|
+
attr_accessor :callbacks
|
|
8
|
+
|
|
9
|
+
field :name, type: String
|
|
10
|
+
|
|
11
|
+
validates :name, presence: true
|
|
12
|
+
|
|
13
|
+
before_revise -> i { i.callbacks = i.callbacks << 'before_revise' }
|
|
14
|
+
after_revise -> i { i.callbacks = i.callbacks << 'after_revise' }
|
|
15
|
+
before_save -> i { i.callbacks = i.callbacks << 'before_save' }
|
|
16
|
+
after_save -> i { i.callbacks = i.callbacks << 'after_save' }
|
|
17
|
+
before_update -> i { i.callbacks = i.callbacks << 'before_update' }
|
|
18
|
+
after_update -> i { i.callbacks = i.callbacks << 'after_update' }
|
|
19
|
+
before_create -> i { i.callbacks = i.callbacks << 'before_create' }
|
|
20
|
+
after_create -> i { i.callbacks = i.callbacks << 'after_create' }
|
|
21
|
+
|
|
22
|
+
def callbacks
|
|
23
|
+
@callbacks ||= []
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module MongoidVersioning
|
|
28
|
+
describe Versioned do
|
|
29
|
+
|
|
30
|
+
subject { TestDocument.new(name: 'Init') }
|
|
31
|
+
|
|
32
|
+
# =====================================================================
|
|
33
|
+
|
|
34
|
+
describe 'fields' do
|
|
35
|
+
it 'has :_version' do
|
|
36
|
+
subject.must_respond_to :_version
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'has :_based_on_version' do
|
|
40
|
+
subject.must_respond_to :_based_on_version
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# =====================================================================
|
|
45
|
+
|
|
46
|
+
describe 'class methods' do
|
|
47
|
+
describe '.versions_collection_name' do
|
|
48
|
+
it 'infers name for version collection' do
|
|
49
|
+
subject.class.versions_collection_name.must_equal "#{subject.collection.name}.versions"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# =====================================================================
|
|
55
|
+
|
|
56
|
+
describe 'instance methods' do
|
|
57
|
+
describe '#revise' do
|
|
58
|
+
|
|
59
|
+
describe 'when invalid' do
|
|
60
|
+
let(:invalid_document) { TestDocument.new }
|
|
61
|
+
|
|
62
|
+
it 'returns false' do
|
|
63
|
+
invalid_document.revise.must_equal false
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe 'new record' do
|
|
68
|
+
before do
|
|
69
|
+
subject.callbacks = []
|
|
70
|
+
subject.revise
|
|
71
|
+
|
|
72
|
+
@current_docs = TestDocument.collection.where({ _id: subject.id })
|
|
73
|
+
@version_docs = TestDocument.collection.database[TestDocument.versions_collection_name].where(_orig_id: subject.id)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe 'callbacks' do
|
|
77
|
+
it 'runs :revise, :save, :create' do
|
|
78
|
+
subject.callbacks.must_equal %w(before_revise before_save before_create after_create after_save after_revise)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe 'default collection' do
|
|
83
|
+
it 'stores the document' do
|
|
84
|
+
@current_docs.first.must_be :present?
|
|
85
|
+
end
|
|
86
|
+
it '_version to 1' do
|
|
87
|
+
@current_docs.first['_version'].must_equal 1
|
|
88
|
+
end
|
|
89
|
+
it '_based_on_version at nil' do
|
|
90
|
+
@current_docs.first['_based_on_version'].must_be_nil
|
|
91
|
+
end
|
|
92
|
+
it 'maintains only one current doc' do
|
|
93
|
+
@current_docs.count.must_equal 1
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe 'versions' do
|
|
98
|
+
it 'does not create any versions' do
|
|
99
|
+
@version_docs.count.must_equal 0
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# ---------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
describe 'existing record' do
|
|
107
|
+
let(:existing_document) { TestDocument.create(name: 'Init') }
|
|
108
|
+
|
|
109
|
+
before do
|
|
110
|
+
existing_document.callbacks = []
|
|
111
|
+
existing_document.name = 'Foo'
|
|
112
|
+
existing_document.revise
|
|
113
|
+
|
|
114
|
+
@current_docs = TestDocument.collection.where(_id: existing_document.id)
|
|
115
|
+
@version_docs = TestDocument.collection.database[TestDocument.versions_collection_name].where(_orig_id: existing_document.id)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
describe 'callbacks' do
|
|
119
|
+
it 'runs :revise, :save, :update' do
|
|
120
|
+
existing_document.callbacks.must_equal %w(before_revise before_save before_update after_update after_save after_revise)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
describe 'default collection' do
|
|
125
|
+
it 'updates the document' do
|
|
126
|
+
@current_docs.first['name'].must_equal 'Foo'
|
|
127
|
+
end
|
|
128
|
+
it '_version to 2' do
|
|
129
|
+
@current_docs.first['_version'].must_equal 2
|
|
130
|
+
end
|
|
131
|
+
it 'sets the _based_on_version to 1' do
|
|
132
|
+
@current_docs.first['_based_on_version'].must_equal 1
|
|
133
|
+
end
|
|
134
|
+
it 'maintains only one current doc' do
|
|
135
|
+
@current_docs.count.must_equal 1
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
describe 'previous versions' do
|
|
140
|
+
it 'copies the latest version to .versions' do
|
|
141
|
+
@version_docs.first.must_be :present?
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it '_version to 1' do
|
|
145
|
+
@version_docs.first['_version'].must_equal 1
|
|
146
|
+
end
|
|
147
|
+
it '_version to 1' do
|
|
148
|
+
@version_docs.first['_based_on_version'].must_equal nil
|
|
149
|
+
end
|
|
150
|
+
it 'is not updated' do
|
|
151
|
+
@version_docs.first['name'].wont_equal 'Foo'
|
|
152
|
+
end
|
|
153
|
+
it 'creates only one version' do
|
|
154
|
+
@version_docs.count.must_equal 1
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# ---------------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
describe 'subsequent revision' do
|
|
162
|
+
before do
|
|
163
|
+
subject.name = 'v1'
|
|
164
|
+
subject.revise
|
|
165
|
+
subject.name = 'v2'
|
|
166
|
+
subject.revise
|
|
167
|
+
subject.name = 'v3'
|
|
168
|
+
subject.revise
|
|
169
|
+
|
|
170
|
+
@current_docs = TestDocument.collection.where(_id: subject.id)
|
|
171
|
+
@version_docs = TestDocument.collection.database[TestDocument.versions_collection_name].where(_orig_id: subject.id)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
describe 'default collection' do
|
|
175
|
+
it 'updates the current document in the db' do
|
|
176
|
+
@current_docs.first['name'].must_equal 'v3'
|
|
177
|
+
@current_docs.first['_version'].must_equal 3
|
|
178
|
+
@current_docs.first['_based_on_version'].must_equal 2
|
|
179
|
+
@current_docs.count.must_equal 1
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
describe 'versions' do
|
|
184
|
+
it 'has 2 previous versions' do
|
|
185
|
+
@version_docs.count.must_equal 2
|
|
186
|
+
@version_docs.collect{ |i| i['_version'] }.must_equal [1,2]
|
|
187
|
+
@version_docs.collect{ |i| i['_based_on_version'] }.must_equal [nil,1]
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# ---------------------------------------------------------------------
|
|
193
|
+
|
|
194
|
+
describe 'revise on previous version' do
|
|
195
|
+
before do
|
|
196
|
+
subject.name = 'v1'
|
|
197
|
+
subject.revise
|
|
198
|
+
subject.name = 'v2'
|
|
199
|
+
subject.revise
|
|
200
|
+
subject.name = 'v3'
|
|
201
|
+
subject.revise
|
|
202
|
+
|
|
203
|
+
@new_version = subject.version(1)
|
|
204
|
+
@new_version.revise
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it 'saves reverted attribute' do
|
|
208
|
+
@new_version.name.must_equal 'v1'
|
|
209
|
+
end
|
|
210
|
+
it 'updates :_version' do
|
|
211
|
+
@new_version._version.must_equal 4
|
|
212
|
+
end
|
|
213
|
+
it 'updates :_based_on_version' do
|
|
214
|
+
@new_version._based_on_version.must_equal 1
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# =====================================================================
|
|
220
|
+
|
|
221
|
+
describe 'versions' do
|
|
222
|
+
before do
|
|
223
|
+
subject.name = 'v1'
|
|
224
|
+
subject.revise
|
|
225
|
+
subject.name = 'v2'
|
|
226
|
+
subject.revise
|
|
227
|
+
subject.name = 'v3'
|
|
228
|
+
subject.revise
|
|
229
|
+
subject.name = 'Foo'
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it 'returns an Array' do
|
|
233
|
+
subject.versions.must_be_kind_of Array
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# ---------------------------------------------------------------------
|
|
237
|
+
|
|
238
|
+
describe '#previous_versions' do
|
|
239
|
+
it 'returns everything but the latest' do
|
|
240
|
+
subject.previous_versions.map(&:_version).must_equal [2,1]
|
|
241
|
+
end
|
|
242
|
+
it 'correctly reverts document _ids' do
|
|
243
|
+
subject.previous_versions.map(&:id).uniq.must_equal [subject.id]
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# ---------------------------------------------------------------------
|
|
248
|
+
|
|
249
|
+
describe '#latest_version' do
|
|
250
|
+
it 'includes the latest version as in the database' do
|
|
251
|
+
subject.latest_version.name.wont_equal 'Foo'
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# ---------------------------------------------------------------------
|
|
256
|
+
|
|
257
|
+
describe '#versions' do
|
|
258
|
+
it 'returns all versions including the latest one' do
|
|
259
|
+
subject.versions.map(&:_version).must_equal [3,2,1]
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
# ---------------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
describe '#version' do
|
|
267
|
+
before do
|
|
268
|
+
subject.name = 'v1'
|
|
269
|
+
subject.revise
|
|
270
|
+
subject.name = 'v2'
|
|
271
|
+
subject.revise
|
|
272
|
+
subject.name = 'v3'
|
|
273
|
+
subject.revise
|
|
274
|
+
subject.name = 'Foo'
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
describe 'when latest version' do
|
|
278
|
+
it 'returns the version from db' do
|
|
279
|
+
subject.version(3)._version.must_equal 3
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
describe 'when previous version' do
|
|
284
|
+
it 'returns the version from db' do
|
|
285
|
+
subject.version(1)._version.must_equal 1
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
describe 'when version does not exist' do
|
|
290
|
+
it 'returns nil' do
|
|
291
|
+
subject.version(10).must_be_nil
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
end
|
|
299
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'bundler/setup'
|
|
2
|
+
require 'database_cleaner'
|
|
3
|
+
require 'minitest'
|
|
4
|
+
require 'minitest/autorun'
|
|
5
|
+
require 'minitest/spec'
|
|
6
|
+
require 'mongoid'
|
|
7
|
+
|
|
8
|
+
require 'mongoid_versioning'
|
|
9
|
+
|
|
10
|
+
# ---------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
if ENV["CI"]
|
|
13
|
+
require "coveralls"
|
|
14
|
+
Coveralls.wear!
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
ENV["MONGOID_TEST_HOST"] ||= "localhost"
|
|
18
|
+
ENV["MONGOID_TEST_PORT"] ||= "27017"
|
|
19
|
+
|
|
20
|
+
HOST = ENV["MONGOID_TEST_HOST"]
|
|
21
|
+
PORT = ENV["MONGOID_TEST_PORT"].to_i
|
|
22
|
+
|
|
23
|
+
def database_id
|
|
24
|
+
"mongoid_versioning_test"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
CONFIG = {
|
|
28
|
+
sessions: {
|
|
29
|
+
default: {
|
|
30
|
+
database: database_id,
|
|
31
|
+
hosts: [ "#{HOST}:#{PORT}" ]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
Mongoid.configure do |config|
|
|
37
|
+
config.load_configuration(CONFIG)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
DatabaseCleaner.orm = :mongoid
|
|
41
|
+
DatabaseCleaner.strategy = :truncation
|
|
42
|
+
|
|
43
|
+
class MiniTest::Spec
|
|
44
|
+
before(:each) { DatabaseCleaner.clean }
|
|
45
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: mongoid_versioning
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Tomas Celizna
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-12-30 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: mongoid
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '4.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '4.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.3'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.3'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: coveralls
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: database_cleaner
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: guard
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: guard-minitest
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: minitest
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rake
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
description: Versioning Mongoid documents by means of separate collection.
|
|
126
|
+
email:
|
|
127
|
+
- tomas.celizna@gmail.com
|
|
128
|
+
executables: []
|
|
129
|
+
extensions: []
|
|
130
|
+
extra_rdoc_files: []
|
|
131
|
+
files:
|
|
132
|
+
- ".gitignore"
|
|
133
|
+
- ".travis.yml"
|
|
134
|
+
- Gemfile
|
|
135
|
+
- Gemfile.lock
|
|
136
|
+
- Guardfile
|
|
137
|
+
- LICENSE
|
|
138
|
+
- README.md
|
|
139
|
+
- Rakefile
|
|
140
|
+
- lib/mongoid_versioning.rb
|
|
141
|
+
- lib/mongoid_versioning/version.rb
|
|
142
|
+
- lib/mongoid_versioning/versioned.rb
|
|
143
|
+
- mongoid_versioning.gemspec
|
|
144
|
+
- test/mongoid_versioning/versioned_test.rb
|
|
145
|
+
- test/test_helper.rb
|
|
146
|
+
homepage: https://github.com/tomasc/mongoid_versioning
|
|
147
|
+
licenses:
|
|
148
|
+
- MIT
|
|
149
|
+
metadata: {}
|
|
150
|
+
post_install_message:
|
|
151
|
+
rdoc_options: []
|
|
152
|
+
require_paths:
|
|
153
|
+
- lib
|
|
154
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
|
+
requirements:
|
|
156
|
+
- - ">="
|
|
157
|
+
- !ruby/object:Gem::Version
|
|
158
|
+
version: '0'
|
|
159
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
|
+
requirements:
|
|
161
|
+
- - ">="
|
|
162
|
+
- !ruby/object:Gem::Version
|
|
163
|
+
version: '0'
|
|
164
|
+
requirements: []
|
|
165
|
+
rubyforge_project:
|
|
166
|
+
rubygems_version: 2.2.2
|
|
167
|
+
signing_key:
|
|
168
|
+
specification_version: 4
|
|
169
|
+
summary: Versioning Mongoid documents by means of separate collection.
|
|
170
|
+
test_files:
|
|
171
|
+
- test/mongoid_versioning/versioned_test.rb
|
|
172
|
+
- test/test_helper.rb
|