mongoid-versioning 0.2.0 → 1.0.0.beta1
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/.travis.yml +20 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +2 -1
- data/README.md +2 -1
- data/Rakefile +3 -5
- data/gemfiles/mongoid_master.gemfile +8 -0
- data/lib/mongoid/config/locales/en.yml +11 -0
- data/lib/mongoid/core_ext/errors/versioning_not_on_root.rb +23 -0
- data/lib/mongoid/core_ext/fields/standard.rb +17 -0
- data/lib/mongoid/core_ext/fields/validators/macro.rb +11 -0
- data/lib/mongoid/core_ext/hierarchy.rb +25 -0
- data/lib/mongoid/core_ext/relations/bindings/embedded/many.rb +31 -0
- data/lib/mongoid/core_ext/relations/cascading.rb +23 -0
- data/lib/mongoid/core_ext/relations/embedded/batchable.rb +36 -0
- data/lib/mongoid/core_ext/relations/embedded/many.rb +24 -0
- data/lib/mongoid/core_ext/relations/macros.rb +39 -0
- data/lib/mongoid/core_ext/relations/metadata.rb +63 -0
- data/lib/mongoid/core_ext/relations/options.rb +9 -0
- data/lib/mongoid/core_ext/threaded/lifecycle.rb +37 -0
- data/lib/mongoid/core_ext/versioning.rb +218 -0
- data/lib/mongoid/versioning/version.rb +1 -1
- data/lib/mongoid/versioning.rb +16 -213
- data/mongoid-versioning.gemspec +2 -2
- data/spec/app/models/account.rb +0 -4
- data/spec/app/models/acolyte.rb +1 -1
- data/spec/app/models/address.rb +2 -2
- data/spec/app/models/appointment.rb +1 -1
- data/spec/app/models/article.rb +0 -3
- data/spec/app/models/building.rb +0 -2
- data/spec/app/models/building_address.rb +0 -2
- data/spec/app/models/contractor.rb +0 -2
- data/spec/app/models/dog.rb +1 -1
- data/spec/app/models/drug.rb +0 -2
- data/spec/app/models/event.rb +1 -1
- data/spec/app/models/game.rb +0 -2
- data/spec/app/models/house.rb +1 -2
- data/spec/app/models/item.rb +0 -4
- data/spec/app/models/name.rb +0 -2
- data/spec/app/models/paranoid_phone.rb +2 -0
- data/spec/app/models/paranoid_post.rb +3 -1
- data/spec/app/models/person.rb +3 -5
- data/spec/app/models/player.rb +2 -2
- data/spec/app/models/post.rb +2 -2
- data/spec/app/models/preference.rb +1 -1
- data/spec/app/models/quiz.rb +0 -3
- data/spec/app/models/registry.rb +1 -1
- data/spec/app/models/symptom.rb +1 -1
- data/spec/app/models/tree.rb +1 -1
- data/spec/app/models/video.rb +1 -5
- data/spec/app/models/wiki_page.rb +0 -2
- data/spec/config/mongoid.yml +0 -5
- data/spec/mongoid/errors/versioning_not_on_root_spec.rb +29 -0
- data/spec/mongoid/relations/macros_spec.rb +17 -0
- data/spec/mongoid/relations/metadata_spec.rb +50 -0
- data/spec/mongoid/versioning_spec.rb +2 -36
- data/spec/spec_helper.rb +4 -3
- metadata +44 -30
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e909070135c192cc4bbdd0c62416daed6d33d837
|
4
|
+
data.tar.gz: 2481913b87525fa8e554283d395ef52f189319af
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1528b23826c4709c66b7ea37649408040d2eb2a3f0748fb03094459a3f2f1ed887d7234822bab9310c6677122b0581913c3b17b4de04f57fe5e6cd29634e3981
|
7
|
+
data.tar.gz: fffbba7feefc13c2f2298cc23b7e935c9bbca28059705507d908449c1eb0ebcd5b3e69f79f210b571851ac7526ba38e4a3022659df9f348c76a82dea4431f1e3
|
data/.travis.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
3
|
+
rvm:
|
4
|
+
- 1.9.3
|
5
|
+
- 2.0.0
|
6
|
+
- 2.1.0
|
7
|
+
- ruby-head
|
8
|
+
|
9
|
+
gemfile:
|
10
|
+
- Gemfile
|
11
|
+
- gemfiles/mongoid_master.gemfile
|
12
|
+
|
13
|
+
branches:
|
14
|
+
only:
|
15
|
+
- master
|
16
|
+
|
17
|
+
matrix:
|
18
|
+
allow_failures:
|
19
|
+
- rvm: ruby-head
|
20
|
+
- gemfile: gemfiles/mongoid_master.gemfile
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# mongoid-versioning
|
1
|
+
# mongoid-versioning [](https://travis-ci.org/haihappen/mongoid-versioning)
|
2
|
+
|
2
3
|
**Important:** This gem is an extraction of [Mongoid::Versioning](http://mongoid.org/en/mongoid/docs/extras.html#versioning) from the official [mongoid](http://mongoid.org) gem. Since Mongoid::Versioning will be removed in the upcoming `4.0.0` release of mongoid, this gem re-enables the functionality of versioned documents.
|
3
4
|
|
4
5
|
**Please submit only bug and security fixes**. Neighter I will accept new features nor changes to exiting APIs. Please consider forking the project if you want new features to appear! :)
|
data/Rakefile
CHANGED
@@ -0,0 +1,11 @@
|
|
1
|
+
en:
|
2
|
+
mongoid:
|
3
|
+
errors:
|
4
|
+
messages:
|
5
|
+
versioning_not_on_root:
|
6
|
+
message: "Versioning not allowed on embedded document: %{klass}."
|
7
|
+
summary: "Mongoid::Versioning behaviour is only allowed on documents
|
8
|
+
that are the root document in the hierarchy."
|
9
|
+
resolution: "Remove the versioning from the embedded %{klass} or
|
10
|
+
consider moving it to a root location in the hierarchy if
|
11
|
+
versioning is needed."
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
module Errors
|
4
|
+
|
5
|
+
# This error is raised when attempting to version an embedded document.
|
6
|
+
class VersioningNotOnRoot < MongoidError
|
7
|
+
|
8
|
+
# Create the new error.
|
9
|
+
#
|
10
|
+
# @example Create the new error.
|
11
|
+
# VersioningNotOnRoot.new(Address)
|
12
|
+
#
|
13
|
+
# @param [ Class ] klass The embedded class.
|
14
|
+
#
|
15
|
+
# @since 3.0.0
|
16
|
+
def initialize(klass)
|
17
|
+
super(
|
18
|
+
compose_message("versioning_not_on_root", { klass: klass })
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Fields
|
3
|
+
class Standard
|
4
|
+
# Is this field included in versioned attributes?
|
5
|
+
#
|
6
|
+
# @example Is the field versioned?
|
7
|
+
# field.versioned?
|
8
|
+
#
|
9
|
+
# @return [ true, false ] If the field is included in versioning.
|
10
|
+
#
|
11
|
+
# @since 2.1.0
|
12
|
+
def versioned?
|
13
|
+
@versioned ||= (options[:versioned].nil? ? true : options[:versioned])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Hierarchy
|
3
|
+
# Collect all the children of this document.
|
4
|
+
#
|
5
|
+
# @example Collect all the children.
|
6
|
+
# document.collect_children
|
7
|
+
#
|
8
|
+
# @return [ Array<Document> ] The children.
|
9
|
+
#
|
10
|
+
# @since 2.4.0
|
11
|
+
def collect_children
|
12
|
+
children = []
|
13
|
+
embedded_relations.each_pair do |name, metadata|
|
14
|
+
without_autobuild do
|
15
|
+
child = send(name)
|
16
|
+
Array.wrap(child).each do |doc|
|
17
|
+
children.push(doc)
|
18
|
+
children.concat(doc._children) unless metadata.versioned?
|
19
|
+
end if child
|
20
|
+
end
|
21
|
+
end
|
22
|
+
children
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Relations
|
3
|
+
module Bindings
|
4
|
+
module Embedded
|
5
|
+
class Many < Binding
|
6
|
+
# Binds a single document with the inverse relation. Used
|
7
|
+
# specifically when appending to the proxy.
|
8
|
+
#
|
9
|
+
# @example Bind one document.
|
10
|
+
# person.addresses.bind_one(address)
|
11
|
+
#
|
12
|
+
# @param [ Document ] doc The single document to bind.
|
13
|
+
# @param [ Hash ] options The binding options.
|
14
|
+
#
|
15
|
+
# @option options [ true, false ] :continue Continue binding the inverse.
|
16
|
+
# @option options [ true, false ] :binding Are we in build mode?
|
17
|
+
#
|
18
|
+
# @since 2.0.0.rc.1
|
19
|
+
def bind_one(doc)
|
20
|
+
doc.parentize(base)
|
21
|
+
binding do
|
22
|
+
unless metadata.versioned?
|
23
|
+
doc.do_or_do_not(metadata.inverse_setter(target), base)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Relations
|
3
|
+
module Cascading
|
4
|
+
# Perform all cascading deletes, destroys, or nullifies. Will delegate to
|
5
|
+
# the appropriate strategy to perform the operation.
|
6
|
+
#
|
7
|
+
# @example Execute cascades.
|
8
|
+
# document.cascade!
|
9
|
+
#
|
10
|
+
# @since 2.0.0.rc.1
|
11
|
+
def cascade!
|
12
|
+
cascades.each do |name|
|
13
|
+
if !relation_metadata || !relation_metadata.versioned?
|
14
|
+
if meta = relations[name]
|
15
|
+
strategy = meta.cascade_strategy
|
16
|
+
strategy.new(self, meta).cascade if strategy
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Relations
|
3
|
+
module Embedded
|
4
|
+
module Batchable
|
5
|
+
# Pre process the batch removal.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
#
|
9
|
+
# @example Pre process the documents.
|
10
|
+
# batchable.pre_process_batch_remove(docs, :delete)
|
11
|
+
#
|
12
|
+
# @param [ Array<Document> ] docs The documents.
|
13
|
+
# @param [ Symbol ] method Delete or destroy.
|
14
|
+
#
|
15
|
+
# @return [ Array<Hash> ] The documents as hashes.
|
16
|
+
#
|
17
|
+
# @since 3.0.0
|
18
|
+
def pre_process_batch_remove(docs, method)
|
19
|
+
docs.map do |doc|
|
20
|
+
self.path = doc.atomic_path unless path
|
21
|
+
execute_callback :before_remove, doc
|
22
|
+
if !_assigning? && !metadata.versioned?
|
23
|
+
doc.cascade!
|
24
|
+
doc.run_before_callbacks(:destroy) if method == :destroy
|
25
|
+
end
|
26
|
+
target.delete_one(doc)
|
27
|
+
_unscoped.delete_one(doc)
|
28
|
+
unbind_one(doc)
|
29
|
+
execute_callback :after_remove, doc
|
30
|
+
doc.as_document
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Relations
|
3
|
+
module Embedded
|
4
|
+
class Many < Relations::Many
|
5
|
+
class << self
|
6
|
+
# Get the valid options allowed with this relation.
|
7
|
+
#
|
8
|
+
# @example Get the valid options.
|
9
|
+
# Relation.valid_options
|
10
|
+
#
|
11
|
+
# @return [ Array<Symbol> ] The valid options.
|
12
|
+
#
|
13
|
+
# @since 2.1.0
|
14
|
+
def valid_options
|
15
|
+
[
|
16
|
+
:as, :cascade_callbacks, :cyclic, :order, :versioned, :store_as,
|
17
|
+
:before_add, :after_add, :before_remove, :after_remove
|
18
|
+
]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Relations
|
3
|
+
module Macros
|
4
|
+
module ClassMethods
|
5
|
+
# Adds the relation back to the parent document. This macro is
|
6
|
+
# necessary to set the references from the child back to the parent
|
7
|
+
# document. If a child does not define this relation calling
|
8
|
+
# persistence methods on the child object will cause a save to fail.
|
9
|
+
#
|
10
|
+
# @example Define the relation.
|
11
|
+
#
|
12
|
+
# class Person
|
13
|
+
# include Mongoid::Document
|
14
|
+
# embeds_many :addresses
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# class Address
|
18
|
+
# include Mongoid::Document
|
19
|
+
# embedded_in :person
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# @param [ Symbol ] name The name of the relation.
|
23
|
+
# @param [ Hash ] options The relation options.
|
24
|
+
# @param [ Proc ] block Optional block for defining extensions.
|
25
|
+
def embedded_in(name, options = {}, &block)
|
26
|
+
if ancestors.include?(Mongoid::Versioning)
|
27
|
+
raise Errors::VersioningNotOnRoot.new(self)
|
28
|
+
end
|
29
|
+
meta = characterize(name, Embedded::In, options, &block)
|
30
|
+
self.embedded = true
|
31
|
+
relate(name, meta)
|
32
|
+
builder(name, meta).creator(name, meta)
|
33
|
+
add_counter_cache_callbacks(meta) if meta.counter_cached?
|
34
|
+
meta
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Relations
|
3
|
+
class Metadata < Hash
|
4
|
+
# Since a lot of the information from the metadata is inferred and not
|
5
|
+
# explicitly stored in the hash, the inspection needs to be much more
|
6
|
+
# detailed.
|
7
|
+
#
|
8
|
+
# @example Inspect the metadata.
|
9
|
+
# metadata.inspect
|
10
|
+
#
|
11
|
+
# @return [ String ] Oodles of information in a nice format.
|
12
|
+
#
|
13
|
+
# @since 2.0.0.rc.1
|
14
|
+
def inspect
|
15
|
+
%Q{#<Mongoid::Relations::Metadata
|
16
|
+
autobuild: #{autobuilding?}
|
17
|
+
class_name: #{class_name}
|
18
|
+
cyclic: #{cyclic.inspect}
|
19
|
+
counter_cache:#{counter_cached?}
|
20
|
+
dependent: #{dependent.inspect}
|
21
|
+
inverse_of: #{inverse_of.inspect}
|
22
|
+
key: #{key}
|
23
|
+
macro: #{macro}
|
24
|
+
name: #{name}
|
25
|
+
order: #{order.inspect}
|
26
|
+
polymorphic: #{polymorphic?}
|
27
|
+
relation: #{relation}
|
28
|
+
setter: #{setter}
|
29
|
+
versioned: #{versioned?}>
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Is this relation using Mongoid's internal versioning system?
|
34
|
+
#
|
35
|
+
# @example Is this relation versioned?
|
36
|
+
# metadata.versioned?
|
37
|
+
#
|
38
|
+
# @return [ true, false ] If the relation uses Mongoid versioning.
|
39
|
+
#
|
40
|
+
# @since 2.1.0
|
41
|
+
def versioned?
|
42
|
+
!!self[:versioned]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get the inverse relation candidates.
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
#
|
49
|
+
# @example Get the inverse relation candidates.
|
50
|
+
# metadata.inverse_relation_candidates
|
51
|
+
#
|
52
|
+
# @return [ Array<Metdata> ] The candidates.
|
53
|
+
#
|
54
|
+
# @since 3.0.0
|
55
|
+
def inverse_relation_candidates
|
56
|
+
relations_metadata.select do |meta|
|
57
|
+
next if meta.versioned? || meta.name == name
|
58
|
+
meta.class_name == inverse_class_name
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Threaded
|
3
|
+
module Lifecycle
|
4
|
+
private
|
5
|
+
# Execute a block in loading revision mode.
|
6
|
+
#
|
7
|
+
# @example Execute in loading revision mode.
|
8
|
+
# _loading_revision do
|
9
|
+
# load_revision
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# @return [ Object ] The return value of the block.
|
13
|
+
#
|
14
|
+
# @since 2.3.4
|
15
|
+
def _loading_revision
|
16
|
+
Threaded.begin_execution("load_revision")
|
17
|
+
yield
|
18
|
+
ensure
|
19
|
+
Threaded.exit_execution("load_revision")
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
# Is the current thread in loading revision mode?
|
24
|
+
#
|
25
|
+
# @example Is the current thread in loading revision mode?
|
26
|
+
# proxy._loading_revision?
|
27
|
+
#
|
28
|
+
# @return [ true, false ] If the thread is loading a revision.
|
29
|
+
#
|
30
|
+
# @since 2.3.4
|
31
|
+
def _loading_revision?
|
32
|
+
Threaded.executing?("load_revision")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mongoid
|
3
|
+
|
4
|
+
# Include this module to get automatic versioning of root level documents.
|
5
|
+
# This will add a version field to the +Document+ and a has_many association
|
6
|
+
# with all the versions contained in it.
|
7
|
+
module Versioning
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
field :version, type: Integer, default: 1
|
12
|
+
|
13
|
+
embeds_many \
|
14
|
+
:versions,
|
15
|
+
class_name: self.name,
|
16
|
+
validate: false,
|
17
|
+
cyclic: true,
|
18
|
+
inverse_of: nil,
|
19
|
+
versioned: true
|
20
|
+
|
21
|
+
set_callback :save, :before, :revise, if: :revisable?
|
22
|
+
|
23
|
+
class_attribute :version_max
|
24
|
+
self.cyclic = true
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create a new version of the +Document+. This will load the previous
|
28
|
+
# document from the database and set it as the next version before saving
|
29
|
+
# the current document. It then increments the version number. If a #max_versions
|
30
|
+
# limit is set in the model and it's exceeded, the oldest version gets discarded.
|
31
|
+
#
|
32
|
+
# @example Revise the document.
|
33
|
+
# person.revise
|
34
|
+
#
|
35
|
+
# @since 1.0.0
|
36
|
+
def revise
|
37
|
+
previous = previous_revision
|
38
|
+
if previous && versioned_attributes_changed?
|
39
|
+
new_version = versions.build(
|
40
|
+
previous.versioned_attributes
|
41
|
+
)
|
42
|
+
new_version._id = nil
|
43
|
+
if version_max.present? && versions.length > version_max
|
44
|
+
deleted = versions.first
|
45
|
+
if deleted.respond_to?(:paranoid?) && deleted.paranoid?
|
46
|
+
versions.delete_one(deleted)
|
47
|
+
collection.find(atomic_selector).
|
48
|
+
update({ "$pull" => { "versions" => { "version" => deleted.version }}})
|
49
|
+
else
|
50
|
+
versions.delete(deleted)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
self.version = (version || 1 ) + 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Forces the creation of a new version of the +Document+, regardless of
|
58
|
+
# whether a change was actually made.
|
59
|
+
#
|
60
|
+
# @example Revise the document.
|
61
|
+
# person.revise!
|
62
|
+
#
|
63
|
+
# @since 2.2.1
|
64
|
+
def revise!
|
65
|
+
versions.build(
|
66
|
+
(previous_revision || self).versioned_attributes
|
67
|
+
)
|
68
|
+
versions.shift if version_max.present? && versions.length > version_max
|
69
|
+
self.version = (version || 1 ) + 1
|
70
|
+
save
|
71
|
+
end
|
72
|
+
|
73
|
+
# Filters the results of +changes+ by removing any fields that should
|
74
|
+
# not be versioned.
|
75
|
+
#
|
76
|
+
# @return [ Hash ] A hash of versioned changed attributes.
|
77
|
+
#
|
78
|
+
# @since 2.1.0
|
79
|
+
def versioned_changes
|
80
|
+
only_versioned_attributes(changes.except("updated_at"))
|
81
|
+
end
|
82
|
+
|
83
|
+
# Filters the results of +attributes+ by removing any fields that should
|
84
|
+
# not be versioned.
|
85
|
+
#
|
86
|
+
# @return [ Hash ] A hash of versioned attributes.
|
87
|
+
#
|
88
|
+
# @since 2.1.0
|
89
|
+
def versioned_attributes
|
90
|
+
only_versioned_attributes(attributes)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Check if any versioned fields have been modified. This is similar
|
94
|
+
# to +changed?+, except this method also ignores fields set to be
|
95
|
+
# ignored by versioning.
|
96
|
+
#
|
97
|
+
# @return [ Boolean ] Whether fields that will be versioned have changed.
|
98
|
+
#
|
99
|
+
# @since 2.1.0
|
100
|
+
def versioned_attributes_changed?
|
101
|
+
!versioned_changes.empty?
|
102
|
+
end
|
103
|
+
|
104
|
+
# Executes a block that temporarily disables versioning. This is for cases
|
105
|
+
# where you do not want to version on every save.
|
106
|
+
#
|
107
|
+
# @example Execute a save without versioning.
|
108
|
+
# person.versionless(&:save)
|
109
|
+
#
|
110
|
+
# @return [ Object ] The document or result of the block execution.
|
111
|
+
#
|
112
|
+
# @since 2.0.0
|
113
|
+
def versionless
|
114
|
+
@versionless = true
|
115
|
+
result = yield(self) if block_given?
|
116
|
+
@versionless = false
|
117
|
+
result || self
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
# Find the previous version of this document in the database, or if the
|
123
|
+
# document had been saved without versioning return the persisted one.
|
124
|
+
#
|
125
|
+
# @example Find the last version.
|
126
|
+
# document.find_last_version
|
127
|
+
#
|
128
|
+
# @return [ Document, nil ] The previously saved document.
|
129
|
+
#
|
130
|
+
# @since 2.0.0
|
131
|
+
def previous_revision
|
132
|
+
_loading_revision do
|
133
|
+
self.class.unscoped.
|
134
|
+
with(self.mongo_session.options).
|
135
|
+
where(_id: id).
|
136
|
+
any_of({ version: version }, { version: nil }).first
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Is the document able to be revised? This is true if the document has
|
141
|
+
# changed and we have not explicitly told it not to version.
|
142
|
+
#
|
143
|
+
# @example Is the document revisable?
|
144
|
+
# document.revisable?
|
145
|
+
#
|
146
|
+
# @return [ true, false ] If the document is revisable.
|
147
|
+
#
|
148
|
+
# @since 2.0.0
|
149
|
+
def revisable?
|
150
|
+
versioned_attributes_changed? && !versionless?
|
151
|
+
end
|
152
|
+
|
153
|
+
# Are we in versionless mode? This is true if in a versionless block on the
|
154
|
+
# document.
|
155
|
+
#
|
156
|
+
# @example Is the document in versionless mode?
|
157
|
+
# document.versionless?
|
158
|
+
#
|
159
|
+
# @return [ true, false ] Is the document not currently versioning.
|
160
|
+
#
|
161
|
+
# @since 2.0.0
|
162
|
+
def versionless?
|
163
|
+
@versionless ||= false
|
164
|
+
end
|
165
|
+
|
166
|
+
# Filters fields that should not be versioned out of an attributes hash.
|
167
|
+
# Dynamic attributes are always versioned.
|
168
|
+
#
|
169
|
+
# @param [ Hash ] A hash with field names as keys.
|
170
|
+
#
|
171
|
+
# @return [ Hash ] The hash without non-versioned columns.
|
172
|
+
#
|
173
|
+
# @since 2.1.0
|
174
|
+
def only_versioned_attributes(hash)
|
175
|
+
versioned = {}
|
176
|
+
hash.except("versions").each_pair do |name, value|
|
177
|
+
add_versioned_attribute(versioned, name, value)
|
178
|
+
end
|
179
|
+
versioned
|
180
|
+
end
|
181
|
+
|
182
|
+
# Add the versioned attribute. Will work now for localized fields.
|
183
|
+
#
|
184
|
+
# @api private
|
185
|
+
#
|
186
|
+
# @example Add the versioned attribute.
|
187
|
+
# model.add_versioned_attribute({}, "name", "test")
|
188
|
+
#
|
189
|
+
# @param [ Hash ] versioned The versioned attributes.
|
190
|
+
# @param [ String ] name The name of the field.
|
191
|
+
# @param [ Object ] value The value for the field.
|
192
|
+
#
|
193
|
+
# @since 3.0.10
|
194
|
+
def add_versioned_attribute(versioned, name, value)
|
195
|
+
field = fields[name]
|
196
|
+
if field && field.localized?
|
197
|
+
versioned["#{name}_translations"] = value
|
198
|
+
else
|
199
|
+
versioned[name] = value if !field || field.versioned?
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
module ClassMethods
|
204
|
+
|
205
|
+
# Sets the maximum number of versions to store.
|
206
|
+
#
|
207
|
+
# @example Set the maximum.
|
208
|
+
# Person.max_versions(5)
|
209
|
+
#
|
210
|
+
# @param [ Integer ] number The maximum number to store.
|
211
|
+
#
|
212
|
+
# @return [ Integer ] The max number of versions.
|
213
|
+
def max_versions(number)
|
214
|
+
self.version_max = number.to_i
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|