Class: CouchTomato::Migrator

Inherits:
Object
  • Object
show all
Defined in:
lib/couch_tomato/migrator.rb

Overview

:nodoc:

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(direction, db, migrations_path, target_version = nil) ⇒ Migrator

Returns a new instance of Migrator.



114
115
116
117
118
# File 'lib/couch_tomato/migrator.rb', line 114

def initialize(direction, db, migrations_path, target_version = nil)
  @db = db
  @migrations_doc = self.class.migrations_doc(@db)
  @direction, @migrations_path, @target_version = direction, migrations_path, target_version
end

Class Method Details

.current_version(db) ⇒ Object



98
99
100
# File 'lib/couch_tomato/migrator.rb', line 98

def current_version(db)
  get_all_versions(db).max || 0
end

.down(db, migrations_path, target_version = nil) ⇒ Object



69
70
71
# File 'lib/couch_tomato/migrator.rb', line 69

def down(db, migrations_path, target_version = nil)
  self.new(:down, db, migrations_path, target_version).migrate
end

.forward(db, migrations_path, steps = 1) ⇒ Object



61
62
63
# File 'lib/couch_tomato/migrator.rb', line 61

def forward(db, migrations_path, steps=1)
  move(:up, db, migrations_path, steps)
end

.get_all_versions(db) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/couch_tomato/migrator.rb', line 88

def get_all_versions(db)
  doc = migrations_doc(db)

  if doc['versions']
    doc['versions'].sort
  else
    []
  end
end

.migrate(db, migrations_path, target_version = nil) ⇒ Object



49
50
51
52
53
54
55
# File 'lib/couch_tomato/migrator.rb', line 49

def migrate(db, migrations_path, target_version = nil)
  case
    when target_version.nil?                  then up(db, migrations_path, target_version)
    when current_version(db) > target_version then down(db, migrations_path, target_version)
    else                                           up(db, migrations_path, target_version)
  end
end

.migrations_doc(db) ⇒ Object



77
78
79
80
81
82
83
84
85
86
# File 'lib/couch_tomato/migrator.rb', line 77

def migrations_doc(db)
  begin
    doc = db.get('_design/migrations')
  rescue RestClient::ResourceNotFound
    db.save_doc('_id' => '_design/migrations', 'versions' => nil)
    doc = db.get('_design/migrations')
  end

  return doc
end

.rollback(db, migrations_path, steps = 1) ⇒ Object



57
58
59
# File 'lib/couch_tomato/migrator.rb', line 57

def rollback(db, migrations_path, steps=1)
  move(:down, db, migrations_path, steps)
end

.run(direction, db, migrations_path, target_version) ⇒ Object



73
74
75
# File 'lib/couch_tomato/migrator.rb', line 73

def run(direction, db, migrations_path, target_version)
  self.new(direction, db, migrations_path, target_version).run
end

.up(db, migrations_path, target_version = nil) ⇒ Object



65
66
67
# File 'lib/couch_tomato/migrator.rb', line 65

def up(db, migrations_path, target_version = nil)
  self.new(:up, db, migrations_path, target_version).migrate
end

Instance Method Details

#current_migrationObject



124
125
126
# File 'lib/couch_tomato/migrator.rb', line 124

def current_migration
  migrations.detect { |m| m.version == current_version }
end

#current_versionObject



120
121
122
# File 'lib/couch_tomato/migrator.rb', line 120

def current_version
  migrated.last || 0
end

#migrateObject



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/couch_tomato/migrator.rb', line 137

def migrate
  current = migrations.detect { |m| m.version == current_version }
  target = migrations.detect { |m| m.version == @target_version }

  if target.nil? && !@target_version.nil? && @target_version > 0
    raise UnknownMigrationVersionError.new(@target_version)
  end

  start = up? ? 0 : (migrations.index(current) || 0)
  finish = migrations.index(target) || migrations.size - 1
  runnable = migrations[start..finish]

  # skip the last migration if we're headed down, but not ALL the way down
  runnable.pop if down? && !target.nil?

  runnable.each do |migration|
    RAILS_DEFAULT_LOGGER.info("Migrating to #{migration.name} (#{migration.version})")

    # On our way up, we skip migrating the ones we've already migrated
    next if up? && migrated.include?(migration.version.to_i)

    # On our way down, we skip reverting the ones we've never migrated
    if down? && !migrated.include?(migration.version.to_i)
      migration.announce 'never migrated, skipping'; migration.write
      next
    end

    begin
      migration.migrate(@direction, @db)
      record_version_state_after_migrating(migration.version)
    rescue => e
      raise StandardError, "An error has occurred, all later migrations canceled:\n\n#{e}", e.backtrace
    end
  end
end

#migratedObject



208
209
210
# File 'lib/couch_tomato/migrator.rb', line 208

def migrated
  @migrated_versions ||= self.class.get_all_versions(@db)
end

#migrationsObject



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/couch_tomato/migrator.rb', line 173

def migrations
  @migrations ||= begin
    files = Dir["#{@migrations_path}/[0-9]*_*.rb"]

    migrations = files.inject([]) do |klasses, file|
      version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first

      raise IllegalMigrationNameError.new(file) unless version
      version = version.to_i

      if klasses.detect { |m| m.version == version }
        raise DuplicateMigrationVersionError.new(version)
      end

      if klasses.detect { |m| m.name == name.camelize }
        raise DuplicateMigrationNameError.new(name.camelize)
      end

      migration = MigrationProxy.new
      migration.name     = name.camelize
      migration.version  = version
      migration.filename = file
      klasses << migration
    end

    migrations = migrations.sort_by(&:version)
    down? ? migrations.reverse : migrations
  end
end

#pending_migrationsObject



203
204
205
206
# File 'lib/couch_tomato/migrator.rb', line 203

def pending_migrations
  already_migrated = migrated
  migrations.reject { |m| already_migrated.include?(m.version.to_i) }
end

#runObject



128
129
130
131
132
133
134
135
# File 'lib/couch_tomato/migrator.rb', line 128

def run
  target = migrations.detect { |m| m.version == @target_version }
  raise UnknownMigrationVersionError.new(@target_version) if target.nil?
  unless (up? && migrated.include?(target.version.to_i)) || (down? && !migrated.include?(target.version.to_i))
    target.migrate(@direction, @db)
    record_version_state_after_migrating(target.version)
  end
end