Permalink
Browse files

WIP: migrations

  • Loading branch information...
0 parents commit ecc7974286e61fea317afaa68c9127f8dd807448 @begriffs committed Jun 28, 2012
Showing with 170 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +4 −0 Gemfile
  3. +25 −0 Gemfile.lock
  4. +30 −0 README
  5. +74 −0 Rakefile
  6. +9 −0 app.rb
  7. +2 −0 config.ru
  8. +16 −0 db/config.yml.example
  9. +9 −0 init.rb
@@ -0,0 +1 @@
+db/config.yml
@@ -0,0 +1,4 @@
+source 'http://rubygems.org'
+gem 'sinatra'
+gem 'pg'
+gem 'psych'
@@ -0,0 +1,25 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ fileutils (0.7)
+ rmagick (>= 2.13.1)
+ pg (0.14.0)
+ psych (1.3.3)
+ rack (1.4.1)
+ rack-protection (1.2.0)
+ rack
+ rmagick (2.13.1)
+ sinatra (1.3.2)
+ rack (~> 1.3, >= 1.3.6)
+ rack-protection (~> 1.2)
+ tilt (~> 1.3, >= 1.3.3)
+ tilt (1.3.3)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ fileutils
+ pg
+ psych
+ sinatra
@@ -0,0 +1,30 @@
+ *** R U B Y O N T R A I L S ***
+(This project is half trolling, half serious experiment.)
+
+Would you rather be a lazy tourist on a train or a rugged woodsman?
+Ruby on Trails is a small Sinatra-based web framework with the
+following opinions:
+
+* No DSL hell -- preserve the elegance of Ruby but ditch
+ sophomoric domain specific trickery.
+
+* Love your tools; don't hide them. Feeling strangled by ORMs that
+ assume you need "help" using a relational database? Hit the Trails
+ and work directly with the full power of PostgreSQL.
+
+* Preserve good Rails patterns like versioned migrations.
+
+* Keep relevant code close together. No need to hunt for the
+ magical_helper_helper.
+
+* Be declarative and test only things that actually need testing.
+ Forget Ruby model validations, database constraints already have
+ your back.
+
+* Your little app doesn't really need the fancy shit. Your actual
+ challenge is making something anyone cares about, not prematurely
+ scaling it.
+
+* Web development is not that hard. Seriously, just suck it up and
+ handle situations as you encounter them. You'll reinvent the wheel
+ a little, but it takes just as long to untangle a heavy framework.
@@ -0,0 +1,74 @@
+require 'rake'
+require 'pg'
+require 'psych'
+
+$config = Psych.load File.open("db/config.yml", "r").read
+$config.select! { |name, env| env.has_key? 'dbname' }
+
+task 'db:create' do
+ $config.each do |env, opts|
+ sh "createdb #{opts['dbname']}"
+ sql "create table schema_info(version integer not null)", env
+ sql "insert into schema_info (version) values (0)", env
+ end
+end
+
+task 'db:drop' do
+ $config.each_value { |opts| sh "dropdb #{opts['dbname']}" }
+end
+
+task :migration do
+ sh "touch db/#{Time.now.to_i}.{up,down}.sql"
+end
+
+task 'db:migrate', :ver, :env do |t, args|
+ env = args['env'] || 'development'
+ ms = available_migrations
+ to_ver = args['ver'] || ms.last
+ cur_ver = current_schema_version env
+ direction = to_ver >= cur_ver ? 'up' : 'down'
+ apply_migrations migration_path(ms, cur_ver, to_ver), direction, env
+end
+
+def apply_migrations migrations, direction, env
+ begin
+ sql 'begin', env
+ migrations.each do |m|
+ puts "Migrating #{m} #{direction}"
+ sql File.open("db/#{m}.#{direction}.sql", "r").read, env
+ sql 'update schema_info set version=$1', env, [m]
+ end
+ sql 'commit', env
+ rescue Exception => e
+ puts "Failed, rolling back"
+ puts e.message
+ sql 'rollback', env
+ end
+end
+
+def available_migrations direction='up'
+ migrations = Dir.glob "db/*.#{direction}.sql"
+ migrations.map! {|f| File.basename(f, ".#{direction}.sql")}
+ migrations.sort.uniq
+end
+
+def migration_path migrations, from, to
+ if migrations.include? from
+ migrations.reverse! if from > to
+ ends = [from, to].map { |i| migrations.find_index i }
+ min, max = ends.min, ends.max
+ migrations[min..max][1..-1]
+ else
+ migrations.select { |m| m <= to }
+ end
+end
+
+def sql s, env='development', args=[]
+ $db ||= Hash.new
+ $db[env] ||= PG::Connection.new $config[env]
+ $db[env].exec s, args
+end
+
+def current_schema_version env
+ sql('select version from schema_info', env).first['version']
+end
@@ -0,0 +1,9 @@
+require 'sinatra'
+require 'pg'
+require 'psych'
+
+require './init'
+
+get '/' do
+ sql('select version from schema_info').first['version']
+end
@@ -0,0 +1,2 @@
+require './app'
+run Sinatra::Application
@@ -0,0 +1,16 @@
+# Use any options accepted by PG::Connection#new.
+# Leave dbname blank to ignore an environment.
+common: &COMMON
+ host: localhost
+
+development:
+ <<: *COMMON
+ dbname:
+
+test:
+ <<: *COMMON
+ dbname:
+
+production:
+ <<: *COMMON
+ dbname:
@@ -0,0 +1,9 @@
+configure do
+ conf = Psych.load File.open("db/config.yml", "r").read
+ env = settings.environment.to_s
+ $db = PG::Connection.new conf[env] if conf[env].has_key? 'dbname'
+end
+
+def sql cmd, *args
+ $db.exec cmd, args
+end

0 comments on commit ecc7974

Please sign in to comment.