Module: SafePgMigrations::IdempotentStatements

Includes:
Helpers::IndexHelper
Defined in:
lib/safe-pg-migrations/plugins/idempotent_statements.rb

Instance Method Summary collapse

Methods included from Helpers::IndexHelper

#index_definition

Instance Method Details

#add_check_constraint(table_name, expression, **options) ⇒ Object



84
85
86
87
88
89
90
91
92
93
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 84

def add_check_constraint(table_name, expression, **options)
  options_without_validate = options.except(:validate)
  constraint_definition = check_constraint_for table_name,
                                               **check_constraint_options(table_name, expression,
                                                                          options_without_validate)

  return super if constraint_definition.nil?

  log_message("/!\\ Constraint '#{constraint_definition.name}' already exists. Skipping statement.")
end

#add_column(table_name, column_name, type, **options) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 21

def add_column(table_name, column_name, type, **options)
  if column_exists?(table_name, column_name) && !column_exists?(table_name, column_name, type)
    error_message = "/!\\ Column '#{column_name}' already exists in '#{table_name}' with a different type"
    raise error_message
  end

  options_without_default_value_backfill = options.except(:default_value_backfill)

  if column_exists?(table_name, column_name, type)
    log_message(<<~MESSAGE.squish
      /!\\ Column '#{column_name}' already exists in '#{table_name}' with the same type (#{type}).
      Skipping statement.
    MESSAGE
               )
  else
    super(table_name, column_name, type, **options_without_default_value_backfill)
  end
end

#add_foreign_key(from_table, to_table, **options) ⇒ Object



54
55
56
57
58
59
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 54

def add_foreign_key(from_table, to_table, **options)
  sub_options = options.slice(:name, :column)
  return super unless foreign_key_exists?(from_table, sub_options.present? ? nil : to_table, **sub_options)

  log_message("/!\\ Foreign key '#{from_table}' -> '#{to_table}' already exists. Skipping statement.")
end

#add_index(table_name, column_name, **options) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 7

def add_index(table_name, column_name, **options)
  index_definition = index_definition(table_name, column_name, **options)

  return super unless index_name_exists?(index_definition.table, index_definition.name)

  if index_valid?(index_definition.name)
    log_message("/!\\ Index '#{index_definition.name}' already exists in '#{table_name}'. Skipping statement.")
    return
  end

  remove_index(table_name, column_name, **options)
  super
end

#change_column_default(table_name, column_name, default_or_changes) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 111

def change_column_default(table_name, column_name, default_or_changes)
  column = column_for(table_name, column_name)
  previous_alter_statement = change_column_default_for_alter(table_name, column_name, column.default)
  new_alter_statement = change_column_default_for_alter(table_name, column_name, default_or_changes)

  # NOTE: PG change_column_default is already idempotent.
  # We try to detect it because it still takes an ACCESS EXCLUSIVE lock

  return super if new_alter_statement != previous_alter_statement

  log_message(<<~MESSAGE.squish
    /!\\ Column '#{table_name}.#{column.name}' is already set to 'default: #{column.default}'.
    Skipping statement.
  MESSAGE
             )
end

#change_column_null(table_name, column_name, null) ⇒ Object



95
96
97
98
99
100
101
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 95

def change_column_null(table_name, column_name, null, *)
  column = column_for(table_name, column_name)

  return super if column.null != null

  log_message("/!\\ Column '#{table_name}.#{column.name}' is already set to 'null: #{null}'. Skipping statement.")
end

#create_table(table_name, **options) {|td| ... } ⇒ Object

Yields:

  • (td)


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 68

def create_table(table_name, **options)
  return super if options[:force] || !table_exists?(table_name)

  Helpers::Logger.say "/!\\ Table '#{table_name}' already exists.", sub_item: true

  td = create_table_definition(table_name, **options)

  yield td if block_given?

  Helpers::Logger.say td.indexes.empty? ? '-- Skipping statement' : '-- Creating indexes', sub_item: true

  td.indexes.each do |column_name, index_options|
    add_index(table_name, column_name, **index_options)
  end
end

#drop_table(table_name, **options) ⇒ Object



128
129
130
131
132
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 128

def drop_table(table_name, **options)
  return super if table_exists?(table_name)

  log_message("/!\\ Table '#{table_name} does not exist. Skipping statement.")
end

#remove_column(table_name, column_name, type = nil, **options) ⇒ Object



40
41
42
43
44
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 40

def remove_column(table_name, column_name, type = nil, **options)
  return super if column_exists?(table_name, column_name)

  log_message("/!\\ Column '#{column_name}' not found on table '#{table_name}'. Skipping statement.")
end

#remove_foreign_key(from_table, to_table = nil, **options) ⇒ Object



61
62
63
64
65
66
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 61

def remove_foreign_key(from_table, to_table = nil, **options)
  return super if foreign_key_exists?(from_table, to_table, **options)

  reference_name = to_table || options[:to_table] || options[:column] || options[:name]
  log_message("/!\\ Foreign key '#{from_table}' -> '#{reference_name}' does not exist. Skipping statement.")
end

#remove_index(table_name, column_name = nil, **options) ⇒ Object



46
47
48
49
50
51
52
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 46

def remove_index(table_name, column_name = nil, **options)
  index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, column: column_name)

  return super if index_name_exists?(table_name, index_name)

  log_message("/!\\ Index '#{index_name}' not found on table '#{table_name}'. Skipping statement.")
end

#validate_check_constraint(table_name, **options) ⇒ Object



103
104
105
106
107
108
109
# File 'lib/safe-pg-migrations/plugins/idempotent_statements.rb', line 103

def validate_check_constraint(table_name, **options)
  constraint_definition = check_constraint_for!(table_name, **options)

  return super unless constraint_definition.validated?

  log_message("/!\\ Constraint '#{constraint_definition.name}' already validated. Skipping statement.")
end