bulk_dependency_eraser 3.0.0 → 4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 954e4ce7b9c7d42a0cdcdc1403592dce3e61c6c196e72858a5c2f66f5be3e3df
4
- data.tar.gz: 18233fefb36153a49d43d4aed40e3f44ca0f3123d346429a0a0b50a355577a16
3
+ metadata.gz: 16b8469147c79e15bbd947d75f9b9e7aa243f219be6796f516967a4f134609bd
4
+ data.tar.gz: a7a45c24562a67a1762d120caa9b4a14ab211594245383be4b21a70fa9f5a5e0
5
5
  SHA512:
6
- metadata.gz: e57be3e7ab4203123f919530710dd4f63842abbf588b49896fa78b2cb3fcf0c58d7e64e2881b165396cb919a897acfe3279d2c3d740a3c8f0ace8dfd923eb3c0
7
- data.tar.gz: 3b05c7edc262d1cf0b663d451084698b52f2e11fb8ec03a057ac70551f630d35ad67530921f24535288adf1761377981e69803bb7519e8f4449977dab8ec56ca
6
+ metadata.gz: 8ea34f3b1963b7c8d7720292a47edffb1351f18b6ecb6822e2965fe96244700044d9dcba8124cc088033d3114da0775b0a3be0c4636424af11c101e5e90fb686
7
+ data.tar.gz: fe4901ea4c7f99ef0e5228b94280f76b6102ef9686c2a8a6fa5fcb4da768fc0303e1da2929a1672bfea77ebcb0e42c9692c7774df21bf891d4e8054979d2c3ea
@@ -28,6 +28,12 @@ module BulkDependencyEraser
28
28
  ignore_tables_and_dependencies: [],
29
29
  ignore_klass_names_and_dependencies: [],
30
30
  disable_batching: false,
31
+ # Disable model ordering during build batching
32
+ # - Some tables can be too big to order, and just need to trust the DB order
33
+ # - Not 100% guaranteed and could leave orphaned records behind.
34
+ disable_batch_ordering: false,
35
+ # Same as 'disable_batch_ordering', but only for select classes
36
+ disable_batch_ordering_for_klasses: [],
31
37
  # a general batching size
32
38
  batch_size: 10_000,
33
39
  # A specific batching size for this class, overrides the batch_size
@@ -46,10 +52,13 @@ module BulkDependencyEraser
46
52
  # Applied to reading queries
47
53
  # - 1st priority of scopes
48
54
  reading_proc_scopes_per_class_name: {},
55
+ # Using PG system column CTID can result in a 10x deletion speed increase
56
+ # - is used in combination with the primary key column to ensure CTID hasn't changed.
57
+ use_pg_system_column_ctid: false,
49
58
  }.freeze
50
59
 
51
60
  # write access so that these can be edited in-place by end-users who might need to manually adjust deletion order.
52
- attr_accessor :deletion_list, :nullification_list
61
+ attr_accessor :deletion_list, :nullification_list, :deletion_list_with_additional_identifiers
53
62
  attr_reader :ignore_table_deletion_list, :ignore_table_nullification_list
54
63
  attr_reader :query_schema_parser
55
64
  attr_reader :current_klass_name
@@ -59,6 +68,15 @@ module BulkDependencyEraser
59
68
  def initialize query:, opts: {}
60
69
  @query = query
61
70
  @deletion_list = {}
71
+ # CTID column values are stored here
72
+ # - key: <klass_name (with or without suffixes)>
73
+ # - value: Hash
74
+ # - key: Individual record's ID
75
+ # - value: Hash
76
+ # - key: Column Name
77
+ # - value: plucked column value
78
+ # - these additional identifiers will be used when deleting the klasses
79
+ @deletion_list_with_additional_identifiers = {}
62
80
  @nullification_list = {}
63
81
 
64
82
  # For any ignored table results, they will be stored here
@@ -89,9 +107,13 @@ module BulkDependencyEraser
89
107
  # - prior approach was to use table_name.classify, but we can't trust that approach.
90
108
  opts_c.ignore_tables.each do |table_name|
91
109
  table_names_to_parsed_klass_names.dig(table_name)&.each do |klass_name|
