# `EctoFoundationDB.Tenant`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L1)

This module allows the application to create, open, and delete
tenants within the FoundationDB database. All transactions require a tenant,
so any application that uses the Ecto FoundationDB Adapter must use this module.

EctoFoundationDB supports 2 different backends for the Tenant implementation:

1. `EctoFoundationDB.Tenant.DirectoryTenant`: The default. Tenants are managed via
   the `:erlfdb_directory` layer. Each tenant is assigned a byte prefix. EctoFDB
   puts that prefix as the first element of every tuple key. If your application wishes
   to write keys directly to the database, it must also respect this prefix.
2. `EctoFoundationDB.Tenant.ManagedTenant`: Uses the experimental [FoundationDB Tenants](https://apple.github.io/foundationdb/tenants.html).
   This requires `tenant_mode=required_experimental` or `tenant_mode=optional_experimental`
   to be enabled on your FDB system. EctoFDB does not need to prefix keys because it happens
   automatically at the FDB transaction level. If your application wishes to write keys
   directory to the database, there is no prefix to worry about. **Use caution:** FDB Tenants
   are not yet tested with the same rigor as the rest of FDB.

If you wish to use the experimental ManagedTenant, add this option to your Repo config:

```elixir
config :my_app, MyApp.Repo,
  tenant_backend: EctoFoundationDB.Tenant.ManagedTenant
```

EctoFDB does not support switching between tenant backends on a database. If you want to switch backend,
you must use a new empty database.

# `id`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L43)

```elixir
@type id() :: :erlfdb.tenant_name()
```

# `prefix`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L44)

```elixir
@type prefix() :: String.t()
```

# `t`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L42)

```elixir
@type t() :: %EctoFoundationDB.Tenant{
  backend: term(),
  id: term(),
  meta: term(),
  options: term(),
  ref: term(),
  repo: term(),
  txobj: term()
}
```

# `clear`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L138)

```elixir
@spec clear(Ecto.Repo.t(), id()) :: :ok
```

Clear all data for the given tenant. This cannot be undone.

# `clear_delete!`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L66)

```elixir
@spec clear_delete!(Ecto.Repo.t(), id()) :: :ok
```

Clears data in a tenant and then deletes it. If the tenant doesn't exist, no-op.

# `create`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L60)

```elixir
@spec create(Ecto.Repo.t(), id()) :: :ok
```

Create a tenant in the database.

# `delete`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L145)

```elixir
@spec delete(Ecto.Repo.t(), id()) :: :ok
```

Deletes a tenant from the database permanently. The tenant must
have no data.

# `exists?`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L53)

```elixir
@spec exists?(Ecto.Repo.t(), id()) :: boolean()
```

Returns true if the tenant already exists in the database.

# `extend_tuple`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L201)

# `list`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L132)

```elixir
@spec list(Ecto.Repo.t()) :: [id()]
```

List all tenants in the database. Could be expensive.

# `open`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L89)

```elixir
@spec open(Ecto.Repo.t(), id(), EctoFoundationDB.Options.t()) :: t()
```

Open a tenant with a repo. With the result returned by this function, the caller can
do database operations on the tenant's portion of the key-value store.

The tenant must already exist.

When opening tenants with a repo, all migrations are automatically performed. This
can cause open/2 to take a significant amount of time. Tenants can be kept open
indefinitely, with any number of database transactions issued upon them.

# `open!`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L107)

```elixir
@spec open!(Ecto.Repo.t(), id(), EctoFoundationDB.Options.t()) :: t()
```

Open a tenant. With the result returned by this function, the caller can
do database operations on the tenant's portion of the key-value store.

If the tenant does not exist, it is created.

When opening tenants with a repo, all migrations are automatically performed. This
can cause open/2 to take a significant amount of time. Tenants can be kept open
indefinitely, with any number of database transactions issued upon them.

# `open_empty!`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L120)

```elixir
@spec open_empty!(Ecto.Repo.t(), id(), EctoFoundationDB.Options.t()) :: t()
```

Helper function to ensure the given tenant exists and then clear
it of all data, and finally return an open handle. Useful in test code,
but in production, this would be dangerous.

# `pack`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L167)

Packs an Elixir tuple into an FDB-encoded Tuple.

## Keyspace Design
We always pack into a **non-prefixed tuple key**. In other words, EctoFDB
DirectoryTenant keys use the subspace prefix as the first tuple element
instead of binary key prefix. As such, our keys are not compliant with
other Directory Layer implementations. However, we've made this choice so that
we can continue to use GetMappedRange functionality. (Indeed, the GetMappedRange mapper spec
has reserved syntax for stripping out non-tuple prefixes, but it's not yet implemented.)
Note: ManagedTenant keys do not use directories/subspaces. The underlying binary
prefix that a ManagedTenant uses internally still allows use of GetMappedRange.

ManagedTenants and GetMappedRange are both experimental features. The safest choice is
to use neither, but that would forfeit the GetMappedRange optimization. We choose
to accept the risk of GetMappedRange, which can easily be replaced with a different
client implementation, and suggest against using ManagedTenant because it puts
your data at risk with its unsupported[[0](https://github.com/apple/foundationdb/issues/11292)][[1](https://github.com/apple/foundationdb/issues/11382)]
keyspace.

# `pack_vs`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L178)

Packs an Elixir tuple having an incomplete versionstamp into an FDB-encoded Tuple.

Caller should proceed to use `:erlfdb.set_versionstamped_key` or `:erlfdb.set_versionstamped_value`
as needed.

# `primary_codec`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L183)

# `range`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L196)

# `repo`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L47)

# `set_metadata_cache`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L205)

# `txobj`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L46)

# `unpack`
[🔗](https://github.com/foundationdb-beam/ecto_foundationdb/blob/main/lib/ecto_foundationdb/tenant.ex#L190)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
