Skip to content

Instantly share code, notes, and snippets.

@rpanachi
Created April 10, 2016 21:26
Show Gist options
  • Select an option

  • Save rpanachi/f16447f8b03fa5edcf935863fcdffb95 to your computer and use it in GitHub Desktop.

Select an option

Save rpanachi/f16447f8b03fa5edcf935863fcdffb95 to your computer and use it in GitHub Desktop.

Revisions

  1. rpanachi created this gist Apr 10, 2016.
    211 changes: 211 additions & 0 deletions db.rake
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,211 @@
    namespace :db do

    require 'sequel'
    Sequel.extension(:migration)
    MIGRATIONS_PATH = 'db/migrations'

    def db_conn_env
    ENV["BOOKSHELF_DATABASE_URL"]
    end

    def db_conn_url
    db = split_db_url(db_conn_env)
    db_conn = "postgres://#{db[:user]}:#{db[:pass]}@#{db[:host]}"
    end

    def split_db_url(url)
    user, pass, host, database = url.scan(/postgres:\/\/(.+?):(.+?)@(.+?)\/(.+?)$/).first
    data = {
    user: user,
    pass: pass,
    host: host,
    database: database
    }
    end

    def db_migrate(version = db_migrations.last)
    puts "Migrating database to version #{version}"
    Sequel::Migrator.run(DB, MIGRATIONS_PATH, target: version.to_i)
    end

    def db_migrated?(version, schema = :sequel)
    db_versions(schema).include?(version.to_s)
    end

    def db_versions(schema = :sequel)
    if schema == :sequel
    DB[:schema_migrations].order(:filename).select_map(:filename)
    elsif schema == :rails
    DB[:schema_migrations].order(:version).select_map(:version)
    else
    []
    end
    end

    def db_migrations
    Dir[MIGRATIONS_PATH + "/*.rb"]
    .map { |f| File.basename(f) }
    .sort
    end

    def db_schema(object)
    Hash[DB.schema(object)]
    rescue Sequel::DatabaseError
    nil
    end

    desc 'Seed the database with application required data'
    task seed: :environment do
    load 'db/seeds.rb'
    end

    desc "Prints current schema version"
    task :version => :environment do
    puts "Current Schema Version: #{db_versions(:sequel).last}"
    end

    desc "Perform migration up to latest migration available"
    task :migrate, [:version] => :environment do |t, args|
    db_migrate(args[:version] || db_migrations.last)
    Rake::Task['db:version'].execute
    end

    desc "Perform rollback to specified target or previous version as default"
    task :rollback, [:version] => :environment do |t, args|
    version = args[:version] || db_versions(:sequel)[-2]
    db_migrate(version)
    Rake::Task['db:version'].execute
    end

    desc "Perform migration reset (full rollback and migration) only on local environment"
    task :reset => :environment do
    if (ENV["HANAMI_ENV"] || ENV["RACK_ENV"]) == "production"
    abort "You can't run this rake on production environment"
    end

    db_migrate(0)
    db_migrate(db_migrations.last)
    Rake::Task['db:version'].execute
    end

    desc "Creates database"
    task :create => :"settings:load" do
    db = split_db_url(db_conn_env)

    exec "psql",
    "#{db_conn_url}",
    "-c", "CREATE DATABASE #{db[:database]}"
    end

    desc "Drops database"
    task :drop => :"settings:load" do
    if (ENV["HANAMI_ENV"] || ENV["RACK_ENV"]) == "production"
    abort "You can't run this rake on production environment"
    end

    db = split_db_url(db_conn_env)

    exec "psql",
    "#{db_conn_url}",
    "-c", "DROP DATABASE IF EXISTS #{db[:database]}"
    end

    desc "Start a database console on environment"
    task :console => :'settings:load' do
    exec "psql", db_conn_env
    end

    namespace :structure do
    require 'hanami/model'
    require 'hanami/model/migrator'

    task :check_schema_migrations do
    raise "Schema_migrations not prepared! Run 'rake db:migrate'" unless db_schema(:schema_migrations)
    end
    task :check_structure_sequel do
    raise "Sequel schema_migrations not prepared! Run 'rake db:structure:to_sequel'" unless db_schema(:schema_migrations)[:filename]
    end
    task :prepare_structure_sequel do
    schema_migrations = db_schema(:schema_migrations)
    DB.run "alter table schema_migrations alter column version drop not null;" if schema_migrations[:version]
    DB.run "alter table schema_migrations add filename varchar;" unless schema_migrations[:filename]

    puts "Structure: DONE"
    end
    task :migrate_structure_sequel do
    db_migrations.each do |filename|
    version = filename.to_i
    if db_migrated?(version, :rails)
    DB.run "update schema_migrations set filename = '#{filename}' where version = '#{version}';"
    else
    DB.run "insert into schema_migrations (version, filename) values ('#{version}', '#{filename}');"
    end
    puts "> #{filename} DONE"
    end
    puts "Migration: DONE"
    end

    task :check_structure_rails do
    raise "Rails schema_migrations not prepared! Run 'rake db:structure:to_rails'" unless db_schema(:schema_migrations)[:version]
    end
    task :prepare_structure_rails do
    schema_migrations = db_schema(:schema_migrations)
    DB.run "alter table schema_migrations drop constraint schema_migrations_pkey;" if db_schema(:schema_migrations_pkey)
    DB.run "alter table schema_migrations alter column filename drop not null;" if schema_migrations[:filename]
    DB.run "alter table schema_migrations add version varchar;" unless schema_migrations[:version]
    puts "Structure: DONE"
    end
    task :migrate_structure_rails do
    db_migrations.each do |filename|
    version = filename.to_i
    if db_migrated?(filename, :sequel)
    DB.run "update schema_migrations set version = '#{version}' where filename = '#{filename}';"
    else
    DB.run "insert into schema_migrations (version, filename) values ('#{version}', '#{filename}');"
    end
    puts "> #{filename} DONE"
    end
    puts "Migration: DONE"
    end

    desc "Setup database structure from Sequel to Rails Migrations"
    task :to_rails => [
    :environment,
    :check_schema_migrations,
    :check_structure_sequel,
    :prepare_structure_rails,
    :migrate_structure_rails
    ]

    desc "Setup database structure from Rails to Sequel Migrations"
    task :to_sequel => [
    :environment,
    :check_schema_migrations,
    :check_structure_rails,
    :prepare_structure_sequel,
    :migrate_structure_sequel
    ]

    # Configure Hanami::Model for structure dump/load
    task :configure do
    Hanami::Model.configure do
    adapter type: :sql, uri: db_conn_env
    migrations 'db/migrations'
    schema 'db/schema.sql'
    mapping {}
    end.load!
    end

    desc "Dump database structure to db/schema.sql"
    task dump: [:environment, :configure] do
    adapter = Hanami::Model::Migrator::Adapter.for(DB)
    adapter.dump
    end

    desc "Load db/schema.sql database structure"
    task load: :environment do
    adapter = Hanami::Model::Migrator::Adapter.for(DB)
    adapter.load
    end
    end
    end