92
- klass_index = deletion_index_key(klass_name.constantize)
93
- ignore_table_deletion_list[klass_index] = deletion_list.delete(klass_index) if deletion_list.key?(klass_index)
94
- ignore_table_nullification_list[klass_index] = nullification_list.delete(klass_index) if nullification_list.key?(klass_index)
110
+ klass = klass_name.constantize
111
+ # Delete klasses from the deletion/nullification lists if they are from ignored tables.
112
+ # - Handles klass name indexes, with and without suffices.
113
+ deletion_index_keys(klass).each do |klass_index|
114
+ ignore_table_deletion_list[klass_index] = deletion_list.delete(klass_index) if deletion_list.key?(klass_index)
115
+ ignore_table_nullification_list[klass_index] = nullification_list.delete(klass_index) if nullification_list.key?(klass_index)
116
+ end
95
117
  end
96
118
  end
97
119
 
@@ -131,35 +153,80 @@ module BulkDependencyEraser
131
153
  end
132
154
  end
133
155
 
134
- def pluck_from_query(query, column = :id)
156
+ # @param [ActiveRecord::Relation] query
157
+ # @param [Symbol | Array<Symbol>] column - primary_key must be the first or only element in the column.
158
+ # @return [
159
+ # [Array<String | Int>] array of column values,
160
+ # [Hash] hash of column/value pairings - additional identifiers.
161
+ # ]
162
+ def pluck_from_query(query, column = :id, skip_ctid_check: false)
163
+ if column.is_a?(Array)
164
+ columns = column
165
+ else
166
+ columns = [column]
167
+ end
168
+
169
+ # Only pluck CTID if we're plucking column :id (the only primary key supported)
170
+ if columns == [:id] && opts_c.use_pg_system_column_ctid && skip_ctid_check == false
171
+ columns << :ctid
172
+ end
173
+
135
174
  set_current_klass_name(query)
136
175
  # ordering shouldn't matter in these queries, and would slow it down
137
176
  # - we're ignoring default_scope ordering, but assoc-defined ordering would still take effect
138
177
  query = query.reorder('')
139
178
  query = custom_scope_for_query(query)
140
179
 
141
- query_ids = []
180
+ query_results = []
142
181
  read_from_db do
143
182
  # If the query has a limit, then we don't want to clobber with batching.
144
183
  if batching_disabled? || !query.where({}).limit_value.nil?
145
184
  # query without batching
146
- query_ids = query.pluck(column)
147
- else
148
- # query with batching
185
+ query_results = query.pluck(*columns)
186
+ elsif opts_c.disable_batch_ordering || opts_c.disable_batch_ordering_for_klasses.include?(current_klass_name)
187
+ # query with orderless batching
149
188
  offset = 0
150
189
  loop do
151
- new_query_ids = query.offset(offset).limit(batch_size).pluck(column)
152
- query_ids += new_query_ids
190
+ new_query_results = query.offset(offset).limit(batch_size).pluck(*columns)
191
+ query_results += new_query_results
153
192
 
154
- break if new_query_ids.size < batch_size
193
+ break if new_query_results.size < batch_size
155
194
 
156
195
  # Move to the next batch
157
196
  offset += batch_size
158
197
  end
198
+ else
199
+ # query with ordered batching
200
+ query.in_batches(of: batch_size) do |subset_query|
201
+ query_results += subset_query.pluck(*columns)
202
+ end
203
+ end
204
+ end
205
+
206
+ # Early exit if we only plucked one column.
207
+ # - query_results would just be an array of IDs
208
+ return [query_results, nil] if columns.count == 1
209
+
210
+ transposed_results = query_results.transpose
211
+
212
+ query_primary_keys = transposed_results.shift || [] # could be an empty id set
213
+ columns.shift # shift of the primary key column
214
+
215
+ query_additional_identifiers = {}
216
+ results_per_additional_column = {}
217
+ columns.each do |column|
218
+ column_results = transposed_results.shift
219
+ results_per_additional_column[column] = column_results
220
+ end
221
+
222
+ query_primary_keys.each_with_index do |primary_key, plucked_index|
223
+ query_additional_identifiers[primary_key] ||= {}
224
+ results_per_additional_column.each do |column, column_results|
225
+ query_additional_identifiers[primary_key][column] = column_results[plucked_index]
159
226
  end
160
227
  end
161
228
 
162
- return query_ids
229
+ return query_primary_keys, query_additional_identifiers
163
230
  end
164
231
 
165
232
  def batch_size
@@ -170,6 +237,32 @@ module BulkDependencyEraser
170
237
  opts_c.disable_read_batching.nil? ? opts_c.disable_batching : opts_c.disable_read_batching
