class Duck_Duck_Duck

Constants

DB
SCHEMA_TABLE

Attributes

action[R]

Instance methods:

name[R]

Instance methods:

sub_action[R]

Instance methods:

Public Class Methods

create(*args) click to toggle source
# File lib/duck_duck_duck.rb, line 19
def create *args
  new(*args).create
end
dev_only() click to toggle source
# File lib/duck_duck_duck.rb, line 15
def dev_only
  fail "Not allowed on a dev machine." if ENV['IS_DEV']
end
migrate_schema() click to toggle source
# File lib/duck_duck_duck.rb, line 23
    def migrate_schema
      DB << <<-EOF
        CREATE TABLE IF NOT EXISTS #{SCHEMA_TABLE} (
          name              varchar(255) NOT NULL PRIMARY KEY,
          version           smallint     NOT NULL DEFAULT 0
        )
      EOF
    end
new(*args) click to toggle source
# File lib/duck_duck_duck.rb, line 78
def initialize *args
  @name, @action, @sub_action = args
  if !@name
    fail ArgumentError, "Name required."
  end

  @__files = `find . -iregex ".+/#{name}/migrates/__.+\.sql"`
  .strip
  .split("\n")
  .sort

  @files = (
    `find . -iregex ".+/#{name}/migrates/.+\.sql"`
    .strip
    .split("\n")
    .grep(/\/\d+\-/)
    .sort
  )
end
read_file(f) click to toggle source
# File lib/duck_duck_duck.rb, line 32
def read_file f
  raw = File.read(f).split(/\s*--\s+(UP|BOTH|DOWN):?\s*/).
  inject([:UP, {:UP=>[], :DOWN=>[]}]) do |memo, val|
    dir   = memo.first
    meta  = memo.last

    case val
    when 'UP', :UP, :DOWN, 'DOWN', 'BOTH', :BOTH
      dir = val.to_sym
    when ''
      # do nothing
    else
      case dir
      when :BOTH
        meta[:UP] << val
        meta[:DOWN] << val
      else
        meta[dir] << val
      end
    end

    [dir, meta]
  end

  meta = raw.last
  {:UP=>meta[:UP].join("\n"), :DOWN=>meta[:DOWN].join("\n")}
end
stdout(*args) click to toggle source
# File lib/duck_duck_duck.rb, line 11
def stdout *args
  args.each { |a| print "#{a}\n" }
end

Public Instance Methods

create() click to toggle source
# File lib/duck_duck_duck.rb, line 207
def create
  `mkdir -p #{name}/migrates`

  size = 3
  next_ver = begin
               (@files.last || '')[/\/(\d+)[^\/]+\z/]
               v = if $1
                     size = $1.size
                     $1
                    else
                      '0'
                    end
               "%0#{size}d" % (v.to_i + 1)
             end

  new_file = "#{name}/migrates/#{next_ver}-#{[action, sub_action].compact.join('-')}.sql"
  File.open(new_file, 'a') do |f|
    f.print "\n\n\n\n-- DOWN\n\n\n\n"
  end

  stdout new_file
end
down() click to toggle source
# File lib/duck_duck_duck.rb, line 166
def down
  rec = init_model_in_schema

  if rec[:version] < 0
    stdout "#{name} is at invalid version: #{rec[:version]}\n"
    exit 1
  end

  files = if rec[:version] == 0
            []
          else
            @files.sort.reverse.map { |f|
              ver = file_to_ver(f)
              next unless ver <= rec[:version]
              [ ver, Duck_Duck_Duck.read_file(f)[:DOWN] ]
            }.compact
          end

  if @__files.empty? && files.empty?
    stdout "#{name} is already the latest: #{rec[:version]}\n"
    exit 0
  end

  new_ver = nil

  files.each_with_index { |pair, i|
    prev_pair = files[i+1] || [0, nil]
    ver = prev_pair.first.to_i
    sql = pair[1]
    DB << sql
    DB[" UPDATE #{SCHEMA_TABLE} SET version = ? WHERE name = upper( ? )", ver, name].update
    stdout "#{name} schema is now : #{ver}"
  }

  @__files.reverse.each { |f|
    DB << Duck_Duck_Duck.read_file(f)[:DOWN]
    stdout "down: #{f}"
  }

end
file_to_ver(str) click to toggle source
# File lib/duck_duck_duck.rb, line 102
def file_to_ver str
  File.basename(str)[/\A\d{1,}/].to_i
end
init_model_in_schema() click to toggle source
# File lib/duck_duck_duck.rb, line 111
def init_model_in_schema
  rec = DB.fetch(
    "SELECT version FROM #{SCHEMA_TABLE} WHERE name = upper( :name )",
    :name=>name
  ).all.first

  if !rec
    dir_name = "#{name}/migrates"
    dir = `find . -iregex ".+/#{dir_name}"`.strip.split("\n")
    if dir.empty?
      fail "Directory #{dir_name} does not exist."
    end
    rec = DB.fetch(
      "INSERT INTO #{SCHEMA_TABLE} (name, version) VALUES (upper(:name), :version) RETURNING *",
      :name=>name, :version=>0
    ).all.first
  end

  {:version=>rec[:version]}
end
reset() click to toggle source
# File lib/duck_duck_duck.rb, line 106
def reset
  down
  up
end
stdout(*args) click to toggle source
# File lib/duck_duck_duck.rb, line 98
def stdout *args
  Duck_Duck_Duck.stdout *args
end
up() click to toggle source
# File lib/duck_duck_duck.rb, line 132
def up
  rec = init_model_in_schema

  if rec[:version] < 0
    stdout "#{name} has an invalid version: #{rec[:version]}\n"
    exit 1
  end

  files = @files.sort.map { |f|
    ver = file_to_ver(f)
    if ver > rec[:version]
      [ ver, Duck_Duck_Duck.read_file(f)[:UP] ]
    end
  }.compact

  if @__files.empty? && files.empty?
    stdout "#{name} is already the latest: #{rec[:version]}"
  end

  @__files.each { |f|
    DB << Duck_Duck_Duck.read_file(f)[:UP]
    stdout "ran file: #{f}"
  }

  files.each { |pair|
    ver = pair.first
    sql = pair[1]
    DB << sql
    DB[" UPDATE #{SCHEMA_TABLE.inspect} SET version = ? WHERE name = upper( ? ); ", ver, name].update
    stdout "#{name} schema is now : #{ver}"
  }

end