lib/mix/tasks/securex_gen_migration.ex

if Code.ensure_loaded?(Ecto) do
  defmodule Mix.Tasks.Securex.Gen.Migration do
    @moduledoc "The SecureX mix task to create migrations into your project `priv/repo/migrations` folder"
    use Mix.Task

    import Macro, only: [camelize: 1, underscore: 1]
    import Mix.{Generator, Ecto}
    import SecureX.Migration

    def run(args) do
      repos = parse_repo(args)

      Enum.each(repos, fn repo ->
        ensure_repo(repo, args)
        path = Path.relative_to(migrations_path(repo), Mix.Project.app_path())
        create_directory(path)

        migrations = [
          role: "create_table_roles",
          res: "create_table_resources",
          permission: "create_table_permission",
          user_roles: "create_table_user_roles"
        ]

        Enum.reduce(migrations, 1, fn {key, value}, acc ->
          time = timestamp(acc)

          content =
            [mod: Module.concat([repo, Migrations, camelize(value)])]
            |> (fn f -> f ++ [check: key] end).()
            |> migration_template
            |> format_string!

          Path.join(path, "#{time}_#{underscore(value)}.exs")
          |> create_file(content)

          acc + 1
        end)
      end)
    end

    defp timestamp(acc) do
      {{y, m, d}, {hh, mm, ss}} = :calendar.universal_time()
      "#{y}#{pad(m)}#{pad(d)}#{pad(hh)}#{pad(mm)}#{pad(ss + acc)}"
    end

    defp pad(i) when i < 10, do: <<?0, ?0 + i>>
    defp pad(i), do: to_string(i)

    embed_template(
      :migration,
      """
      defmodule <%= inspect @mod %> do
        use Ecto.Migration
        <%= case @check do %>
          <% :role ->  %>
            def change do
              create table(:roles, primary_key: false) do
                add :id, :string, null: false, primary_key: true, unique: true
                add :name, :string

                timestamps()
              end
            end
        <% :res ->  %>
            def change do
              create table(:resources, primary_key: false) do
                add :id, :string, primary_key: true
                add :name, :string

                timestamps()
              end
            end
        <% :permission ->  %>
            def change do
              create table(:permissions) do
                add :permission, :integer
                add :role_id, references(:roles, on_delete: :nothing, type: :string)
                add :resource_id, references(:resources, on_delete: :nothing, type: :string)

                timestamps()
              end
              create unique_index(:permissions, [:role_id, :resource_id])
            end
        <% :user_roles ->  %>
            def change do
              create table(:user_roles) do
                add :role_id, references(:roles, on_delete: :nothing, type: :string)
                add :user_id, references(:users, on_delete: :nothing)

                timestamps()
              end
              create unique_index(:user_roles, [:user_id, :role_id])
            end
      <% end %>
      end
      """
    )
  end
end