171
238
  end
172
239
 
240
+ # No need for recursion here. Nullifying does not effect nested dependencies
241
+ def nullification_query_parser(query, nullfication_klass, klass_foreign_key, klass_foreign_type = nil)
242
+ # We're not destroying these assocs (just nullifying foreign_key columns) so we don't need to parse their dependencies.
243
+ # Setting skip_ctid_check: true because we currently don't support CTID with nullifications yet
244
+ assoc_ids, additional_identifiers_by_id = pluck_from_query(query, skip_ctid_check: true)
245
+ klass_name = nullfication_klass.name
246
+
247
+ # No assoc_ids, no need to add it to the nullification list
248
+ return if assoc_ids.none?
249
+
250
+ klass_foreign_key = klass_foreign_key.to_s
251
+ nullification_list[klass_name] ||= {}
252
+ nullification_list[klass_name][klass_foreign_key] ||= []
253
+ nullification_list[klass_name][klass_foreign_key] += assoc_ids
254
+ nullification_list[klass_name][klass_foreign_key].uniq!
255
+
256
+
257
+ # Also nullify the 'type' field, if the association is polymorphic
258
+ if klass_foreign_type
259
+ klass_foreign_type = klass_foreign_type.to_s
260
+ nullification_list[klass_name][klass_foreign_type] ||= []
261
+ nullification_list[klass_name][klass_foreign_type] += assoc_ids
262
+ nullification_list[klass_name][klass_foreign_type].uniq!
263
+ end
264
+ end
265
+
173
266
  def deletion_query_parser query, association_parent = nil
174
267
  # necessary for "ActiveRecord::Reflection::ThroughReflection" use-case
175
268
  # force_through_destroy_chains = options[:force_destroy_chain] || {}
@@ -214,24 +307,28 @@ module BulkDependencyEraser
214
307
  end
215
308
 
216
309
  # Pluck IDs of the current query
217
- query_ids = pluck_from_query(query)
310
+ query_ids, additional_identifiers_by_id = pluck_from_query(query)
218
311
 
219
312
  klass_index = initialize_deletion_list_for_klass(klass)
220
313
 
221
314
  # prevent infinite recursion here.
222
315
  # - Remove any IDs that have been processed before
223
- query_ids = remove_already_deletion_processed_ids(klass, query_ids)
316
+ query_ids, additional_identifiers_by_id = remove_already_deletion_processed_ids(klass, query_ids, additional_identifiers_by_id:)
224
317
 
225
318
  # If ids are nil, let's find that error
226
319
  if query_ids.none? #|| query_ids.nil?
227
320
  # quick cleanup, if turns out was an empty class
228
- deletion_list.delete(klass_index) if deletion_list[klass_index].none?
321
+ if deletion_list[klass_index].none?
322
+ deletion_list.delete(klass_index)
323
+ deletion_list_with_additional_identifiers.delete(klass_index)
324
+ end
229
325
  return
230
326
  end
231
327
 
232
328
  # Use-case: We have more IDs to process
233
329
  # - can now safely add to the list, since we've prevented infinite recursion
234
330
  deletion_list[klass_index] += query_ids
331
+ deletion_list_with_additional_identifiers[klass_index].merge!(additional_identifiers_by_id)
235
332
 
236
333
  # ignore associations that aren't a dependent destroyable type
237
334
  destroy_associations = query.reflect_on_all_associations.select do |reflection|
@@ -367,25 +464,25 @@ module BulkDependencyEraser
367
464
  end
368
465
 
369
466
  # Look for manually specified keys in the assocation first
370
- specified_primary_key = reflection.options[:primary_key]&.to_s
371
- specified_foreign_key = reflection.options[:foreign_key]&.to_s
467
+ specified_primary_key = reflection.options[:primary_key]&.to_sym
468
+ specified_foreign_key = reflection.options[:foreign_key]&.to_sym
372
469
  # For polymorphic_associations
373
470
  specified_foreign_type = nil
374
471
 
375
472
  # handle foreign_key edge cases
376
473
  if specified_foreign_key.nil?
377
474
  if reflection.options[:as]
378
- specified_foreign_type = "#{reflection.options[:as]}_type"
379
- specified_foreign_key = "#{reflection.options[:as]}_id"
475
+ specified_foreign_type = "#{reflection.options[:as]}_type".to_sym
476
+ specified_foreign_key = "#{reflection.options[:as]}_id".to_sym
380
477
  # Only filtering by type here, the extra work for a poly assoc. We filter by IDs later
