lib/bitcrowd_ecto/migration.ex

defmodule BitcrowdEcto.Migration do
  @moduledoc """
  Utilities for migrations.
  """

  @moduledoc since: "0.7.0"

  use Ecto.Migration

  @grants [
    "GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES",
    "GRANT ALL ON ALL FUNCTIONS",
    "GRANT ALL ON ALL SEQUENCES"
  ]

  @default_grants [
    "GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES",
    "GRANT ALL ON FUNCTIONS",
    "GRANT ALL ON SEQUENCES"
  ]

  @doc """
  This function grants data manipulation privileges for a given schema to a given role.

  Use this when you have a setup where your "runtime" user is deprived of all DDL privileges
  (i.e., it can't create or modify tables, etc.), but your migration user is allowed to do so.

  In particular, the following GRANTS are executed:

      GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES
      GRANT ALL ON ALL FUNCTIONS
      GRANT ALL ON ALL SEQUENCES

  ## Usage

  The easiest way of using this is to issue the command after every `CREATE SCHEMA` call:

      def change do
        execute("CREATE SCHEMA foo;", "DROP SCHEMA foo;")

        if direction() == :up do
          BitcrowdEcto.Migration.grant_dml_privileges_on_schema("foo", "mydmlrole")
        end
      end

  ## Options

  * `default`  boolean indicating whether the privileges should automatically be granted for
               future objects, defaults to true
  """
  @doc since: "0.7.0"
  @spec grant_dml_privileges_on_schema(binary(), binary()) :: :ok
  @spec grant_dml_privileges_on_schema(binary(), binary(), keyword()) :: :ok
  def grant_dml_privileges_on_schema(schema, role, opts \\ []) do
    execute("GRANT USAGE ON SCHEMA #{schema} TO #{role};")

    for grant <- @grants do
      execute("#{grant} IN SCHEMA #{schema} TO #{role};")
    end

    if Keyword.get(opts, :default, true) do
      for grant <- @default_grants do
        execute("ALTER DEFAULT PRIVILEGES IN SCHEMA #{schema} #{grant} TO #{role};")
      end
    end

    :ok
  end
end