cascade-deleter 0.1.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 +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: []
|