381
- assoc_query = assoc_query.where({ specified_foreign_type.to_sym => parent_class.name })
478
+ assoc_query = assoc_query.where({ specified_foreign_type => parent_class.name })
382
479
  else
383
- specified_foreign_key = parent_class.table_name.singularize + "_id"
480
+ specified_foreign_key = "#{parent_class.table_name.singularize}_id".to_sym
384
481
  end
385
482
  end
386
483
 
387
484
  # Check to see if foreign_key exists in association class's table
388
- unless assoc_klass.column_names.include?(specified_foreign_key)
485
+ unless assoc_klass.column_names.include?(specified_foreign_key.to_s)
389
486
  report_error(
390
487
  "
391
488
  For #{parent_class.name}'s assoc '#{assoc_klass.name}': Could not determine the assoc's foreign key.
@@ -398,11 +495,11 @@ module BulkDependencyEraser
398
495
  # Build association query, based on parent class's primary key and the assoc's foreign key
399
496
  # - handle primary key edge cases
400
497
  # - The associations might not be using the primary_key of the klass table, but we can support that here.
401
- if specified_primary_key && specified_primary_key&.to_s != 'id'
402
- alt_primary_ids = pluck_from_query(query, specified_primary_key)
403
- assoc_query = assoc_query.where(specified_foreign_key.to_sym => alt_primary_ids)
498
+ if specified_primary_key && specified_primary_key != :id
499
+ alt_primary_ids, _ = pluck_from_query(query, specified_primary_key)
500
+ assoc_query = assoc_query.where(specified_foreign_key => alt_primary_ids)
404
501
  else
405
- assoc_query = assoc_query.where(specified_foreign_key.to_sym => query_ids)
502
+ assoc_query = assoc_query.where(specified_foreign_key => query_ids)
406
503
  end
407
504
 
408
505
  # remove any ordering or limits imposed on the association queries from the association definitions
@@ -416,25 +513,7 @@ module BulkDependencyEraser
416
513
  deletion_query_parser(assoc_query, parent_class)
417
514
  end
418
515
  elsif type == :nullify
419
- # No need for recursion here.
420
- # - we're not destroying these assocs (just nullifying foreign_key columns) so we don't need to parse their dependencies.
421
- assoc_ids = pluck_from_query(assoc_query)
422
-
423
- # No assoc_ids, no need to add it to the nullification list
424
- return if assoc_ids.none?
425
-
426
- nullification_list[assoc_klass_name] ||= {}
427
- nullification_list[assoc_klass_name][specified_foreign_key] ||= []
428
- nullification_list[assoc_klass_name][specified_foreign_key] += assoc_ids
429
- nullification_list[assoc_klass_name][specified_foreign_key].uniq!
430
-
431
-
432
- # Also nullify the 'type' field, if the association is polymorphic
433
- if specified_foreign_type
434
- nullification_list[assoc_klass_name][specified_foreign_type] ||= []
435
- nullification_list[assoc_klass_name][specified_foreign_type] += assoc_ids
436
- nullification_list[assoc_klass_name][specified_foreign_type].uniq!
437
- end
516
+ nullification_query_parser(assoc_query, assoc_klass, specified_foreign_key, specified_foreign_type)
438
517
  else
439
518
  raise "invalid parsing type: #{type}"
440
519
  end
@@ -520,7 +599,7 @@ module BulkDependencyEraser
520
599
  return
521
600
  end
522
601
 
523
- foreign_keys = pluck_from_query(query, specified_foreign_key)
602
+ foreign_keys, _ = pluck_from_query(query, specified_foreign_key, skip_ctid_check: true)
524
603
  assoc_query = assoc_query.where(
525
604
  specified_primary_key.to_sym => foreign_keys
526
605
  )
@@ -679,8 +758,14 @@ module BulkDependencyEraser
679
758
  opts_c.db_read_wrapper.call(block)
680
759
  end
681
760
 
682
- def remove_already_deletion_processed_ids(klass, new_ids)
761
+ # @return [
762
+ # [Array] array of IDs that haven't already been added to the deletion list
763
+ # [Hash | Nil] the additional deletion query identifiers, minus the ones already processed
764
+ # - will be nil if we're not plucking additional columns.
765
+ # ]
766
+ def remove_already_deletion_processed_ids(klass, new_ids, additional_identifiers_by_id: nil)
683
767
  already_processed_ids = []
768
+ additional_identifiers_by_id ||= {}
684
769
 
685
770
  if is_a_circular_dependency_klass?(klass)
686
771
  klass_keys = find_circular_dependency_deletion_keys(klass)
@@ -691,7 +776,10 @@ module BulkDependencyEraser
691
776
  already_processed_ids = deletion_list[klass.name]
692
777
  end
693
778
 
694
- new_ids - already_processed_ids
779
+ return [
780
+ (new_ids - already_processed_ids),
781
+ additional_identifiers_by_id.except(*already_processed_ids)
782
+ ]
695
783
  end
696
784
 
697
785
  # Initializes deletion_list index
@@ -703,9 +791,11 @@ module BulkDependencyEraser
703
791
  raise "circular_index already existed for klass: #{klass.name}" if deletion_list.key?(klass_index)
704
792
 
705
793
  deletion_list[klass_index] = []
794
+ deletion_list_with_additional_identifiers[klass_index] = {}
706
795
  else
707
796
  # Not a circular dependency, define as normal
708
797
  deletion_list[klass_index] ||= []
798
+ deletion_list_with_additional_identifiers[klass_index] ||= {}
709
799
  end
710
800
 
711
801
  klass_index
@@ -723,6 +813,14 @@ module BulkDependencyEraser
723
813
  deletion_list.keys.select { |key| key.match?(regex) }
724
814
  end
725
815
 
816
+ # returns any current index keys, with or without suffix, in the deletion_list for the given klass param
817
+ def deletion_index_keys(klass)
818
+ klass_keys = []
819
+ klass_keys << klass.name if deletion_list.keys.include?(klass.name)
820
+ klass_keys += find_circular_dependency_deletion_keys(klass)
821
+ return klass_keys
822
+ end
823
+
726
824
  # If circular dependency, append a index suffix to the deletion hash key
727
825
  # - they will be deleted in highest index to lowest index order.
728
826
  def deletion_index_key(klass, increment_circular_index: false)
@@ -53,8 +53,9 @@ module BulkDependencyEraser
53
53
  deletion_proc_scopes_per_class_name: {},
54
54
  }.freeze
