sequel-revisions 0.1.1 → 0.2.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 +4 -4
- data/lib/sequel/plugins/revisions.rb +170 -61
- metadata +34 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78b1a7fff0b37569c9483503d58542a6859878a0
|
4
|
+
data.tar.gz: abcc54a0f00e59827389312a65ffb359f3e2a64b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2bfd8bf7a0b2cdda5a17352d05703f821629ce039aabe3c573c648e13be490551f3dfb725315c9c36f27c2bd9edc255ff985f22f2855a4a627b150ed48f062c3
|
7
|
+
data.tar.gz: e7f8355ceb4db7b8450315a628a048f28866e5b1f71d8db3ef7772762643895fdef17bfabddf2d8f294b55016ced5131c9b38fb5a80c7fe4214c8c2b139f7677
|
@@ -1,93 +1,202 @@
|
|
1
1
|
require 'sequel'
|
2
2
|
require 'json'
|
3
3
|
|
4
|
-
module Sequel
|
5
|
-
module
|
6
|
-
|
7
|
-
options = {
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
mods = options[:model_name].split("::")
|
17
|
-
if mods.length > 1
|
18
|
-
mobject = Object.const_get mods[0..mods.length-2].join("::")
|
19
|
-
base_name = mods.last
|
20
|
-
else
|
21
|
-
mobject = Object
|
4
|
+
module Sequel
|
5
|
+
module Plugins
|
6
|
+
module Revisions
|
7
|
+
def self.apply(model, options = {})
|
8
|
+
options = set_options(model, options)
|
9
|
+
model.class_eval do
|
10
|
+
@revisions_polymorphic = options[:polymorphic]
|
11
|
+
@revisions_embedded_in = options[:embedded_in]
|
12
|
+
@revisions_on = options[:on]
|
13
|
+
@revisions_meta = options[:meta]
|
14
|
+
@revisions_exclude = options[:exclude]
|
15
|
+
end
|
22
16
|
end
|
23
17
|
|
24
|
-
|
25
|
-
|
26
|
-
klass.class_eval do
|
27
|
-
@@lmeta = options[:meta]
|
28
|
-
plugin :timestamps
|
29
|
-
plugin :serialization
|
18
|
+
def self.configure(model, options = {})
|
19
|
+
options = set_options(model, options)
|
30
20
|
|
31
|
-
|
32
|
-
serialize_attributes :json, :changes
|
33
|
-
many_to_one model.table_name.to_sym, class: model.name
|
21
|
+
base_name = options[:model_name]
|
34
22
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
23
|
+
mods = options[:model_name].split("::")
|
24
|
+
if mods.length > 1
|
25
|
+
mobject = Object.const_get mods[0..mods.length-2].join("::")
|
26
|
+
base_name = mods.last
|
27
|
+
else
|
28
|
+
mobject = Object
|
29
|
+
end
|
30
|
+
|
31
|
+
# Don't redefine
|
32
|
+
unless mobject.const_defined?(base_name)
|
33
|
+
klass = setup_revisions_model(model, options)
|
34
|
+
# Actually define the class in the module
|
35
|
+
mobject.const_set base_name, klass
|
39
36
|
end
|
37
|
+
|
38
|
+
# Configure associations / methods on models
|
39
|
+
setup_model(model, options)
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
|
-
|
42
|
+
module ClassMethods
|
43
|
+
Plugins.inherited_instance_variables(self,
|
44
|
+
:@revisions_polymorphic => :dup,
|
45
|
+
:@revisions_embedded_in => :dup,
|
46
|
+
:@revisions_on => :dup,
|
47
|
+
:@revisions_exclude => :dup,
|
48
|
+
:@revisions_meta => nil)
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
50
|
+
def revisions_polymorphic?
|
51
|
+
@revisions_polymorphic
|
52
|
+
end
|
48
53
|
|
49
|
-
def
|
50
|
-
|
54
|
+
def revisions_embedded_in
|
55
|
+
@revisions_embedded_in
|
56
|
+
end
|
51
57
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
58
|
+
def revisions_on? action
|
59
|
+
# We track everything by default
|
60
|
+
unless @revisions_on
|
61
|
+
true
|
62
|
+
else
|
63
|
+
@revisions_on.include? action
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
67
|
+
def revisions_meta
|
68
|
+
@revisions_meta
|
69
|
+
end
|
70
|
+
|
71
|
+
def revisions_exclude
|
72
|
+
@revisions_exclude
|
62
73
|
end
|
63
74
|
end
|
64
|
-
end
|
65
75
|
|
66
|
-
|
67
|
-
end
|
76
|
+
module InstanceMethods
|
68
77
|
|
69
|
-
|
70
|
-
|
78
|
+
def before_update
|
79
|
+
super
|
80
|
+
track_changes(:update) if model.revisions_on? :update
|
81
|
+
end
|
82
|
+
|
83
|
+
def before_destroy
|
84
|
+
super
|
85
|
+
track_changes(:destroy) if model.revisions_on? :destroy
|
86
|
+
end
|
87
|
+
|
88
|
+
def after_create
|
89
|
+
super
|
90
|
+
track_changes(:create) if model.revisions_on? :create
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def track_changes(action)
|
96
|
+
case action
|
97
|
+
when :update
|
98
|
+
return if changed_columns.empty?
|
99
|
+
# Map the changed fields into an object
|
100
|
+
changes = changed_columns.inject({}) do |obj, key|
|
101
|
+
obj[key] = column_change(key)
|
102
|
+
obj
|
103
|
+
end
|
104
|
+
when :create
|
105
|
+
changes = (columns - model.revisions_exclude).inject({}) do |obj, key|
|
106
|
+
obj[key] = [nil, send(key)]
|
107
|
+
obj
|
108
|
+
end
|
109
|
+
when :destroy
|
110
|
+
changes = (columns - model.revisions_exclude).inject({}) do |obj, key|
|
111
|
+
obj[key] = [send(key), nil]
|
112
|
+
obj
|
113
|
+
end
|
114
|
+
end
|
71
115
|
|
72
|
-
|
116
|
+
#
|
117
|
+
meta = model.revisions_meta.call() unless model.revisions_meta.nil?
|
73
118
|
|
74
|
-
|
75
|
-
|
76
|
-
|
119
|
+
if model.revisions_embedded_in.nil?
|
120
|
+
add_revision(changes: changes, action: action, meta: meta)
|
121
|
+
else
|
122
|
+
trackable = self.send(model.revisions_embedded_in)
|
123
|
+
add_revision(changes: changes, action: action, meta: meta, trackable: trackable)
|
124
|
+
end
|
125
|
+
end
|
77
126
|
end
|
78
127
|
|
79
128
|
private
|
80
129
|
|
81
|
-
def
|
82
|
-
|
130
|
+
def self.set_options(model, options)
|
131
|
+
model_name = options[:polymorphic] ? "Revision" : "#{model.name}Revision"
|
132
|
+
table_name = options[:polymorphic] ? "revisions" : "#{model.table_name.to_s.singularize}_revisions"
|
133
|
+
|
134
|
+
options = {
|
135
|
+
model_name: model_name,
|
136
|
+
table_name: table_name,
|
137
|
+
exclude: [:id, :created_at, :updated_at],
|
138
|
+
meta: nil
|
139
|
+
}.merge(options)
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.setup_revisions_model(model, options)
|
143
|
+
# Dynamically create Model class
|
144
|
+
klass = Class.new(Sequel::Model(options[:table_name].to_sym))
|
145
|
+
klass.class_eval do
|
146
|
+
plugin :timestamps
|
147
|
+
plugin :serialization
|
148
|
+
|
149
|
+
serialize_attributes :json, :meta
|
150
|
+
serialize_attributes :json, :changes
|
151
|
+
end
|
152
|
+
|
153
|
+
if options[:polymorphic]
|
154
|
+
klass.class_eval do
|
155
|
+
many_to_one :trackable, polymorphic: true
|
156
|
+
many_to_one :embeddable, polymorphic: true
|
157
|
+
end
|
158
|
+
else
|
159
|
+
klass.class_eval do
|
160
|
+
many_to_one model.table_name.to_sym, class: model.name
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
klass
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.setup_model(model, options)
|
168
|
+
model.class_eval do
|
169
|
+
plugin :dirty
|
170
|
+
|
171
|
+
def revert
|
172
|
+
return if revisions.empty?
|
173
|
+
|
174
|
+
last = revisions.last
|
175
|
+
changes = last.changes
|
176
|
+
changes.keys.each do |key|
|
177
|
+
send("#{key}=", changes[key][0])
|
178
|
+
end
|
179
|
+
end
|
83
180
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
181
|
+
def revert!
|
182
|
+
revert
|
183
|
+
save
|
184
|
+
end
|
88
185
|
end
|
89
186
|
|
90
|
-
|
187
|
+
if options[:polymorphic]
|
188
|
+
model.class_eval do
|
189
|
+
one_to_many :revisions, as: :trackable
|
190
|
+
end
|
191
|
+
elsif options[:embedded_in]
|
192
|
+
model.class_eval do
|
193
|
+
one_to_many :revisions, as: :embeddable
|
194
|
+
end
|
195
|
+
else
|
196
|
+
model.class_eval do
|
197
|
+
one_to_many :revisions, class: options[:model_name]
|
198
|
+
end
|
199
|
+
end
|
91
200
|
end
|
92
201
|
end
|
93
202
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel-revisions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fabian Becker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -38,34 +38,62 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sequel_polymorphic
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: sqlite3
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
61
|
+
version: '1'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
68
|
+
version: '1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: rspec
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
58
86
|
requirements:
|
59
87
|
- - "~>"
|
60
88
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
89
|
+
version: '3'
|
62
90
|
type: :development
|
63
91
|
prerelease: false
|
64
92
|
version_requirements: !ruby/object:Gem::Requirement
|
65
93
|
requirements:
|
66
94
|
- - "~>"
|
67
95
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
96
|
+
version: '3'
|
69
97
|
description: Use this plugin to track field changes and revert your model to an older
|
70
98
|
state.
|
71
99
|
email: halfdan@xnorfz.de
|