sequel-paranoid 0.6.2 → 0.7.0
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/paranoid.rb +149 -60
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e14a35d77873153c4dd8983fb9e338796ccbfab5
|
4
|
+
data.tar.gz: 40feef72715beab3225246870ffdf84e241ed44c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e84e46393bb292be70bb7c00f9f77a77c7dde85b2468c022f5c66aaa0dabe8fab5a93b2f6744f3a609ae9176b9a7677e35599b55700c5506a2b7ffcaef249470
|
7
|
+
data.tar.gz: 489045f17951b5390d17902511793e14b2d215ed4af44f473baf8598cf1bf2e2da9e8ef7cb39d962b7d73a9ecc3d9bddaed9398caa89e49eb86f5c126802512a
|
@@ -2,46 +2,115 @@ require 'sequel'
|
|
2
2
|
|
3
3
|
module Sequel::Plugins
|
4
4
|
module Paranoid
|
5
|
+
|
5
6
|
def self.configure(model, options = {})
|
6
|
-
options = {
|
7
|
+
model.sequel_paranoid_options = options = {
|
7
8
|
:deleted_at_field_name => :deleted_at,
|
8
9
|
:deleted_by_field_name => :deleted_by,
|
10
|
+
:delete_method_name => :soft_delete,
|
9
11
|
:enable_deleted_by => false,
|
10
12
|
:deleted_scope_name => :deleted,
|
11
|
-
:non_deleted_scope_name => :
|
13
|
+
:non_deleted_scope_name => :not_deleted,
|
12
14
|
:ignore_deletion_scope_name => :with_deleted,
|
13
15
|
:enable_default_scope => false,
|
14
|
-
:
|
15
|
-
|
16
|
+
:soft_delete_on_destroy => false,
|
17
|
+
:deleted_column_default => nil,
|
18
|
+
:include_validation_helpers => false,
|
19
|
+
}.update(options)
|
20
|
+
|
21
|
+
delete_attributes = proc do |*args|
|
22
|
+
destroy_options = args.first || {}
|
23
|
+
|
24
|
+
attrs = {}
|
25
|
+
# set the deletion time
|
26
|
+
attrs[options[:deleted_at_field_name]] = Time.now
|
27
|
+
|
28
|
+
# set the deletion author
|
29
|
+
if options[:enable_deleted_by] && destroy_options && destroy_options[:deleted_by]
|
30
|
+
attrs[options[:deleted_by_field_name]] = destroy_options[:deleted_by]
|
31
|
+
end
|
32
|
+
|
33
|
+
attrs
|
34
|
+
end
|
35
|
+
|
36
|
+
ds_mod = Module.new do
|
37
|
+
# scope for deleted items
|
38
|
+
define_method(options[:deleted_scope_name]) do
|
39
|
+
send(options[:ignore_deletion_scope_name]).exclude(Sequel.qualify(model.table_name, options[:deleted_at_field_name]) => options[:deleted_column_default])
|
40
|
+
end
|
41
|
+
|
42
|
+
# scope for non-deleted items
|
43
|
+
define_method(options[:non_deleted_scope_name]) do
|
44
|
+
filter(Sequel.qualify(model.table_name, options[:deleted_at_field_name]) => options[:deleted_column_default])
|
45
|
+
end
|
46
|
+
|
47
|
+
# scope for both
|
48
|
+
define_method(options[:ignore_deletion_scope_name]) do
|
49
|
+
unfiltered
|
50
|
+
end
|
51
|
+
|
52
|
+
# soft delete the records without callbacks.
|
53
|
+
define_method(options[:delete_method_name]) do |*args|
|
54
|
+
update(delete_attributes.call(*args))
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
im_mod = Module.new do
|
60
|
+
|
61
|
+
define_method(options[:delete_method_name]) do |*args|
|
62
|
+
self.set(delete_attributes.call(*args))
|
63
|
+
self.save
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
16
67
|
|
17
68
|
model.instance_eval do
|
18
|
-
|
19
|
-
|
20
|
-
#
|
69
|
+
dataset_module ds_mod
|
70
|
+
include im_mod
|
21
71
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
72
|
+
plugin SoftDeleteOnDestroy if options[:soft_delete_on_destroy]
|
73
|
+
plugin EnableDefaultScope if options[:enable_default_scope]
|
74
|
+
plugin Validations if options[:include_validation_helpers]
|
75
|
+
end
|
76
|
+
end
|
27
77
|
|
28
|
-
|
29
|
-
|
30
|
-
filter(Sequel.qualify(model.table_name, options[:deleted_at_field_name]) => options[:deleted_column_default])
|
31
|
-
end
|
78
|
+
module ClassMethods
|
79
|
+
attr_accessor :sequel_paranoid_options
|
32
80
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
81
|
+
::Sequel::Plugins.inherited_instance_variables(self, :@sequel_paranoid_options=>:hash_dup)
|
82
|
+
end
|
83
|
+
|
84
|
+
module InstanceMethods
|
85
|
+
|
86
|
+
#
|
87
|
+
# Method for undeleting an instance.
|
88
|
+
#
|
89
|
+
def recover
|
90
|
+
opts = self.class.sequel_paranoid_options
|
91
|
+
send("#{opts[:deleted_at_field_name]}=".to_sym, opts[:deleted_column_default])
|
92
|
+
|
93
|
+
if opts[:enable_deleted_by] && self.respond_to?(opts[:deleted_by_field_name].to_sym)
|
94
|
+
send("#{opts[:deleted_by_field_name]}=", nil)
|
37
95
|
end
|
38
96
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
97
|
+
save
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Check if an instance is deleted.
|
102
|
+
#
|
103
|
+
|
104
|
+
def deleted?
|
105
|
+
opts = self.class.sequel_paranoid_options
|
106
|
+
send(opts[:deleted_at_field_name]) != opts[:deleted_column_default]
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
module SoftDeleteOnDestroy
|
112
|
+
module InstanceMethods
|
113
|
+
def destroy(*args)
|
45
114
|
# Save the variables threadsafe (because the locks have not been
|
46
115
|
# initialized by sequel yet).
|
47
116
|
Thread.current["_paranoid_destroy_args_#{self.object_id}"] = args
|
@@ -49,28 +118,37 @@ module Sequel::Plugins
|
|
49
118
|
super(*args)
|
50
119
|
end
|
51
120
|
|
52
|
-
|
121
|
+
#
|
122
|
+
# Overwrite the "_destroy_delete" method which is used by sequel to
|
123
|
+
# delete an object. This makes sure, we run all the hook correctly and
|
124
|
+
# in a transaction.
|
125
|
+
#
|
126
|
+
|
127
|
+
def _destroy_delete
|
53
128
|
# _destroy_delete does not take arguments.
|
54
129
|
destroy_options = Thread.current["_paranoid_destroy_args_#{self.object_id}"].first
|
55
130
|
Thread.current["_paranoid_destroy_args_#{self.object_id}"] = nil
|
56
131
|
|
57
|
-
|
58
|
-
|
132
|
+
send(self.class.sequel_paranoid_options[:delete_method_name], destroy_options)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
59
136
|
|
60
|
-
|
61
|
-
if options[:enable_deleted_by] && destroy_options && destroy_options[:deleted_by]
|
62
|
-
self.send("#{options[:deleted_by_field_name]}=", destroy_options[:deleted_by])
|
63
|
-
end
|
137
|
+
module EnableDefaultScope
|
64
138
|
|
65
|
-
|
139
|
+
def self.configure(model)
|
140
|
+
model.class_eval do
|
141
|
+
set_dataset(send(sequel_paranoid_options[:non_deleted_scope_name]))
|
66
142
|
end
|
143
|
+
end
|
144
|
+
|
145
|
+
module InstanceMethods
|
67
146
|
|
68
147
|
#
|
69
148
|
# Sequel patch to allow updates to deleted instances
|
70
149
|
# when default scope is enabled
|
71
150
|
#
|
72
|
-
|
73
|
-
define_method("_update_without_checking") do |columns|
|
151
|
+
def _update_without_checking(columns)
|
74
152
|
# figure out correct pk conditions (see base#this)
|
75
153
|
conditions = this.send(:joined_dataset?) ? qualified_pk_hash : pk_hash
|
76
154
|
|
@@ -80,38 +158,49 @@ module Sequel::Plugins
|
|
80
158
|
# run the original update on the with_deleted dataset
|
81
159
|
update_with_deleted_dataset.update(columns)
|
82
160
|
|
83
|
-
end if(options[:enable_default_scope])
|
84
|
-
|
85
|
-
#
|
86
|
-
# Method for undeleting an instance.
|
87
|
-
#
|
88
|
-
|
89
|
-
define_method("recover") do
|
90
|
-
self.send("#{options[:deleted_at_field_name]}=".to_sym, options[:deleted_column_default])
|
91
|
-
|
92
|
-
if options[:enable_deleted_by] && self.respond_to?(options[:deleted_by_field_name].to_sym)
|
93
|
-
self.send("#{options[:deleted_by_field_name]}=", nil)
|
94
|
-
end
|
95
|
-
|
96
|
-
self.save
|
97
161
|
end
|
98
162
|
|
99
|
-
|
100
|
-
|
101
|
-
#
|
163
|
+
end
|
164
|
+
end
|
102
165
|
|
103
|
-
|
104
|
-
send(options[:deleted_at_field_name]) != options[:deleted_column_default]
|
105
|
-
end
|
166
|
+
module Validations
|
106
167
|
|
168
|
+
def self.apply(base)
|
169
|
+
base.plugin :validation_helpers
|
170
|
+
end
|
171
|
+
|
172
|
+
module InstanceMethods
|
107
173
|
#
|
108
|
-
#
|
174
|
+
# Enhance validates_unique to support :paranoid => true for paranoid
|
175
|
+
# uniqueness checking.
|
109
176
|
#
|
110
|
-
|
111
|
-
|
112
|
-
|
177
|
+
def validates_unique(*columns)
|
178
|
+
return super(*columns) unless columns.last.kind_of?(Hash) && columns.last.delete(:paranoid)
|
179
|
+
|
180
|
+
opts = self.class.sequel_paranoid_options
|
181
|
+
if deleted?
|
182
|
+
columns = columns.map { |c|
|
183
|
+
case c
|
184
|
+
when Array, Symbol
|
185
|
+
[ c, opts[:deleted_at_field_name] ].flatten
|
186
|
+
else
|
187
|
+
c
|
188
|
+
end
|
189
|
+
}
|
190
|
+
|
191
|
+
super(*columns) { |ds|
|
192
|
+
ds = ds.send(opts[:deleted_scope_name])
|
193
|
+
block_given? ? yield(ds) : ds
|
194
|
+
}
|
195
|
+
else
|
196
|
+
super(*columns) { |ds|
|
197
|
+
ds = ds.send(opts[:non_deleted_scope_name])
|
198
|
+
block_given? ? yield(ds) : ds
|
199
|
+
}
|
200
|
+
end
|
113
201
|
end
|
114
202
|
end
|
203
|
+
|
115
204
|
end
|
116
205
|
end
|
117
206
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel-paranoid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sascha Depold
|
@@ -24,7 +24,7 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
description: Use this plugin to mark a model instance as deleted without
|
27
|
+
description: Use this plugin to mark a model instance as deleted without losing its
|
28
28
|
actual data.
|
29
29
|
email: sascha@depold.com
|
30
30
|
executables: []
|
@@ -52,8 +52,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
52
|
version: '0'
|
53
53
|
requirements: []
|
54
54
|
rubyforge_project:
|
55
|
-
rubygems_version: 2.
|
55
|
+
rubygems_version: 2.6.11
|
56
56
|
signing_key:
|
57
57
|
specification_version: 4
|
58
|
-
summary: A plugin for the Ruby ORM Sequel
|
58
|
+
summary: A plugin for the Ruby ORM Sequel that allows soft deletion of database entries.
|
59
59
|
test_files: []
|