Skip to content

rhetzler/apartmentex

 
 

Repository files navigation

CircleCI

Apartmentex

Easy SaaS for Phoenix/Ecto.

In this branch, the following versions are supported:

  • Ecto 2.0.x
  • Postgrex 0.11.0

Features

  • Tenant-qualified queries targeting postgres schemas or MySql databases
  • Automatic migrations for tenant tables to schema for Postgres or database for MySQL

See an example app at https://github.com/Dania02525/widget_saas

Setup

  • Add this to your mix.exs deps:
{:apartmentex, "~> 0.2.2"}
  • Run mix deps.get && mix deps.compile

  • You can also configure your tenant schema prefix, adding this to your application configs:

config :apartmentex, schema_prefix: "prefix_" # the default prefix is "tenant_"
  • If you want to use mix apartmentex.migrate below, you also need a schema iterator config like this:
config :apartmentex, :schema_iterator,
  repo: MyApp.Repo,
  app_start_needed: true,
  list: quote(do: MyApp.Repo.all(MyApp.Tenant) |> Enum.map(fn x -> x.schema_name end))

The :list parameter can be either a list of tenant names or a quoted expression like the one shown. Your application will be started before evaluating the quoted content if app_start_needed is true.

Use

Generate a migration file that will be run against each tenant:

mix apartmentex.gen.migration CreateUsers

By default, the migration will be generated to the "priv/YOUR_REPO/tenant_migrations" directory of the current application but it can be configured to be any subdirectory of priv by specifying the :priv key under the repository configuration.

You can now add a new tenant and automatically create a new schema for Postgres users or a new database for MySQL users, and run the migrations in priv/YOUR_REPO/tenant_migrations for that schema or database.

Table references and indexes in a migration will be applied to the same tenant prefix as the table within tenant_migrations.

Apartmentex.new_tenant(Repo, tenant)

When you need to update a tenant's schema based on new migrations, you can run:

# Runs all migrations necessary for the tenant, based on that tenant's
`schema_migrations` table
# Returns a tuple that is either:
# {:ok, prefix_of_tenant, versions_migrated}
# {:error, prefix_of_tenant, db_error_message}

{status, prefix, versions_or_error} = Apartmentex.migrate_tenant(Repo, tenant)

If there is a problem with a migration, you can roll it back by passing in the version (as an integer). This will revert every migration back until the version specified (including that version):

As a convenience, if you need to update all tenant schemas based on new migrations, you can run:

mix apartmentex.migrate

Note: this requires the schema_iterator config mentioned above.

# Returns a tuple that is either:
# {:ok, prefix_of_tenant, versions_rolled_back}
# {:error, prefix_of_tenant, db_error_message}

{status, prefix, versions_or_error} = Apartmentex.migrate_tenant(Repo, tenant, :down, to: 20160711125401)

When deleting a tenant, you can also automatically drop their associated schema or database (for MySQL).

Apartmentex.drop_tenant(Repo, tenant)

Include the tenant struct or tenant id in Apartmentex calls for queries, inserts, updates, and deletes.

  widgets = Apartmentex.all(Repo, Widget, tenant)

  Apartmentex.insert(Repo, changeset, tenant)

  Apartmentex.update(Repo, changeset, tenant_id)

  Apartmentex.delete!(Repo, widget, tenant_id)

To Do

  • mix task to migrate or rollback all tenant schemas/databases

About

SaaS support for Phoenix + Ecto

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Elixir 100.0%