sequel-paranoid 0.6.2 → 0.7.0

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/paranoid.rb +149 -60
  3. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 00ea7005b5cef0b88e4dd80e5592dd83b55ec5ee
4
- data.tar.gz: 0754305ae29e1968e0cf9dba290d798e00a1ec1a
3
+ metadata.gz: e14a35d77873153c4dd8983fb9e338796ccbfab5
4
+ data.tar.gz: 40feef72715beab3225246870ffdf84e241ed44c
5
5
  SHA512:
6
- metadata.gz: 0d1c1864e7b354a34bfdaef9c082da089f141e642c0f68ee91e1437a9c875d6f7f3509f862dcbb98f61092e9a23d674276e35dd709f78d5d21c30b7ff8fc7086
7
- data.tar.gz: c80715773eda084fc7479794f10b528dfbbbb48696d73cda96de8be8932cb06a9f177d233b6c1b80299afd7a004f3cc3dc9230acf76d33829847b6fcaecb62fa
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 => :present,
13
+ :non_deleted_scope_name => :not_deleted,
12
14
  :ignore_deletion_scope_name => :with_deleted,
13
15
  :enable_default_scope => false,
14
- :deleted_column_default => nil
15
- }.merge(options)
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
- # Inject the scopes for the deleted and the existing entries.
20
- #
69
+ dataset_module ds_mod
70
+ include im_mod
21
71
 
22
- dataset_module do
23
- # scope for deleted items
24
- define_method(options[:deleted_scope_name]) do
25
- send(options[:ignore_deletion_scope_name]).exclude(Sequel.qualify(model.table_name, options[:deleted_at_field_name]) => options[:deleted_column_default])
26
- end
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
- # scope for non-deleted items
29
- define_method(options[:non_deleted_scope_name]) do
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
- # scope for both
34
- define_method(options[:ignore_deletion_scope_name]) do
35
- unfiltered
36
- end
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
- # Overwrite the "_destroy_delete" method which is used by sequel to
41
- # delete an object. This makes sure, we run all the hook correctly and
42
- # in a transaction.
43
- #
44
- define_method("destroy") do |*args|
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
- define_method("_destroy_delete") do
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
- # set the deletion time
58
- self.send("#{options[:deleted_at_field_name]}=", Time.now)
132
+ send(self.class.sequel_paranoid_options[:delete_method_name], destroy_options)
133
+ end
134
+ end
135
+ end
59
136
 
60
- # set the deletion author
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
- self.save
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
- # Check if an instance is deleted.
101
- #
163
+ end
164
+ end
102
165
 
103
- define_method("deleted?") do
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
- # Inject the default scope that filters deleted entries.
174
+ # Enhance validates_unique to support :paranoid => true for paranoid
175
+ # uniqueness checking.
109
176
  #
110
-
111
- if options[:enable_default_scope]
112
- set_dataset(self.send(options[:non_deleted_scope_name]))
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.6.2
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 loosing its
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.4.5.1
55
+ rubygems_version: 2.6.11
56
56
  signing_key:
57
57
  specification_version: 4
58
- summary: A plugin for the Ruby ORM Sequel, that allows soft deletion of database entries.
58
+ summary: A plugin for the Ruby ORM Sequel that allows soft deletion of database entries.
59
59
  test_files: []