Class: Sequent::Migrations::Versions

Inherits:
ApplicationRecord show all
Defined in:
lib/sequent/migrations/versions.rb

Constant Summary collapse

MIGRATE_ONLINE_RUNNING =
1
MIGRATE_ONLINE_FINISHED =
2
MIGRATE_OFFLINE_RUNNING =
3
DONE =
nil

Class Method Summary collapse

Class Method Details

.current_snapshot_xmin_xact_idObject



77
78
79
# File 'lib/sequent/migrations/versions.rb', line 77

def self.current_snapshot_xmin_xact_id
  connection.execute('SELECT pg_snapshot_xmin(pg_current_snapshot())::text::bigint AS xmin').first['xmin']
end

.current_versionObject



28
29
30
# File 'lib/sequent/migrations/versions.rb', line 28

def self.current_version
  done.latest_version || 0
end

.end_offline!(new_version) ⇒ Object



73
74
75
# File 'lib/sequent/migrations/versions.rb', line 73

def self.end_offline!(new_version)
  find_by!(version: new_version, status: MIGRATE_OFFLINE_RUNNING).update(status: DONE)
end

.end_online!(new_version) ⇒ Object



50
51
52
# File 'lib/sequent/migrations/versions.rb', line 50

def self.end_online!(new_version)
  find_by!(version: new_version, status: MIGRATE_ONLINE_RUNNING).update(status: MIGRATE_ONLINE_FINISHED)
end

.latestObject



40
41
42
# File 'lib/sequent/migrations/versions.rb', line 40

def self.latest
  order('version desc').limit(1).first
end

.latest_versionObject



36
37
38
# File 'lib/sequent/migrations/versions.rb', line 36

def self.latest_version
  latest&.version
end

.migration_sqlObject



11
12
13
14
15
16
17
18
19
20
# File 'lib/sequent/migrations/versions.rb', line 11

def self.migration_sql
  <<~SQL.chomp
    CREATE TABLE IF NOT EXISTS #{table_name} (version integer NOT NULL, CONSTRAINT version_pk PRIMARY KEY(version));
    ALTER TABLE #{table_name} drop constraint if exists only_one_running;
    ALTER TABLE #{table_name} ADD COLUMN IF NOT EXISTS status INTEGER DEFAULT NULL CONSTRAINT only_one_running CHECK (status in (1,2,3));
    ALTER TABLE #{table_name} ADD COLUMN IF NOT EXISTS xmin_xact_id BIGINT;
    DROP INDEX IF EXISTS single_migration_running;
    CREATE UNIQUE INDEX single_migration_running ON #{table_name} ((status * 0)) where status is not null;
  SQL
end

.rollback!(new_version) ⇒ Object



54
55
56
# File 'lib/sequent/migrations/versions.rb', line 54

def self.rollback!(new_version)
  running.where(version: new_version).delete_all
end

.start_offline!(new_version) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/sequent/migrations/versions.rb', line 58

def self.start_offline!(new_version)
  current_migration = find_by(version: new_version)
  fail MigrationNotStarted if current_migration.blank?

  current_migration.with_lock('FOR UPDATE NOWAIT') do
    current_migration.reload
    fail MigrationDone if current_migration.status.nil?
    fail ConcurrentMigration if current_migration.status != MIGRATE_ONLINE_FINISHED

    current_migration.update(status: MIGRATE_OFFLINE_RUNNING)
  end
rescue ActiveRecord::LockWaitTimeout
  raise ConcurrentMigration
end

.start_online!(new_version) ⇒ Object



44
45
46
47
48
# File 'lib/sequent/migrations/versions.rb', line 44

def self.start_online!(new_version)
  create!(version: new_version, status: MIGRATE_ONLINE_RUNNING, xmin_xact_id: current_snapshot_xmin_xact_id)
rescue ActiveRecord::RecordNotUnique
  raise ConcurrentMigration, "Migration for version #{new_version} is already running"
end

.version_currently_migratingObject



32
33
34
# File 'lib/sequent/migrations/versions.rb', line 32

def self.version_currently_migrating
  running.latest_version
end