Skip to content

Instantly share code, notes, and snippets.

@joshnuss
Last active December 31, 2015 11:59
Show Gist options
  • Save joshnuss/7982938 to your computer and use it in GitHub Desktop.
Save joshnuss/7982938 to your computer and use it in GitHub Desktop.
ecto migrations w/ create/alter macros
defmodule MigrationRunner do
use GenServer.Behaviour
@server_name :migration_runner
@full_name {:local, @server_name}
def start_link do
:gen_server.start_link(@full_name, __MODULE__, nil, [])
end
def handle_call({:direction, direction}, _from, _state) do
{:reply, :ok, direction}
end
def handle_call({:run, command}, _from, direction) do
IO.puts "#{direction}: #{inspect command}"
{:reply, :ok, direction}
end
def direction(direction) do
call {:direction, direction}
end
def run(command) do
call {:run, command}
end
defp call(message) do
:gen_server.call(@server_name, message)
end
end
defmodule Migration.Dsl do
defmacro create(object, do: block) do
commands = case block do
{:__block__, _location, ops} -> ops
_ -> [block]
end
quote do
execute {:create, unquote(object), unquote(commands) |> List.flatten}
end
end
defmacro alter(object, do: block) do
commands = case block do
{:__block__, _location, ops} -> ops
_ -> [block]
end
quote do
execute {:alter, unquote(object), unquote(commands) |> List.flatten}
end
end
def create(object) do
execute {:create, object}
end
def drop(object) do
execute {:drop, object}
end
def execute(command) do
MigrationRunner.run command
end
def table(name, options // []) do
{:table, name, options}
end
def index(name, options // []) do
{:index, name, options}
end
def add(column_name, type, options // []) do
{:add, column_name, type, options}
end
def references(relationship) do
add("#{relationship}_id", :integer)
end
def timestamps do
add(:updated_at, :datetime)
add(:created_at, :datetime)
end
def modify(column_name, type, options // []) do
{:modify, column_name, type, options}
end
def rename(from, to: to) when is_tuple(from) do
execute {:rename, from, to}
end
def rename(from, to) do
{:rename, from, to}
end
def remove(column_name) do
{:remove, column_name}
end
end
# example of adding custom methods to dsl
defmodule AttachmentMigration do
import Migration.Dsl, only: [add: 2, remove: 1]
def add_attachment(name // :attachment) do
[add("#{name}_file_name", :string),
add("#{name}_file_size", :integer),
add("#{name}_created_at", :datetime),
add("#{name}_updated_at", :datetime)]
end
def remove_attachment(name // :attachment) do
[remove("#{name}_file_name"),
remove("#{name}_file_size"),
remove("#{name}_created_at"),
remove("#{name}_updated_at")]
end
end
defmodule TestMigration do
import Migration.Dsl
import AttachmentMigration
def change do
create table(:posts) do
references :category
add :name, :string, default: "Untitled"
add :summary, :string
add_attachment(:cover)
timestamps
end
alter table(:posts) do
add :title, :string
remove :name
modify :summary, :string
rename :summary, :details
remove_attachment
end
create index(:posts_idx, on: :posts, columns: [:title])
drop index(:posts_idx2)
rename table(:posts), to: "myposts"
end
end
MigrationRunner.start_link
MigrationRunner.direction(:up)
TestMigration.change
MigrationRunner.direction(:down)
TestMigration.change
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment