Class: HerokuSchemas::Migration

Inherits:
SchemaCommand show all
Defined in:
lib/heroku-schemas/migration.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from SchemaCommand

#write

Constructor Details

#initialize(options) ⇒ Migration

Returns a new instance of Migration.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/heroku-schemas/migration.rb', line 7

def initialize(options)
  super(options)
  @pgbackups = HerokuSchemas::Pgbackups.new

  @string_reference = options[:string_reference]
  raise 'Context app not provided' if @context_app.blank?
  raise 'Schema reference not provided' if @string_reference.blank?
  
  related_apps = [@context_app, @string_reference.split(':').first].uniq
  @current_schema = HerokuSchemas::SchemaReference.new(heroku: @heroku, string_reference: @context_app, related_apps: related_apps)
  @target_schema = HerokuSchemas::SchemaReference.new(heroku: @heroku, string_reference: @string_reference, related_apps: related_apps)

  @current_database = HerokuSchemas::CurrentDatabase.connect_to_url(@current_schema.database_url)
  @target_database = HerokuSchemas::TargetDatabase.connect_to_url(@target_schema.database_url)
end

Instance Attribute Details

#backup_urlObject (readonly)

Returns the value of attribute backup_url.



5
6
7
# File 'lib/heroku-schemas/migration.rb', line 5

def backup_url
  @backup_url
end

#context_appObject (readonly)

Returns the value of attribute context_app.



5
6
7
# File 'lib/heroku-schemas/migration.rb', line 5

def context_app
  @context_app
end

#current_databaseObject (readonly)

Returns the value of attribute current_database.



3
4
5
# File 'lib/heroku-schemas/migration.rb', line 3

def current_database
  @current_database
end

#current_schemaObject (readonly)

Returns the value of attribute current_schema.



3
4
5
# File 'lib/heroku-schemas/migration.rb', line 3

def current_schema
  @current_schema
end

#target_databaseObject (readonly)

Returns the value of attribute target_database.



4
5
6
# File 'lib/heroku-schemas/migration.rb', line 4

def target_database
  @target_database
end

#target_schemaObject (readonly)

Returns the value of attribute target_schema.



4
5
6
# File 'lib/heroku-schemas/migration.rb', line 4

def target_schema
  @target_schema
end

Instance Method Details

#app_database_url(app) ⇒ Object



100
101
102
103
# File 'lib/heroku-schemas/migration.rb', line 100

def app_database_url(app)
  vars = @heroku.get_config_vars(app).body
  vars['DATABASE_URL']
end

#create_backup(app, database_variable) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
# File 'lib/heroku-schemas/migration.rb', line 83

def create_backup(app, database_variable)
  args = [database_variable, '--app', app, '--expire'].compact
  # args = ['HEROKU_POSTGRESQL_CYAN_URL', '--app', 'tom-target-app', '--expire'].compact

  # @pgbackups.app = app
  # @pgbackups.capture(database_variable, expire: true)
  Heroku::Command.run('pgbackups:capture', args)

  @pgbackups.app = app
  @pgbackups.latest_backup_url
end

#create_backup_with_target_schemaObject



61
62
63
64
65
66
# File 'lib/heroku-schemas/migration.rb', line 61

def create_backup_with_target_schema
  write 'Creating database backup...'
  current_database.rename_schema(current_schema.schema, target_schema.schema)
  @backup_url = create_backup(current_schema.database_app, current_schema.database_variable)
  current_database.rename_schema(target_schema.schema, current_schema.schema)
end

#create_target_schema_in_target_databaseObject



68
69
70
# File 'lib/heroku-schemas/migration.rb', line 68

def create_target_schema_in_target_database
  target_database.create_schema(target_schema.schema)
end

#current_schema_has_data?Boolean

Returns:

  • (Boolean)


42
43
44
# File 'lib/heroku-schemas/migration.rb', line 42

def current_schema_has_data?
  current_database.existing_schemas.include?(current_schema.schema) && current_database.tables_exist?(current_schema.schema)
end

#import_backup_into_target_databaseObject



72
73
74
75
# File 'lib/heroku-schemas/migration.rb', line 72

def import_backup_into_target_database
  write 'Restoring database backup...'
  restore_from_backup_url
end

#is_migrated?Boolean

Returns:

  • (Boolean)


50
51
52
# File 'lib/heroku-schemas/migration.rb', line 50

def is_migrated?
  target_database.existing_schemas.include?(target_schema.schema)
end

#migrate_databaseObject



54
55
56
57
58
59
# File 'lib/heroku-schemas/migration.rb', line 54

def migrate_database
  create_backup_with_target_schema
  update_database_url
  create_target_schema_in_target_database
  import_backup_into_target_database
end

#performObject



23
24
25
26
27
28
29
30
# File 'lib/heroku-schemas/migration.rb', line 23

def perform
  validate_migration
  if current_schema_has_data?
    migrate_database
  else
    update_database_url
  end
end

#restore_from_backup_urlObject



95
96
97
98
# File 'lib/heroku-schemas/migration.rb', line 95

def restore_from_backup_url
  args = [target_schema.database_variable, backup_url, '--app', target_schema.database_app, '--confirm', target_schema.database_app]
  Heroku::Command.run('pgbackups:restore', args)
end

#set_app_database_url(app, url) ⇒ Object



105
106
107
# File 'lib/heroku-schemas/migration.rb', line 105

def set_app_database_url(app, url)
  @heroku.put_config_vars(app, 'DATABASE_URL' => url)
end

#target_schema_has_data?Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/heroku-schemas/migration.rb', line 46

def target_schema_has_data?
  target_database.existing_schemas.include?(target_schema.schema) && target_database.tables_exist?(target_schema.schema)
end

#update_database_urlObject

Point DATABASE_URL to the target app’s DATABASE_URL, but with the new schema_search_path



78
79
80
81
# File 'lib/heroku-schemas/migration.rb', line 78

def update_database_url
  target_database_url = SchemaUtilities.add_schema_search_path_to_url(target_schema.database_url, target_schema.schema)
  set_app_database_url(context_app, target_database_url)
end

#validate_migrationObject



32
33
34
35
36
37
38
39
40
# File 'lib/heroku-schemas/migration.rb', line 32

def validate_migration
  if current_schema == target_schema
    raise "App (#{context_app}) is already using the target schema (#{target_schema.base_database_url}, #{target_schema.schema})"
  end
  if target_schema_has_data?
    command = "heroku schemas:drop #{target_schema.database_app}:#{target_schema.database_variable}:#{target_schema.schema}"
    raise "Target schema (#{target_schema.base_database_url}, #{target_schema.schema}) already contains data. Please drop it before proceding by running:\n`#{command}`"
  end
end