55
55
 
56
- def initialize class_names_and_ids: {}, opts: {}
56
+ def initialize class_names_and_ids: {}, additional_identifiers_by_id: {}, opts: {}
57
57
  @class_names_and_ids = class_names_and_ids
58
+ @additional_identifiers_by_id = additional_identifiers_by_id
58
59
  super(opts:)
59
60
  end
60
61
 
@@ -68,19 +69,23 @@ module BulkDependencyEraser
68
69
  begin
69
70
  class_names_and_ids.keys.reverse.each do |class_name|
70
71
  current_class_name = class_name
72
+ additional_identifiers = additional_identifiers_by_id[class_name]
73
+ raise "invalid state! #{class_name} not found in 'additional_identifiers_by_id' list" if additional_identifiers.nil?
74
+
75
+ # Last in, First out
71
76
  ids = class_names_and_ids[class_name].reverse
72
77
  klass = constantize(class_name)
73
78
 
74
79
  if opts_c.enable_invalid_foreign_key_detection
75
80
  # delete with referential integrity
76
- delete_by_klass_and_ids(klass, ids)
81
+ delete_by_klass_and_ids(klass, ids, additional_identifiers:)
77
82
  else
78
83
  # delete without referential integrity
79
84
  # Disable any ActiveRecord::InvalidForeignKey raised errors.
80
85
  # - src: https://stackoverflow.com/questions/41005849/rails-migrations-temporarily-ignore-foreign-key-constraint
81
86
  # https://apidock.com/rails/ActiveRecord/ConnectionAdapters/AbstractAdapter/disable_referential_integrity
82
87
  ActiveRecord::Base.connection.disable_referential_integrity do
83
- delete_by_klass_and_ids(klass, ids)
88
+ delete_by_klass_and_ids(klass, ids, additional_identifiers:)
84
89
  end
85
90
  end
86
91
  end
@@ -94,7 +99,7 @@ module BulkDependencyEraser
94
99
 
95
100
  protected
96
101
 
97
- attr_reader :class_names_and_ids
102
+ attr_reader :class_names_and_ids, :additional_identifiers_by_id
98
103
 
99
104
  def custom_scope_for_query(query)
100
105
  klass = query.klass
