bulk_dependency_eraser 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc034a38ab80a2e277860a5a69f6a654e1e461f691f54d6a510814b55279cebd
|
4
|
+
data.tar.gz: 88055bcbcb73bc260ef4718006f3149d95ea216badb4bd4ac142506e756c1882
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c9d1bc7851eaa2f51a853a99b24ff3842940f792938b2eac86ebfcc6471653c0d14de735d837f108ca59118a6661c086566b48475b87f1c98870cd80544dd79
|
7
|
+
data.tar.gz: 7e09f55e2baf0db2eefd7f2dfc028fda58b7f9ec2469a6bdbcfa56855bd4cf1ddc0b1502468554f56726fcbd08135daecc5e20940d18b2d9a2f49dc2558c5971
|
@@ -209,19 +209,24 @@ module BulkDependencyEraser
|
|
209
209
|
nullify_association_names = nullify_associations.map(&:name)
|
210
210
|
restricted_association_names = restricted_associations.map(&:name)
|
211
211
|
|
212
|
-
if
|
213
|
-
|
214
|
-
|
215
|
-
puts " Restricted Associations: #{restricted_association_names}"
|
216
|
-
end
|
217
|
-
|
218
|
-
# Iterate through the assoc names, if there are any :through assocs, then remap
|
212
|
+
# Iterate through the assoc names, if there are any :through assocs, then rename the association
|
213
|
+
# - Rails interpretation of any dependencies of a :through association is to apply it to
|
214
|
+
# the leaf association at the end of the :through chain(s)
|
219
215
|
destroy_association_names = destroy_association_names.collect do |assoc_name|
|
220
216
|
find_root_association_from_through_assocs(klass, assoc_name)
|
221
217
|
end
|
222
218
|
nullify_association_names = nullify_association_names.collect do |assoc_name|
|
223
219
|
find_root_association_from_through_assocs(klass, assoc_name)
|
224
220
|
end
|
221
|
+
restricted_association_names = restricted_association_names.collect do |assoc_name|
|
222
|
+
find_root_association_from_through_assocs(klass, assoc_name)
|
223
|
+
end
|
224
|
+
|
225
|
+
if opts_c.verbose
|
226
|
+
puts "Destroyable Associations: #{destroy_association_names}"
|
227
|
+
puts "Nullifiable Associations: #{nullify_association_names}"
|
228
|
+
puts " Restricted Associations: #{restricted_association_names}"
|
229
|
+
end
|
225
230
|
|
226
231
|
destroy_association_names.each do |destroy_association_name|
|
227
232
|
association_parser(klass, query, query_ids, destroy_association_name, :delete)
|
@@ -2,7 +2,11 @@ module BulkDependencyEraser
|
|
2
2
|
class Nullifier < Base
|
3
3
|
DEFAULT_OPTS = {
|
4
4
|
verbose: false,
|
5
|
-
db_nullify_wrapper: self::DEFAULT_DB_WRAPPER
|
5
|
+
db_nullify_wrapper: self::DEFAULT_DB_WRAPPER,
|
6
|
+
# Set to true if you want 'ActiveRecord::InvalidForeignKey' errors raised during nullifications
|
7
|
+
# - I can't think of a use-case where a nullification would generate an invalid key error
|
8
|
+
# - Not hurting anything to leave it in, but might remove it in the future.
|
9
|
+
enable_invalid_foreign_key_detection: false
|
6
10
|
}.freeze
|
7
11
|
|
8
12
|
DEFAULT_DB_WRAPPER = ->(block) do
|
@@ -22,6 +26,53 @@ module BulkDependencyEraser
|
|
22
26
|
def initialize class_names_columns_and_ids:, opts: {}
|
23
27
|
@class_names_columns_and_ids = class_names_columns_and_ids
|
24
28
|
super(opts:)
|
29
|
+
|
30
|
+
if opts_c.verbose
|
31
|
+
puts "Combining nullification column groups (if groupable)"
|
32
|
+
puts "Before Combination: #{@class_names_columns_and_ids}"
|
33
|
+
end
|
34
|
+
|
35
|
+
@class_names_columns_and_ids = combine_matching_columns(@class_names_columns_and_ids)
|
36
|
+
|
37
|
+
if opts_c.verbose
|
38
|
+
puts "After Combination: #{@class_names_columns_and_ids}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Combine columns if the IDs are the same
|
43
|
+
# - will do one SQL call instead of several
|
44
|
+
def combine_matching_columns(nullification_hash)
|
45
|
+
return {} if nullification_hash.none?
|
46
|
+
|
47
|
+
merged_hash = {}
|
48
|
+
|
49
|
+
nullification_hash.each do |klass_name, columns_and_ids|
|
50
|
+
merged_hash[klass_name] = {}
|
51
|
+
columns_and_ids.each do |key, array|
|
52
|
+
sorted_array = array.sort
|
53
|
+
|
54
|
+
# Find any existing key in merged_hash that has the same sorted array
|
55
|
+
matching_key = merged_hash[klass_name].keys.find { |k| merged_hash[klass_name][k].sort == sorted_array }
|
56
|
+
|
57
|
+
if matching_key
|
58
|
+
# Concatenate the matching keys and update the hash
|
59
|
+
new_key = key.is_a?(Array) ? key : [key]
|
60
|
+
if matching_key.is_a?(Array)
|
61
|
+
new_key += matching_key
|
62
|
+
else
|
63
|
+
new_key << matching_key
|
64
|
+
end
|
65
|
+
|
66
|
+
merged_hash[klass_name][new_key] = sorted_array
|
67
|
+
merged_hash[klass_name].delete(matching_key)
|
68
|
+
else
|
69
|
+
# Otherwise, just add the current key-value pair
|
70
|
+
merged_hash[klass_name][key] = sorted_array
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
merged_hash
|
25
76
|
end
|
26
77
|
|
27
78
|
def execute
|
@@ -34,15 +85,19 @@ module BulkDependencyEraser
|
|
34
85
|
klass = class_name.constantize
|
35
86
|
|
36
87
|
columns_and_ids = class_names_columns_and_ids[class_name]
|
37
|
-
|
38
88
|
columns_and_ids.each do |column, ids|
|
39
89
|
current_column = column
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
90
|
+
|
91
|
+
if opts_c.enable_invalid_foreign_key_detection
|
92
|
+
# nullify with referential integrity
|
93
|
+
nullify_by_klass_column_and_ids(klass, column, ids)
|
94
|
+
else
|
95
|
+
# nullify without referential integrity
|
96
|
+
# Disable any ActiveRecord::InvalidForeignKey raised errors.
|
97
|
+
# - src: https://stackoverflow.com/questions/41005849/rails-migrations-temporarily-ignore-foreign-key-constraint
|
98
|
+
# https://apidock.com/rails/ActiveRecord/ConnectionAdapters/AbstractAdapter/disable_referential_integrity
|
99
|
+
ActiveRecord::Base.connection.disable_referential_integrity do
|
100
|
+
nullify_by_klass_column_and_ids(klass, column, ids)
|
46
101
|
end
|
47
102
|
end
|
48
103
|
end
|
@@ -60,6 +115,23 @@ module BulkDependencyEraser
|
|
60
115
|
|
61
116
|
attr_reader :class_names_columns_and_ids
|
62
117
|
|
118
|
+
def nullify_by_klass_column_and_ids klass, columns, ids
|
119
|
+
nullify_columns = {}
|
120
|
+
|
121
|
+
# supporting nullification of groups of columns simultaneously
|
122
|
+
if columns.is_a?(Array)
|
123
|
+
columns.each do |column|
|
124
|
+
nullify_columns[column] = nil
|
125
|
+
end
|
126
|
+
else
|
127
|
+
nullify_columns[columns] = nil
|
128
|
+
end
|
129
|
+
|
130
|
+
nullify_in_db do
|
131
|
+
klass.unscoped.where(id: ids).update_all(nullify_columns)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
63
135
|
def nullify_in_db(&block)
|
64
136
|
puts "Nullifying from DB..." if opts_c.verbose
|
65
137
|
opts_c.db_nullify_wrapper.call(block)
|