Class: BulkDependencyEraser::Builder

Inherits:
Base
  • Object
show all
Defined in:
lib/bulk_dependency_eraser/builder.rb

Constant Summary collapse

DEFAULT_DB_BUILD_ALL_WRAPPER =
->(builder, block) do
  begin
    block.call
  rescue StandardError => e
    builder.report_error(
      <<~STRING.strip
      Issue attempting to build deletion query for '#{e.building_klass_name}'
        => #{e.original_error_klass.name}: #{e.message}
      STRING
    )
  end
end
DEFAULT_OPTS =
{
  force_destroy_restricted: false,
  verbose: false,
  db_build_all_wrapper: self::DEFAULT_DB_BUILD_ALL_WRAPPER,
  # Some associations scopes take parameters.
  # - We would have to instantiate if we wanted to apply that scope filter.
  instantiate_if_assoc_scope_with_arity: false,
  # wraps around the DB reading
  db_read_wrapper: self::DEFAULT_DB_READ_WRAPPER,
  # Will parse these tables and their dependencies, but will remove the tables from the lists after parsing.
  ignore_tables: [],
  # Won't parse any table in this list
  ignore_tables_and_dependencies: [],
  ignore_klass_names_and_dependencies: [],
  disable_batching: false,
  # a general batching size
  batch_size: 10_000,
  # A specific batching size for this class, overrides the batch_size
  read_batch_size: nil,
  # A specific read batching disable option
  disable_read_batching: nil,
  # Applied to all queries. Useful for taking advantage of specific indexes
  # - not indexed by klass name. Proc would handle the logic for that.
  # - 3rd, and lowest, priority of scopes
  # - accepts rails query as parameter
  # - return nil if no applicable scope.
  proc_scopes: self::DEFAULT_SCOPE_WRAPPER,
  # Applied to all queries. Useful for taking advantage of specific indexes
  # - 2nd highest priority of scopes
  proc_scopes_per_class_name: {},
  # Applied to reading queries
  # - 1st priority of scopes
  reading_proc_scopes_per_class_name: {},
}.freeze

Constants inherited from Base

BulkDependencyEraser::Base::DEFAULT_DB_BLANK_WRAPPER, BulkDependencyEraser::Base::DEFAULT_DB_READ_WRAPPER, BulkDependencyEraser::Base::DEFAULT_DB_WRITE_WRAPPER, BulkDependencyEraser::Base::DEFAULT_KLASS_MAPPED_SCOPE_WRAPPER, BulkDependencyEraser::Base::DEFAULT_SCOPE_WRAPPER, BulkDependencyEraser::Base::DEPENDENCY_DESTROY, BulkDependencyEraser::Base::DEPENDENCY_DESTROY_IGNORE_REFLECTION_TYPES, BulkDependencyEraser::Base::DEPENDENCY_NULLIFY, BulkDependencyEraser::Base::DEPENDENCY_RESTRICT, BulkDependencyEraser::Base::POLY_KLASS_NAME

Instance Attribute Summary collapse

Attributes inherited from Base

#errors

Instance Method Summary collapse

Methods inherited from Base

#merge_errors, #report_error

Methods included from Utils::Methods

#deep_freeze

Constructor Details

#initialize(query:, opts: {}) ⇒ Builder

Returns a new instance of Builder.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/bulk_dependency_eraser/builder.rb', line 59

def initialize query:, opts: {}
  @query = query
  @deletion_list  = {}
  @nullification_list = {}

  # For any ignored table results, they will be stored here
  @ignore_table_deletion_list = {}
  @ignore_table_nullification_list = {}

  @table_names_to_parsed_klass_names = {}

  super(opts:)

  @ignore_table_name_and_dependencies = opts_c.ignore_tables_and_dependencies.collect { |table_name| table_name }
  @ignore_klass_name_and_dependencies = opts_c.ignore_klass_names_and_dependencies.collect { |klass_name| klass_name }
  @query_schema_parser = BulkDependencyEraser::QuerySchemaParser.new(query:, opts:)
  # Moving pointer, points to the current class that is being queries
  @current_klass_name = query.is_a?(ActiveRecord::Relation) ? query.klass.name : query.name
end

Instance Attribute Details

#current_klass_nameObject (readonly)

Returns the value of attribute current_klass_name.



55
56
57
# File 'lib/bulk_dependency_eraser/builder.rb', line 55

def current_klass_name
  @current_klass_name
end

#deletion_listObject

write access so that these can be edited in-place by end-users who might need to manually adjust deletion order.



52
53
54
# File 'lib/bulk_dependency_eraser/builder.rb', line 52

def deletion_list
  @deletion_list
end

#ignore_table_deletion_listObject (readonly)

Returns the value of attribute ignore_table_deletion_list.



53
54
55
# File 'lib/bulk_dependency_eraser/builder.rb', line 53

def ignore_table_deletion_list
  @ignore_table_deletion_list
end

#ignore_table_nullification_listObject (readonly)

Returns the value of attribute ignore_table_nullification_list.



53
54
55
# File 'lib/bulk_dependency_eraser/builder.rb', line 53

def ignore_table_nullification_list
  @ignore_table_nullification_list
end

#nullification_listObject

write access so that these can be edited in-place by end-users who might need to manually adjust deletion order.



52
53
54
# File 'lib/bulk_dependency_eraser/builder.rb', line 52

def nullification_list
  @nullification_list
end

#query_schema_parserObject (readonly)

Returns the value of attribute query_schema_parser.



54
55
56
# File 'lib/bulk_dependency_eraser/builder.rb', line 54

def query_schema_parser
  @query_schema_parser
end

Instance Method Details

#buildObject



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/bulk_dependency_eraser/builder.rb', line 101

def build
  build_all_in_db do
    begin
      if opts_c.verbose
        puts "Starting build for #{@query.is_a?(ActiveRecord::Relation) ? @query.klass.name : @query.name}"
      end

      deletion_query_parser(@query)

      uniqify_errors!

      return errors.none?
    rescue StandardError => e
      raise BulkDependencyEraser::Errors::BuilderError.new(e.class, e.message, building_klass_name: current_klass_name)
    end
  end
end

#executeObject



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/bulk_dependency_eraser/builder.rb', line 79

def execute
  unless query_schema_parser.execute
    merge_errors(full_schema_parser.errors, 'QuerySchemaParser: ')
    return false
  end

  # go through deletion/nullification lists and remove any tables from 'ignore_tables' option
  build_result = build

  # move any klass names if told to ignore them into their respective new lists
  # - prior approach was to use table_name.classify, but we can't trust that approach.
  opts_c.ignore_tables.each do |table_name|
    table_names_to_parsed_klass_names.dig(table_name)&.each do |klass_name|
      klass_index = deletion_index_key(klass_name.constantize)
      ignore_table_deletion_list[klass_index]      = deletion_list.delete(klass_index)      if deletion_list.key?(klass_index)
      ignore_table_nullification_list[klass_index] = nullification_list.delete(klass_index) if nullification_list.key?(klass_index)
    end
  end

  return build_result
end