Module: PgHaMigrations::DependentObjectsChecks

Defined in:
lib/pg_ha_migrations/dependent_objects_checks.rb

Defined Under Namespace

Classes: ObjectDependency

Constant Summary collapse

ALLOWED_TYPES_OPTIONS =
[:indexes].freeze

Instance Method Summary collapse

Instance Method Details

#dependent_objects_for_migration_method(method_name, arguments:) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/pg_ha_migrations/dependent_objects_checks.rb', line 10

def dependent_objects_for_migration_method(method_name, arguments:)
  allowed_types = arguments.last.is_a?(Hash) ? arguments.last[:allow_dependent_objects] || [] : []

  if (invalid_allowed_types = allowed_types - ALLOWED_TYPES_OPTIONS).present?
    raise ArgumentError, "Received invalid entries in allow_dependent_objects: #{invalid_allowed_types.inspect}"
  end

  dependent_objects = []

  case method_name
  when :remove_column
    table_name = arguments[0]
    column_name = arguments[1]

    unless allowed_types.include?(:indexes)
      # https://www.postgresql.org/docs/current/catalog-pg-depend.html
      # deptype:
      # - 'a' (DEPENDENCY_AUTO): the dependent object should be automatically
      #   dropped if the referenced object is dropped
      indexes = ActiveRecord::Base.structs_from_sql(ObjectDependency, <<~SQL)
        SELECT
          'column' AS owner_type,
          ref_attr.attname AS owner_name,
          'index' AS dependent_type,
          dep_class.relname AS dependent_name
        FROM pg_catalog.pg_depend
        JOIN pg_catalog.pg_class ref_class ON ref_class.oid = pg_depend.refobjid
        JOIN pg_catalog.pg_attribute ref_attr ON ref_attr.attrelid = ref_class.oid
          AND ref_attr.attnum = pg_depend.refobjsubid
        JOIN pg_catalog.pg_class dep_class ON dep_class.oid = pg_depend.objid
        WHERE pg_depend.deptype = 'a'
          AND pg_depend.refclassid = 'pg_class'::regclass
          -- This doesn't currently handle table names that are duplicative across schemas.
          AND ref_class.relname = '#{PG::Connection.escape_string(table_name.to_s)}'
          AND ref_attr.attname = '#{PG::Connection.escape_string(column_name.to_s)}'
          AND pg_depend.classid = 'pg_class'::regclass
      SQL
      dependent_objects.concat(indexes)
    end
  end
end

#disallow_migration_method_if_dependent_objects!(method_name, arguments:) ⇒ Object



52
53
54
55
56
57
58
# File 'lib/pg_ha_migrations/dependent_objects_checks.rb', line 52

def disallow_migration_method_if_dependent_objects!(method_name, arguments:)
  dependent_objects = dependent_objects_for_migration_method(method_name, arguments: arguments)

  if dependent_objects.present?
    raise PgHaMigrations::UnsafeMigrationError, dependent_objects.map(&:error_text).join("; ")
  end
end