Class: PG::Schema::Migrator

Inherits:
Object
  • Object
show all
Defined in:
lib/pg/schema-migration.rb

Constant Summary collapse

MIGRATION_FILE_REGEX =
/^(\d+)_.+\.rb/i

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(db:, directory: nil, log: Logger.new(STDOUT)) ⇒ Migrator

Returns a new instance of Migrator.



65
66
67
68
69
70
71
72
# File 'lib/pg/schema-migration.rb', line 65

def initialize(db:, directory: nil, log: Logger.new(STDOUT))
  @db        = db
  @directory = directory
  @log       = log

  load_migration_files
  generate_schema_migration_table!
end

Instance Attribute Details

#connectionObject

Returns the value of attribute connection.



61
62
63
# File 'lib/pg/schema-migration.rb', line 61

def connection
  @connection
end

#directoryObject

Returns the value of attribute directory.



61
62
63
# File 'lib/pg/schema-migration.rb', line 61

def directory
  @directory
end

Instance Method Details

#apply(version, direction) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/pg/schema-migration.rb', line 101

def apply(version, direction)
  migration = PG::Schema.get_migration_by_version(version)
  commands  = migration.public_send(direction)

  commands.reverse! if direction == :down

  @db.transaction do
    commands.each do |command|
      @db.exec(command)
    end
  end

  update_version(direction == :up ? version : version - 1)
rescue => error
  @log.error error.message
  @log.info  "The migration failed. Current version #{current_version}"
  raise
end

#current_versionObject



153
154
155
156
157
158
159
160
161
# File 'lib/pg/schema-migration.rb', line 153

def current_version
  res = @db.exec <<~SQL
    SELECT version FROM schema_information
  SQL

  raise "Schema information has multiple values" if res.ntuples > 1

  res.field_values("version").first.to_i
end

#generate_schema_migration_table!Object



135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/pg/schema-migration.rb', line 135

def generate_schema_migration_table!
  @db.exec <<~SQL
    CREATE TABLE IF NOT EXISTS schema_information (
      version INTEGER DEFAULT 0 NOT NULL
    )
  SQL

  if @db.exec("SELECT * FROM schema_information").ntuples.zero?
    @db.exec <<~SQL
      INSERT INTO schema_information DEFAULT VALUES
    SQL
  end
end

#load_migration_filesObject



120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/pg/schema-migration.rb', line 120

def load_migration_files
  files = []

  if directory
    Dir.new(directory).sort.each do |file|
      next unless file.match(MIGRATION_FILE_REGEX)
      file = File.join(directory, file)
      files << file
      load(file)
    end
  end

  files
end

#run!(version: nil) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/pg/schema-migration.rb', line 74

def run!(version: nil)
  migrations       = PG::Schema.migrations
  _current_version = current_version

  version||= migrations.count

  if version == _current_version || migrations.empty?
    @log.info "Nothing to do."
    return
  end

  t = Time.now
  @log.info "Migrationg from #{_current_version} to version #{version}"
  if version > _current_version
    (_current_version + 1).upto(version) do |target|
      apply(target, :up)
    end
  else
    (_current_version).downto(version + 1) do |target|
      apply(target, :down)
    end
  end

  @log.info "Finished applying migration #{version}, took #{sprintf('%0.6f', Time.now - t)} seconds"
  @log.info "Done!"
end

#update_version(version) ⇒ Object



149
150
151
# File 'lib/pg/schema-migration.rb', line 149

def update_version(version)
  @db.exec("UPDATE schema_information SET version = $1", [version])
end