bulk_dependency_eraser 1.0.3 → 1.0.5
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: cbea15215c816eca6790c1d7c3cbf4f4f68534fc3ff18cc38e8c26dc7e94513d
|
4
|
+
data.tar.gz: 532a711c1290ea4fea4200acc75d9916eb18a2451207b89d1163372d7372028d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5639d23e7fbad812f11db05ad4b4dc3e88cd8823b3623ec38c892ed144ca6002b2e6bf56a826cca62aa2e87312fc676ac0668d1d6301a66496f91a62c7896fe
|
7
|
+
data.tar.gz: 20f81c4ddae6e875de07849088493f21095a567ccf2e1e39bfe21bbe1486dbfaa76ad06bc53f247724ca0f5e79a7f7af699e480345c2b5a800f617c06bb83844
|
@@ -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)
|
@@ -255,7 +260,7 @@ module BulkDependencyEraser
|
|
255
260
|
when 'ActiveRecord::Reflection::HasManyReflection'
|
256
261
|
association_parser_has_many(parent_class, query, query_ids, association_name, type)
|
257
262
|
when 'ActiveRecord::Reflection::HasOneReflection'
|
258
|
-
association_parser_has_many(parent_class, query, query_ids, association_name, type
|
263
|
+
association_parser_has_many(parent_class, query, query_ids, association_name, type)
|
259
264
|
when 'ActiveRecord::Reflection::BelongsToReflection'
|
260
265
|
if type == :nullify
|
261
266
|
report_error("#{parent_class.name}'s association '#{association_name}' - dependent 'nullify' invalid for 'belongs_to'")
|
@@ -342,10 +347,11 @@ module BulkDependencyEraser
|
|
342
347
|
assoc_query = assoc_query.where(specified_foreign_key.to_sym => query_ids)
|
343
348
|
end
|
344
349
|
|
345
|
-
#
|
346
|
-
if
|
347
|
-
|
348
|
-
|
350
|
+
# Works in theory for ONE record's has_one, but we're dealing with potentially many
|
351
|
+
# # Apply limit if has_one assocation (subset of has_many)
|
352
|
+
# if opts[:limit]
|
353
|
+
# assoc_query = assoc_query.limit(opts[:limit])
|
354
|
+
# end
|
349
355
|
|
350
356
|
if type == :delete
|
351
357
|
# Recursively call 'deletion_query_parser' on association query, to delete any if the assoc's dependencies
|
@@ -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)
|