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 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
@@ -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: []