Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save michaeldwan/1287908 to your computer and use it in GitHub Desktop.
Save michaeldwan/1287908 to your computer and use it in GitHub Desktop.

Revisions

  1. michaeldwan renamed this gist Oct 14, 2011. 1 changed file with 0 additions and 0 deletions.
  2. michaeldwan revised this gist Oct 14, 2011. 2 changed files with 15 additions and 0 deletions.
    8 changes: 8 additions & 0 deletions generators.mongo_migration.mongo_migration_generator.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    class MongoMigrationGenerator < Rails::Generators::NamedBase
    source_root File.expand_path('../templates', __FILE__)

    def create_mongo_migration_file
    version = Time.now.utc.strftime("%Y%m%d%H%M%S")
    template "migration.rb", "db/mongo_migrations/#{version}_#{file_name}.rb"
    end
    end
    7 changes: 7 additions & 0 deletions generators.mongo_migrationtemplatesmigration.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    class <%= file_name.camelize %> < ::Mongo::Migration
    def self.up
    end

    def self.down
    end
    end
  3. michaeldwan created this gist Oct 14, 2011.
    7 changes: 7 additions & 0 deletions migration.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    module Mongo
    class Migration
    def self.say(message, subitem = false)
    puts "#{subitem ? " ->" : "--"} #{message}"
    end
    end
    end
    128 changes: 128 additions & 0 deletions migrator.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,128 @@
    module Mongo
    class Migrator
    def self.database=(db)
    raise "wtf is this? we need a Mongo::DB" unless db.is_a?(Mongo::DB)
    @database = db
    end

    def self.database
    unless @database
    self.database = MongoMapper.database if defined?(MongoMapper)
    end
    return @database
    end

    def self.collection_name
    @collection_name ||= "migrations"
    end

    def self.collection_name=(value)
    @collection_name = value
    end

    def self.migrations_path
    @migrations_path ||= Rails.root.join('db', 'mongo_migrations')
    end

    def self.migrations_path=(value)
    @migrations_path = value
    end

    def self.version_history
    database[collection_name].distinct('version')
    end

    def self.save_history(direction, version)
    case direction
    when :up then database[collection_name].save(:version => version)
    when :down then database[collection_name].remove(:version => version)
    end
    end

    def self.available_migrations
    @migrations ||= begin
    Dir["#{migrations_path}/*.rb"].map do |migration_file|
    MigrationProxy.new(*[File.basename(migration_file).scan(/([0-9]+)_([_a-z0-9]*).rb/).first, migration_file].flatten)
    end.sort_by(&:version)
    end
    end

    def self.pending_migrations
    history = version_history
    available_migrations.reject { |m| history.include?(m.version) }
    end

    def self.processed_migrations
    history = version_history
    available_migrations.select { |m| history.include?(m.version) }
    end

    def self.current_version
    version_history.max
    end

    def initialize(options = {})
    @version = options[:version]
    @direction = options[:direction] || :up
    end

    attr_reader :version, :direction

    def queue
    @queue ||= begin
    if version
    if direction == :up
    [self.class.pending_migrations.detect { |m| m.version == version }]
    elsif direction == :down
    [self.class.processed_migrations.detect { |m| m.version == version }]
    end
    elsif direction == :up
    self.class.pending_migrations
    else
    []
    end
    end
    end

    def run!
    queue.each do |migration|
    migration.run(direction)
    self.class.save_history(direction, migration.version)
    end
    end

    class MigrationProxy < Struct.new(:version, :name, :file)
    def migration
    @instance ||= begin
    load(file)
    name.camelize.constantize
    end
    end

    def run(direction = :up)
    return unless migration.respond_to?(direction)

    case direction
    when :up then announce "migrating"
    when :down then announce "reverting"
    end

    result = nil
    time = Benchmark.measure { result = migration.send("#{direction}") }

    case direction
    when :up then announce "migrated (%.4fs)" % time.real; puts
    when :down then announce "reverted (%.4fs)" % time.real; puts
    end

    result
    end

    def announce(message)
    text = "#{version} #{name}: #{message}"
    length = [0, 75 - text.length].max
    puts "== %s %s" % [text, "=" * length]
    end
    end
    end
    end