· 9 years ago · Dec 07, 2016, 07:08 PM
1namespace :db do
2
3 require 'sequel'
4 Sequel.extension(:migration)
5 MIGRATIONS_PATH = 'db/migrations'
6
7 def db_conn_env
8 ENV["BOOKSHELF_DATABASE_URL"]
9 end
10
11 def db_conn_url
12 db = split_db_url(db_conn_env)
13 db_conn = "postgres://#{db[:user]}:#{db[:pass]}@#{db[:host]}"
14 end
15
16 def split_db_url(url)
17 user, pass, host, database = url.scan(/postgres:\/\/(.+?):(.+?)@(.+?)\/(.+?)$/).first
18 data = {
19 user: user,
20 pass: pass,
21 host: host,
22 database: database
23 }
24 end
25
26 def db_migrate(version = db_migrations.last)
27 puts "Migrating database to version #{version}"
28 Sequel::Migrator.run(DB, MIGRATIONS_PATH, target: version.to_i)
29 end
30
31 def db_migrated?(version, schema = :sequel)
32 db_versions(schema).include?(version.to_s)
33 end
34
35 def db_versions(schema = :sequel)
36 if schema == :sequel
37 DB[:schema_migrations].order(:filename).select_map(:filename)
38 elsif schema == :rails
39 DB[:schema_migrations].order(:version).select_map(:version)
40 else
41 []
42 end
43 end
44
45 def db_migrations
46 Dir[MIGRATIONS_PATH + "/*.rb"]
47 .map { |f| File.basename(f) }
48 .sort
49 end
50
51 def db_schema(object)
52 Hash[DB.schema(object)]
53 rescue Sequel::DatabaseError
54 nil
55 end
56
57 desc 'Seed the database with application required data'
58 task seed: :environment do
59 load 'db/seeds.rb'
60 end
61
62 desc "Prints current schema version"
63 task :version => :environment do
64 puts "Current Schema Version: #{db_versions(:sequel).last}"
65 end
66
67 desc "Perform migration up to latest migration available"
68 task :migrate, [:version] => :environment do |t, args|
69 db_migrate(args[:version] || db_migrations.last)
70 Rake::Task['db:version'].execute
71 end
72
73 desc "Perform rollback to specified target or previous version as default"
74 task :rollback, [:version] => :environment do |t, args|
75 version = args[:version] || db_versions(:sequel)[-2]
76 db_migrate(version)
77 Rake::Task['db:version'].execute
78 end
79
80 desc "Perform migration reset (full rollback and migration) only on local environment"
81 task :reset => :environment do
82 if (ENV["HANAMI_ENV"] || ENV["RACK_ENV"]) == "production"
83 abort "You can't run this rake on production environment"
84 end
85
86 db_migrate(0)
87 db_migrate(db_migrations.last)
88 Rake::Task['db:version'].execute
89 end
90
91 desc "Creates database"
92 task :create => :"settings:load" do
93 db = split_db_url(db_conn_env)
94
95 exec "psql",
96 "#{db_conn_url}",
97 "-c", "CREATE DATABASE #{db[:database]}"
98 end
99
100 desc "Drops database"
101 task :drop => :"settings:load" do
102 if (ENV["HANAMI_ENV"] || ENV["RACK_ENV"]) == "production"
103 abort "You can't run this rake on production environment"
104 end
105
106 db = split_db_url(db_conn_env)
107
108 exec "psql",
109 "#{db_conn_url}",
110 "-c", "DROP DATABASE IF EXISTS #{db[:database]}"
111 end
112
113 desc "Start a database console on environment"
114 task :console => :'settings:load' do
115 exec "psql", db_conn_env
116 end
117
118 namespace :structure do
119 require 'hanami/model'
120 require 'hanami/model/migrator'
121
122 task :check_schema_migrations do
123 raise "Schema_migrations not prepared! Run 'rake db:migrate'" unless db_schema(:schema_migrations)
124 end
125 task :check_structure_sequel do
126 raise "Sequel schema_migrations not prepared! Run 'rake db:structure:to_sequel'" unless db_schema(:schema_migrations)[:filename]
127 end
128 task :prepare_structure_sequel do
129 schema_migrations = db_schema(:schema_migrations)
130 DB.run "alter table schema_migrations alter column version drop not null;" if schema_migrations[:version]
131 DB.run "alter table schema_migrations add filename varchar;" unless schema_migrations[:filename]
132
133 puts "Structure: DONE"
134 end
135 task :migrate_structure_sequel do
136 db_migrations.each do |filename|
137 version = filename.to_i
138 if db_migrated?(version, :rails)
139 DB.run "update schema_migrations set filename = '#{filename}' where version = '#{version}';"
140 else
141 DB.run "insert into schema_migrations (version, filename) values ('#{version}', '#{filename}');"
142 end
143 puts "> #{filename} DONE"
144 end
145 puts "Migration: DONE"
146 end
147
148 task :check_structure_rails do
149 raise "Rails schema_migrations not prepared! Run 'rake db:structure:to_rails'" unless db_schema(:schema_migrations)[:version]
150 end
151 task :prepare_structure_rails do
152 schema_migrations = db_schema(:schema_migrations)
153 DB.run "alter table schema_migrations drop constraint schema_migrations_pkey;" if db_schema(:schema_migrations_pkey)
154 DB.run "alter table schema_migrations alter column filename drop not null;" if schema_migrations[:filename]
155 DB.run "alter table schema_migrations add version varchar;" unless schema_migrations[:version]
156 puts "Structure: DONE"
157 end
158 task :migrate_structure_rails do
159 db_migrations.each do |filename|
160 version = filename.to_i
161 if db_migrated?(filename, :sequel)
162 DB.run "update schema_migrations set version = '#{version}' where filename = '#{filename}';"
163 else
164 DB.run "insert into schema_migrations (version, filename) values ('#{version}', '#{filename}');"
165 end
166 puts "> #{filename} DONE"
167 end
168 puts "Migration: DONE"
169 end
170
171 desc "Setup database structure from Sequel to Rails Migrations"
172 task :to_rails => [
173 :environment,
174 :check_schema_migrations,
175 :check_structure_sequel,
176 :prepare_structure_rails,
177 :migrate_structure_rails
178 ]
179
180 desc "Setup database structure from Rails to Sequel Migrations"
181 task :to_sequel => [
182 :environment,
183 :check_schema_migrations,
184 :check_structure_rails,
185 :prepare_structure_sequel,
186 :migrate_structure_sequel
187 ]
188
189 # Configure Hanami::Model for structure dump/load
190 task :configure do
191 Hanami::Model.configure do
192 adapter type: :sql, uri: db_conn_env
193 migrations 'db/migrations'
194 schema 'db/schema.sql'
195 mapping {}
196 end.load!
197 end
198
199 desc "Dump database structure to db/schema.sql"
200 task dump: [:environment, :configure] do
201 adapter = Hanami::Model::Migrator::Adapter.for(DB)
202 adapter.dump
203 end
204
205 desc "Load db/schema.sql database structure"
206 task load: :environment do
207 adapter = Hanami::Model::Migrator::Adapter.for(DB)
208 adapter.load
209 end
210 end
211end