Skip to content

Instantly share code, notes, and snippets.

@reagent
Created November 21, 2017 17:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reagent/62e8e710535fcb96de12d54ccc0140d7 to your computer and use it in GitHub Desktop.
Save reagent/62e8e710535fcb96de12d54ccc0140d7 to your computer and use it in GitHub Desktop.
DIY migrations in Ruby
require 'pg'
require 'uri'
class Migrator
class Migration
def initialize(connection, path)
@connection, @path = connection, path
end
def execute
unless migration_run?
@connection.exec(sql)
record_migration
end
end
private
def migration_run?
count = 0
result = @connection.exec_params(
"SELECT COUNT(*) AS count FROM migrations WHERE version = $1",
[version]
)
count = result[0]["count"].to_i
result.clear()
count == 1
end
def sql
File.read(@path)
end
def record_migration
@connection.exec_params(
"INSERT INTO migrations (version) VALUES ($1)",
[version.to_s]
)
end
def version
matches = File.basename(@path).match(/\A(\d+)/)
matches[1].to_i
end
end
def initialize(database_url, migrations_path)
@database_url = database_url
@migrations_path = migrations_path
end
def migrate
create_migrations_table
migrations.map(&:execute)
end
private
def ignore
-> (r) { }
end
def connection
@connection ||= begin
conn = PG::Connection.open(connection_options)
conn.set_notice_receiver(&ignore)
conn
end
end
def uri
@uri ||= URI(@database_url)
end
def connection_options
{
host: uri.host,
user: uri.user,
password: uri.password,
port: uri.port || 5432,
dbname: uri.path[1..-1]
}
end
def files
Dir.glob(@migrations_path.expand_path.join("*.sql")).sort
end
def migrations
files.map {|f| Migration.new(connection, f) }
end
def create_migrations_table
connection.exec("
CREATE TABLE IF NOT EXISTS migrations (
version INTEGER NOT NULL UNIQUE
);
")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment