Class: Fancybox2::Migrations::Runner

Inherits:
Object
  • Object
show all
Includes:
Exceptions
Defined in:
lib/fancybox2/migrations/runner.rb

Constant Summary collapse

VERSION_REGEXP =
/^(\d+)/.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(files_path, logger: nil) ⇒ Runner

Returns a new instance of Runner.



38
39
40
41
42
43
# File 'lib/fancybox2/migrations/runner.rb', line 38

def initialize(files_path, logger: nil)
  @files_path = files_path
  @logger = logger || ::Logger.new(STDOUT)

  load_migrations
end

Instance Attribute Details

#current_versionObject (readonly)

Returns the value of attribute current_version.



36
37
38
# File 'lib/fancybox2/migrations/runner.rb', line 36

def current_version
  @current_version
end

#files_pathObject (readonly)

Returns the value of attribute files_path.



36
37
38
# File 'lib/fancybox2/migrations/runner.rb', line 36

def files_path
  @files_path
end

#loggerObject (readonly)

Returns the value of attribute logger.



36
37
38
# File 'lib/fancybox2/migrations/runner.rb', line 36

def logger
  @logger
end

#migrationsObject (readonly)

Returns the value of attribute migrations.



36
37
38
# File 'lib/fancybox2/migrations/runner.rb', line 36

def migrations
  @migrations
end

Class Method Details

.auto(migrations_folder, last_migrated_file_path: nil, logger: nil) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/fancybox2/migrations/runner.rb', line 19

def auto(migrations_folder, last_migrated_file_path: nil, logger: nil)
  # Try to read file content, rescue with nil
  content = File.read(last_migrated_file_path) rescue nil
  # Extract last run migration version
  last_run_migration_version = content.to_i

  runner = new(migrations_folder, logger: logger)
  last_migrated = runner.run last_migrated: last_run_migration_version
  # Update migration status file
  if last_migrated
    f = File.open last_migrated_file_path, 'w'
    f.write last_migrated.version
    f.close
  end
end

.extract_and_validate_version_from(migration_name) ⇒ Object



10
11
12
13
14
15
16
17
# File 'lib/fancybox2/migrations/runner.rb', line 10

def extract_and_validate_version_from(migration_name)
  version = migration_name.to_s.scan(VERSION_REGEXP).flatten.first
  unless version
    raise ArgumentError, 'migration name must start with a positive integer number e.g: 1_do_something.rb'
  end

  version.to_i
end

Instance Method Details

#load_migrationsObject



75
76
77
78
79
80
81
82
83
84
# File 'lib/fancybox2/migrations/runner.rb', line 75

def load_migrations
  # Load files from files_path and create classes
  @migrations = Dir[File.join(File.expand_path(files_path), '**', '*.rb')].map do |file_path|
    migration_name = File.basename(file_path)
    klass = Class.new(Base)
    klass.class_eval(File.read(file_path), file_path)
    klass.freeze
    klass.new migration_name
  end.sort_by { |migration| migration.version }
end

#migrations_to_run(from, to) ⇒ Object

Select migrations to run depending given a starting and an ending one



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/fancybox2/migrations/runner.rb', line 87

def migrations_to_run(from, to)
  selected = []
  direction = from <= to ? :up : :down
  @migrations.each do |m|
    # downgrading - Break if we already arrived to "from" migration (e.g from=4, to=2 => 1, >2<, 3, *4*, 5)
    break if (from > to) && (m.version > from)
    # upgrading - Break if we already arrived to "to" migration (e.g from=2, to=4 => 1, *2*, 3, >4<, 5)
    break if (from < to) && (m.version > to)
    # downgrading - Skip until we arrive to "to" migration (e.g from=4, to=2 => 1, >2<, 3, *4*, 5)
    next if (from > to) && (m.version < to)
    # upgrading - Skip until we arrive to "from" migration (e.g from=2, to=4 => 1, *2*, 3, >4<, 5)
    next if (from <= to) && (m.version < from)
    # Break if we're already out of range
    break if (m.version > from && m.version > to)

    if m.version <= from
      selected.prepend m
    else
      selected.append m
    end
  end

  [selected, direction]
end

#run(from: nil, to: nil, last_migrated: nil) ⇒ Object

Returns last run migration.

Parameters:

  • from (defaults to: nil)

    a valid migration name or version

  • to (defaults to: nil)

    a valid migration name or version

Returns:

  • last run migration



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/fancybox2/migrations/runner.rb', line 48

def run(from: nil, to: nil, last_migrated: nil)
  if from && last_migrated
    logger.warn "#{self.class}#run - Both 'from' and 'last_migrated' params given. Only 'last_migrated' considered"
  end
  # Extract and validate versions
  from = self.class.extract_and_validate_version_from(from || last_migrated || 0)
  # This works independently from the direction if migrations' folder contains only migrations of last installed version
  to = self.class.extract_and_validate_version_from (to || @migrations.last.version)
  # Select migrations to run
  to_run, direction = migrations_to_run from, to
  # If last_migrated param has been provided, remove some migration from the list depending on direction
  if last_migrated && to_run.any?
    if direction == :up && last_migrated == to_run.first.version
      to_run.shift
    elsif direction == :down
      # We surely have at least 2 migrations in the array, otherwise the direction would've been :up
      to_run.pop
    end
  end
  to_run.each do |migration|
    logger.info "Running migration #{migration.name}"
    migration.send direction
  end

  to_run.last
end