README.md

# Toggle
<!-- MDOC !-->

Toggle is a stupid-simple feature flag library for Elixir.

It provides a simple API for enabling and disabling feature flags in your application.

## Installation

Add `toggle` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:toggle, "~> 0.1.0"}
  ]
end
```

## Usage

In order to use Toggle, you need to add an Ecto Migration to your application to set up the database table
`Toggle` will use to store data.

Currently, `Toggle` supports SQLite3 and Postgres as database backends.

You can create migrations using the `Toggle.Migrations.SQLite` or `Toggle.Migrations.Postgres` helper modules:

```elixir
defmodule MyApp.Repo.Migrations.CreateFlagsTables do
  use Ecto.Migration

  def up do
    # Replace `Toggle.Migrations.SQLite` with `Toggle.Migrations.Postgres` if you are using Postgres
    Toggle.Migrations.SQLite.up(table: "toggle_flags")
  end

  def down do
    # Replace `Toggle.Migrations.SQLite` with `Toggle.Migrations.Postgres` if you are using Postgres
    Toggle.Migrations.SQLite.down(table: "toggle_flags")
  end
end
```

After you have run your migrations, you can start using `Toggle` in your application.

```elixir
iex> Toggle.enabled?("my_feature")
false
iex> Toggle.enable!("my_feature")
:ok
iex> Toggle.enabled?("my_feature")
true
```

You can also enable flags specifically for some arbitrary resource:

```elixir
iex> Toggle.disable!("my_feature")
:ok
iex> Toggle.enable!("my_feature", user_id: 123)
:ok
iex> Toggle.enabled?("my_feature")
false
iex> Toggle.enabled?("my_feature", user_id: 123)
true
```

Resources are key-value pairs that can be used to enable or disable a flag for a specific entity. The expected data
type for both the key and value is an atom, string, or integer.

Today, toggle only supports boolean flags, but we plan to add support for more flag types in the future.

Whether or not a flag is enabled is determined by the following rules:

- If a flag is enabled for a resource, that resource's value takes precedence over the global value.
- If a flag is disabled for a resource, that resource's value takes precedence over the global value.
- Otherwise, the global value is used.

> #### Info {: .info}
>
> One edge case is that `Toggle.disabled?/1` and `Toggle.disabled?/2` are implemented as inverses of `Toggle.enabled?/1` and
> `Toggle.enabled?/2` which means that if a flag does not exist, it is considered disabled.

## Caching

Querying flags on every request can be expensive, so `Toggle` provides a caching layer to speed up flag lookups.

Whenever a flag is created, updated, or deleted, we update a cache with the latest flag data using `Cachex` under the
`:toggle_cache` namespace.

Whenever the cache is mutated, `Toggle.Cache` will asynchronously publish the changes to all other connected nodes
using Erlang's `:erpc` module. In the future, we plan to add support for other pubsub strategies.

Using `Toggle.enabled?/1`, `Toggle.enabled?/2`, `Toggle.disabled?/1`, or `Toggle.disabled?/2` will automatically use
the cache if it is available.

The cache has a default ttl of one minute.

## Configuration

`Toggle` aims to be as simple as possible, and as such, it does not require any configuration.

The only possible configuration at the time of writing is:

- `:flag_table_name` - The name of the database table used to store flags. Defaults to `"toggle_flags"`.
- `:cache_ttl` - The time-to-live for cached flags. Defaults to 1 minute.

See `Toggle.Comptime` for more information.

## Further Reading

The core API for `Toggle` is provided by the `Toggle` module. You can use the `Toggle` module to enable and disable flags,
and check if a flag is enabled or disabled.

For more complex querying, please see the `Toggle.Flags` module, the `Toggle.Flags.Flag` schema, and the libraries
this application is built on: `EctoModel` and `EctoHooks`.

The `Toggle.Flags.Flag` schema implements the `EctoModel.Queryable` behaviour, which lends itself well to fluent-api
style querying.

For example, you are able to query flags using the `Toggle.Flags.Flag.query/2` function:

```elixir
iex> MyApp.Repo.one(Toggle.Flags.Flag.query(name: "my_flag", disabled: true))
%Toggle.Flags.Flag{name: "my_flag", enabled: false}
```

Additionally, please feel free to query the `Toggle.Flags.Flag` schema directly.

## Future Work

- Add support for more flag types such as `:percentage` and `:datetime`.
- Add support for deprecating flags and emitting deprecation warnings after a certain date.
- Add support for hooks that can be run before or after a flag is enabled or disabled.
- Pluggable pub/sub strategies.
- Add a `Phoenix.LiveView` interface for managing flags in real-time.
    - Including metrics and analytics for flag usage.