@@ -113,29 +118,49 @@ module BulkDependencyEraser
113
118
  opts_c.disable_delete_batching.nil? ? opts_c.disable_batching : opts_c.disable_delete_batching
114
119
  end
115
120
 
116
- def delete_by_klass_and_ids klass, ids
121
+ def delete_by_klass_and_ids(klass, ids, additional_identifiers:)
117
122
  puts "Deleting #{klass.name}'s IDs: #{ids}" if opts_c.verbose
118
123
  query = klass.unscoped
119
124
  query = custom_scope_for_query(query)
120
125
 
121
126
  if batching_disabled?
122
127
  puts "Deleting without batching" if opts_c.verbose
128
+ # Get column-names/keys of any additional identifer columns
129
+ detected_additional_identifier_columns = additional_identifiers.values.flat_map(&:keys).uniq
123
130
  delete_in_db do
124
- deletion_result = query.where(id: ids).delete_all
131
+ deletion_query = query.where(id: ids)
132
+ # Apply any additional query identifiers (i.e. :ctid column)
133
+ detected_additional_identifier_columns.each do |column|
134
+ deletion_query = deletion_query.where(column => additional_identifiers.values.pluck(column))
135
+ end
136
+
137
+ # Perform Deletion
138
+ deletion_result = deletion_query.delete_all
125
139
  # Returning the following data in the event that the gem-implementer wants to insert their own db_delete_wrapper proc
126
140
  # and have access to these objects in their proc.
127
141
  # - query can give them access to the klass and table_name
128
- [deletion_result, query, ids]
142
+ [deletion_result, query, ids, additional_identifiers]
129
143
  end
130
144
  else
131
145
  puts "Deleting with batching" if opts_c.verbose
132
146
  ids.each_slice(batch_size) do |ids_subset|
147
+ additional_identifiers_subset = additional_identifiers.slice(*ids_subset)
148
+ # Get column-names/keys of any additional identifer columns
149
+ detected_additional_identifier_columns = additional_identifiers_subset.values.flat_map(&:keys).uniq
133
150
  delete_in_db do
134
- deletion_result = query.where(id: ids_subset).delete_all
151
+ deletion_query = query.where(id: ids_subset)
152
+ # Apply any additional query identifiers (i.e. :ctid column)
153
+ detected_additional_identifier_columns.each do |column|
154
+ deletion_query = deletion_query.where(column => additional_identifiers_subset.values.pluck(column))
155
+ end
156
+
157
+ # Perform Deletion
158
+ deletion_result = deletion_query.delete_all
159
+
135
160
  # Returning the following data in the event that the gem-implementer wants to insert their own db_delete_wrapper proc
136
161
  # and have access to these objects in their proc.
137
162
  # - query can give them access to the klass and table_name
138
- [deletion_result, query, ids_subset]
163
+ [deletion_result, query, ids_subset, additional_identifiers_subset]
139
164
  end
140
165
  end
141
166
  end
@@ -7,7 +7,7 @@ module BulkDependencyEraser
7
7
  verbose: false,
8
8
  }.freeze
9
9
 
10
- delegate :nullification_list, :deletion_list, to: :dependency_builder
10
+ delegate :nullification_list, :deletion_list, :deletion_list_with_additional_identifiers, to: :dependency_builder
11
11
  delegate :ignore_table_deletion_list, :ignore_table_nullification_list, to: :dependency_builder
12
12
  delegate :circular_dependency_klasses, :flat_dependencies_per_klass, to: :dependency_builder
13
13
 
@@ -49,7 +49,11 @@ module BulkDependencyEraser
49
49
  end
50
50
 
51
51
  def delete!
52
- @deleter = BulkDependencyEraser::Deleter.new(class_names_and_ids: deletion_list, opts:)
52
+ @deleter = BulkDependencyEraser::Deleter.new(
53
+ class_names_and_ids: deletion_list,
54
+ additional_identifiers_by_id: deletion_list_with_additional_identifiers,
55
+ opts:
56
+ )
53
57
  deleter_execution = deleter.execute
54
58
  unless deleter_execution
55
59
  puts "Deleter execution FAILED" if opts_c.verbose
@@ -1,3 +1,3 @@
1
1
  module BulkDependencyEraser
2
- VERSION = "3.0.0".freeze
2
+ VERSION = "4.1.0".freeze
3
3
  end
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: 3.0.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - benjamin.dana.software.dev@gmail.com