View Source BitcrowdEcto.Migrator behaviour (bitcrowd_ecto v0.16.0)
Release migration logic for repositories.
Can deal with normal repositories & multi-tenant repositories.
usage
Usage
In the simplest case, add the Migrator to your repository:
defmodule MyApp.Repo do
use Ecto.Repo, otp_app: :my_app, adapter: Ecto.Adapters.Postgres
use BitcrowdEcto.Migrator
end
and call the migrator from your release:
$ bin/my_app eval 'MyApp.Repo.up()'
multi-tenant-repositories
Multi-Tenant repositories
For multi-tenant repositories, you need to provide a list of tenants (= PG schemas) by
overriding the known_prefixes/0
function on your repository:
defmodule MyApp.Repo do
use Ecto.Repo, otp_app: :my_app, adapter: Ecto.Adapters.Postgres
use BitcrowdEcto.Migrator
def known_prefixes do
["tenant_a", "tenant_b"]
end
end
This will make the migrator apply migrations from the priv/repo/tenant_migrations
directory
onto schemas tenant_a
and tenant_b
. The schemas will be created if necessary.
mix-tasks-for-development
Mix tasks for development
In normal development without multi-tenancy, the usual Ecto mix tasks will work just fine.
When using tenant schemas, the normal Ecto mix tasks will only apply the "global" (i.e.
non-prefixed migrations) from priv/repo/migrations
, which is not enough. You can define
your own Mix tasks calling the up/0
and down/1
functions on your repository:
defmodule Mix.Tasks.MyApp.Migrate do
use Mix.Task
@shortdoc "Migrates our repository"
@moduledoc "Migrates the repository including the tenant schemas"
@impl true
def run(args) do
Mix.Task.run("app.config", args)
MyApp.Repo.up()
end
end
defmodule Mix.Tasks.MyApp.Rollback do
use Mix.Task
@shortdoc "Rolls back our repository"
@moduledoc "Rolls back the repository including the tenant schemas"
@impl true
def run(args) do
Mix.Task.run("app.config", args)
{[to: to], _} = OptionParser.parse!(args, strict: [to: :integer], aliases: [])
MyApp.Repo.down(to)
end
end
stopping-the-application-if-migrations-are-down
Stopping the application if migrations are down
In some setups (e.g. parallel starts of Kubernetes jobs for migrations and your app workload)
you may want to abort startup if migrations haven't been applied. Use the ensure_up!/0
function to raise an exception in such cases.
$ bin/my_app eval 'MyApp.Repo.ensure_up!()'
[...]
** (RuntimeError) Migrations not up!
20220101120000_create_foo_table.exs
[...]
$ echo $?
1
$ bin/my_app eval 'MyApp.Repo.up()'
[...]
$ bin/my_app eval 'MyApp.Repo.ensure_up!()'
[...]
$ echo $?
0
Link to this section Summary
Callbacks
Rolls back both the main schemas/tables and the tenant schemas to a given version.
Checks that all migrations have been run or raises an exception otherwise.
Called when the migrator experiences an exception.
Returns the list of prefixes used on this repository.
Migrates both the "main" (i.e. non-tenant) schemas/tables and the tenant schemas to their latest version.
Link to this section Callbacks
@callback down(to :: non_neg_integer()) :: :ok
Rolls back both the main schemas/tables and the tenant schemas to a given version.
@callback ensure_up!() :: :ok | no_return()
Checks that all migrations have been run or raises an exception otherwise.
@callback handle_migrator_exception(Exception.t(), Exception.stacktrace()) :: any()
Called when the migrator experiences an exception.
@callback known_prefixes() :: [String.t()]
Returns the list of prefixes used on this repository.
@callback up() :: :ok
Migrates both the "main" (i.e. non-tenant) schemas/tables and the tenant schemas to their latest version.