sequel-revisions 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sequel/plugins/revisions.rb +170 -61
  3. metadata +34 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b638d9cddc49884c2e02153531cb651e74e8f465
4
- data.tar.gz: 7f44a3fa58deb5145a6aef9bbd59e55ec02017ec
3
+ metadata.gz: 78b1a7fff0b37569c9483503d58542a6859878a0
4
+ data.tar.gz: abcc54a0f00e59827389312a65ffb359f3e2a64b
5
5
  SHA512:
6
- metadata.gz: 531a84641e345fc5270b0b2f81af0ca4b99a57882bd97dffb662773d49713aa1f1d423cc15b857405cf4dede7783f9ce1908501c51a0c43760e9edd3f1ea8af0
7
- data.tar.gz: 11bedd40539e7b727b4afc91980cfa0ed14b78cfe2917d3471e4eefcdd07e139715ec9ba80e1dd52602b0f4309eaf0c66c7b142dd24f06bf3a3f602692eb44a5
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::Plugins
5
- module Revisions
6
- def self.apply(model, options = {})
7
- options = {
8
- model_name: "#{model.name}Revisions",
9
- table_name: "#{model.table_name.to_s.singularize}_revisions",
10
- exclude: [:created_at, :updated_at],
11
- meta: nil
12
- }.merge(options)
13
-
14
- base_name = options[:model_name]
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
- # Dynamically create Model class
25
- klass = Class.new(Sequel::Model(options[:table_name].to_sym))
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
- serialize_attributes :json, :meta
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
- def before_create
36
- # ToDo: This should not call to_json. Maybe a bug?
37
- self[:meta] = @@lmeta.call().to_json unless @@lmeta.nil?
38
- super
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
- # Actually define the class in the module
43
- mobject.const_set base_name, klass
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
- model.class_eval do
46
- plugin :dirty
47
- one_to_many :revisions, class: options[:model_name]
50
+ def revisions_polymorphic?
51
+ @revisions_polymorphic
52
+ end
48
53
 
49
- def revert
50
- return if revisions.empty?
54
+ def revisions_embedded_in
55
+ @revisions_embedded_in
56
+ end
51
57
 
52
- last = revisions.last
53
- changes = last.changes
54
- changes.keys.each do |key|
55
- send("#{key}=", changes[key][0])
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 revert!
60
- revert
61
- save
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
- def self.configure(model, options = {})
67
- end
76
+ module InstanceMethods
68
77
 
69
- module ClassMethods
70
- end
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
- module InstanceMethods
116
+ #
117
+ meta = model.revisions_meta.call() unless model.revisions_meta.nil?
73
118
 
74
- def before_update
75
- track_changes
76
- super
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 track_changes
82
- return if changed_columns.empty?
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
- # Map the changed fields into an object
85
- changes = changed_columns.inject({}) do |obj, key|
86
- obj[key] = column_change(key)
87
- obj
181
+ def revert!
182
+ revert
183
+ save
184
+ end
88
185
  end
89
186
 
90
- add_revision(changes: changes)
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.1.1
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-01-19 00:00:00.000000000 Z
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: '0'
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: '0'
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: '0'
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: '0'
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