Module: Ductwork::MigrationHelper

Included in:
Migration
Defined in:
lib/ductwork/migration_helper.rb

Defined Under Namespace

Classes: OpenTransactionError

Constant Summary collapse

AVAILABILITY_CLAIM_INDEX_NAME =
"index_ductwork_availabilities_on_claim_latest"
AVAILABILITY_CLAIM_INDEX_NAME_V2 =
"index_ductwork_availabilities_on_claim_latest_v2"
AVAILABILITY_CLAIM_INDEX_NAMES =
[
  AVAILABILITY_CLAIM_INDEX_NAME,
  AVAILABILITY_CLAIM_INDEX_NAME_V2,
].freeze

Instance Method Summary collapse

Instance Method Details

#add_availability_claim_index(extra_columns: [], where_extra: nil, name: AVAILABILITY_CLAIM_INDEX_NAME, online: false) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/ductwork/migration_helper.rb', line 14

def add_availability_claim_index(
  extra_columns: [],
  where_extra: nil,
  name: AVAILABILITY_CLAIM_INDEX_NAME,
  online: false
)
  if mysql?
    columns = [:pipeline_klass, :completed_at, *extra_columns, :started_at]
    options = { name: }
  else
    columns = %i[pipeline_klass started_at]
    options = {
      name: name,
      where: ["completed_at IS NULL", where_extra].compact.join(" AND "),
    }
  end

  if online
    add_index_online :ductwork_availabilities, columns, **options
  else
    add_index :ductwork_availabilities, columns, **options
  end
end

#add_index_online(table_name, column_names, **options) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/ductwork/migration_helper.rb', line 59

def add_index_online(table_name, column_names, **options)
  ensure_ddl_transaction_disabled!

  name = options[:name] || connection.index_name(table_name, column_names)

  drop_invalid_index(table_name, name)

  return if connection.index_name_exists?(table_name, name)

  full_options = options.merge(name:)
  full_options[:algorithm] = :concurrently if postgresql?

  add_index table_name, column_names, **full_options
end

#belongs_to(table_object, association_name, **options) ⇒ Object



123
124
125
126
127
128
129
130
131
# File 'lib/ductwork/migration_helper.rb', line 123

def belongs_to(table_object, association_name, **options)
  full_options = if postgresql?
                   { type: uuid_column_type }.merge(options)
                 else
                   { type: uuid_column_type, limit: 36 }.merge(options)
                 end

  table_object.belongs_to association_name, **full_options
end

#create_ductwork_table(table_name, &block) ⇒ Object



112
113
114
115
116
117
118
119
120
121
# File 'lib/ductwork/migration_helper.rb', line 112

def create_ductwork_table(table_name, &block)
  if postgresql?
    create_table table_name, id: :uuid, &block
  else
    create_table table_name, id: false do |table|
      table.string :id, limit: 36, null: false, primary_key: true
      block.call(table)
    end
  end
end

#drop_invalid_index(table_name, index_name) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/ductwork/migration_helper.rb', line 85

def drop_invalid_index(table_name, index_name)
  return unless postgresql?

  invalid = connection.select_value(<<~SQL.squish)
    SELECT 1 FROM pg_index
    WHERE indexrelid = to_regclass(#{connection.quote(index_name)})
      AND NOT indisvalid
  SQL

  return if invalid.blank?

  remove_index table_name,
               name: index_name,
               algorithm: :concurrently,
               if_exists: true
end

#ensure_ddl_transaction_disabled!Object



102
103
104
105
106
107
108
109
110
# File 'lib/ductwork/migration_helper.rb', line 102

def ensure_ddl_transaction_disabled!
  return unless postgresql?
  return unless connection.transaction_open?

  raise OpenTransactionError, <<~MESSAGE.squish
    online index changes cannot run inside a transaction on PostgreSQL;
    declare `disable_ddl_transaction!` in the migration
  MESSAGE
end

#mysql?Boolean

Returns:

  • (Boolean)


145
146
147
# File 'lib/ductwork/migration_helper.rb', line 145

def mysql?
  connection.adapter_name.match?(/mysql|trilogy/i)
end

#postgresql?Boolean

Returns:

  • (Boolean)


141
142
143
# File 'lib/ductwork/migration_helper.rb', line 141

def postgresql?
  connection.adapter_name.match?(/postgresql/i)
end

#remove_availability_claim_index(name: AVAILABILITY_CLAIM_INDEX_NAME) ⇒ Object



38
39
40
# File 'lib/ductwork/migration_helper.rb', line 38

def remove_availability_claim_index(name: AVAILABILITY_CLAIM_INDEX_NAME)
  remove_index :ductwork_availabilities, name: name, if_exists: true
end

#remove_index_online(table_name, name:) ⇒ Object



74
75
76
77
78
79
80
81
82
83
# File 'lib/ductwork/migration_helper.rb', line 74

def remove_index_online(table_name, name:)
  ensure_ddl_transaction_disabled!

  return unless connection.index_name_exists?(table_name, name)

  options = { name: name, if_exists: true }
  options[:algorithm] = :concurrently if postgresql?

  remove_index table_name, **options
end

#swap_availability_claim_index(to:, extra_columns: [], where_extra: nil) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ductwork/migration_helper.rb', line 42

def swap_availability_claim_index(to:, extra_columns: [], where_extra: nil)
  unless AVAILABILITY_CLAIM_INDEX_NAMES.include?(to)
    raise ArgumentError, "unrecognized availability claim index name: #{to}"
  end

  add_availability_claim_index(
    extra_columns: extra_columns,
    where_extra: where_extra,
    name: to,
    online: true
  )

  (AVAILABILITY_CLAIM_INDEX_NAMES - [to]).each do |stale|
    remove_index_online :ductwork_availabilities, name: stale
  end
end

#uuid_column_typeObject



133
134
135
136
137
138
139
# File 'lib/ductwork/migration_helper.rb', line 133

def uuid_column_type
  if postgresql?
    :uuid
  else
    :string
  end
end