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: dc8c21921516530d646fff41d72ce0157e1d706373eefea4da7ea924bb1cb9b9
4
- data.tar.gz: 9501007142223dfad5cb05e89ab38162499b564eaaf3636074e3cd54a573592f
3
+ metadata.gz: cbea15215c816eca6790c1d7c3cbf4f4f68534fc3ff18cc38e8c26dc7e94513d
4
+ data.tar.gz: 532a711c1290ea4fea4200acc75d9916eb18a2451207b89d1163372d7372028d
5
5
  SHA512:
6
- metadata.gz: 0f461d596eb9160828f0905dde68396ade1409f8f9c17de2e4bb8677cb12695be59c75f6fa33d84d9156a2b10fdab2eed869b7f19a79c84e1526c705ac4cf58b
7
- data.tar.gz: 64777768e6eb815d575d11690cb793962ab4fcb24911bc2bb209d5d7a33d3bc660b6d939fe287ca2c41dcac8524efe95032f3b6ee76272956391589193315666
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 opts_c.verbose
213
- puts "Destroyable Associations: #{destroy_association_names}"
214
- puts "Nullifiable Associations: #{nullify_association_names}"
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, { limit: 1 })
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
- # Apply limit if has_one assocation (subset of has_many)
346
- if opts[:limit]
347
- assoc_query = assoc_query.limit(opts[:limit])
348
- end
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
@@ -24,8 +24,7 @@ module BulkDependencyEraser
24
24
  return false unless build
25
25
  end
26
26
 
27
- delete!
28
- nullify!
27
+ nullify! && delete!
29
28
 
30
29
  return errors.none?
31
30
  end
@@ -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
- # Disable any ActiveRecord::InvalidForeignKey raised errors.
41
- # src https://stackoverflow.com/questions/41005849/rails-migrations-temporarily-ignore-foreign-key-constraint
42
- # https://apidock.com/rails/ActiveRecord/ConnectionAdapters/AbstractAdapter/disable_referential_integrity
43
- ActiveRecord::Base.connection.disable_referential_integrity do
44
- nullify_in_db do
45
- klass.unscoped.where(id: ids).update_all(column => nil)
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)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bulk_dependency_eraser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - benjamin.dana.software.dev@gmail.com