cascade-deleter 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/cascade_deleter.rb +77 -0
- data/lib/deactivator.rb +45 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6a0e10f1734aed0dcc89834897e051c0e26bbf463706843f60fa90564e90188a
|
4
|
+
data.tar.gz: 46fdd8434d43e0ab32c92cfcff66047988023c2494f00e47eff5ea5b87512e7e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7dd2d5bb3669bd742fe76fecf44ff5236b47e43c27cddfeaf7cf675ac85f1a8ca0b2dd3d2d1523451c9e08cc43e489502fa06d04e079441b28a67b4c76456c36
|
7
|
+
data.tar.gz: 7697d23ef95f3661b30a82c29f22882e02d2fdf4c3bdbad12befb8c99255b976c0f8f1d1a1c4e9b1e625a21bac862f80ac12d3a873b83888d5c4efd5a691da00
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'hierarchy_tree'
|
2
|
+
require 'deactivator'
|
3
|
+
|
4
|
+
# Cascade delete items and all of their children items
|
5
|
+
# ⚠ Be aware, this lib executes HARD deletions, so
|
6
|
+
# 1. The items will be completely removed from the database
|
7
|
+
# 2. No validations or callbacks will be triggered
|
8
|
+
# Usage 1: CascadeDeleter.new(Project.unscoped.where(active: false)).delete_all
|
9
|
+
# Usage 2: CascadeDeleter.new(Project.unscoped.where(active: false)).delete_all(
|
10
|
+
# custom_joins: { 'Attachment' => {:subproject=>:project} }
|
11
|
+
# )
|
12
|
+
# Usage 3: CascadeDeleter.new(Discipline.where_like(description: '[TO BE DELETED]')).delete_all(
|
13
|
+
# method: :soft
|
14
|
+
# )
|
15
|
+
|
16
|
+
################ Debug ################
|
17
|
+
# gem cleanup cascade-deleter
|
18
|
+
# rm cascade-deleter-0.1.0.gem
|
19
|
+
# gem build cascade_deleter
|
20
|
+
# gem install cascade-deleter-0.1.0.gem
|
21
|
+
# ruby -Itest test/test_cascade_deleter.rb
|
22
|
+
class CascadeDeleter
|
23
|
+
def initialize(items)
|
24
|
+
@items = items
|
25
|
+
@class = @items.klass
|
26
|
+
@classes = classes
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete_all(custom_joins: {}, method: :hard)
|
30
|
+
Deactivator.new(@classes).without_default_scopes do
|
31
|
+
ActiveRecord::Base.connection.execute('SET FOREIGN_KEY_CHECKS = 0;')
|
32
|
+
|
33
|
+
ActiveRecord::Base.transaction do
|
34
|
+
@classes.map(&:constantize).each do |klass|
|
35
|
+
delete(klass, build_join(klass, custom_joins), method)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
ensure
|
39
|
+
ActiveRecord::Base.connection.execute('SET FOREIGN_KEY_CHECKS = 1;')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def classes
|
46
|
+
Hierarchy.bottom_up_classes(@class).without('Audited::Audit')
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete(klass, join, method)
|
50
|
+
puts "#{method.to_s.titleize} Deleting #{klass.name.pluralize.titleize}".green
|
51
|
+
count = apply_delete(build_query(klass, join), method)
|
52
|
+
puts "#{count} #{klass.name.pluralize.titleize} are #{method} deleted".yellow
|
53
|
+
end
|
54
|
+
|
55
|
+
def apply_delete(items, method)
|
56
|
+
case method
|
57
|
+
when :hard
|
58
|
+
items.delete_all
|
59
|
+
when :soft
|
60
|
+
items.update_all(active: false, updated_at: Time.now)
|
61
|
+
else
|
62
|
+
puts 'Unregistered Delete Method. Possible methods → :hard or :soft'.red
|
63
|
+
0
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def build_query(klass, join)
|
68
|
+
return @items if @class.to_s == klass.to_s
|
69
|
+
|
70
|
+
klass.joins(join).where(@class.table_name => { id: @items.select(:id) })
|
71
|
+
end
|
72
|
+
|
73
|
+
def build_join(model, custom_joins = {})
|
74
|
+
custom_joins[model.to_s] || Hierarchy.ancestors_bfs(from: model, to: @class)
|
75
|
+
# You can use `Hierarchy.ancestors(from: model, to: @class)` to choose one custom_join
|
76
|
+
end
|
77
|
+
end
|
data/lib/deactivator.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Deactivate default_scopes for the given classes for a given code block
|
2
|
+
# --------------------------- Usage ---------------------------
|
3
|
+
# Deactivator.new(['ClassA', 'ClassB']).without_default_scopes do
|
4
|
+
# My
|
5
|
+
# Code
|
6
|
+
# Block
|
7
|
+
# Without ClassA and ClassB default_scopes
|
8
|
+
# end
|
9
|
+
class Deactivator
|
10
|
+
def initialize(classes)
|
11
|
+
@classes = classes
|
12
|
+
@default_scopes = capture_default_scopes
|
13
|
+
end
|
14
|
+
|
15
|
+
def without_default_scopes
|
16
|
+
remove_default_scopes
|
17
|
+
yield
|
18
|
+
ensure
|
19
|
+
restore_default_scopes
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def capture_default_scopes
|
25
|
+
@classes.to_h do |klass|
|
26
|
+
[klass, klass.constantize.default_scopes]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def remove_default_scopes
|
31
|
+
@classes.each do |klass|
|
32
|
+
klass.constantize.class_eval { self.default_scopes = [] }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def restore_default_scopes
|
37
|
+
deactivator = self
|
38
|
+
|
39
|
+
@classes.each do |klass|
|
40
|
+
klass.constantize.class_eval do
|
41
|
+
self.default_scopes = deactivator.instance_variable_get(:@default_scopes)[klass]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cascade-deleter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Victor Cordeiro Costa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-11-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hierarchy-tree
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.3.5
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.3.5
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '12.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '12.1'
|
55
|
+
description: |-
|
56
|
+
cascade-deleter is a ruby gem designed to delete items
|
57
|
+
with all of their descendant items in their hierarchy.
|
58
|
+
email:
|
59
|
+
- victorcorcos@gmail.com
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- lib/cascade_deleter.rb
|
65
|
+
- lib/deactivator.rb
|
66
|
+
homepage: https://github.com/Victorcorcos/cascade-deleter
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '2.0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubygems_version: 3.1.6
|
86
|
+
signing_key:
|
87
|
+
specification_version: 4
|
88
|
+
summary: cascade-deleter is a ruby gem designed to delete items with all of their
|
89
|
+
descendant items in their hierarchy.
|
90
|
+
test_files: []
|