# MaxoAdapt

[![CI](https://github.com/maxohq/maxo_adapt/actions/workflows/ci.yml/badge.svg?style=flat)](https://github.com/maxohq/maxo_adapt/actions/workflows/ci.yml)
[![Hex.pm](https://img.shields.io/hexpm/v/maxo_adapt.svg?style=flat)](https://hex.pm/packages/maxo_adapt)
[![Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg?style=flat)](https://hexdocs.pm/maxo_adapt)
[![Total Download](https://img.shields.io/hexpm/dt/maxo_adapt.svg?style=flat)](https://hex.pm/packages/maxo_adapt)
[![License](https://img.shields.io/hexpm/l/maxo_adapt.svg?style=flat)](https://github.com/maxohq/maxo_adapt/blob/main/LICENCE)

MaxoAdapt generates adapter facades from ordinary Elixir callbacks. The generated functions retain callback documentation and specs, validate implementations, and can use either direct delegates or runtime lookup.

MaxoAdapt is derived from [Ian Luites' adapter library](https://github.com/IanLuites/adapter), with additional fixes and runtime modes.

## Why use it?

- **Fast:** `:compile` and `:get_compiled` dispatch through direct delegates.
- **Small:** the package has no runtime dependencies beyond Logger.
- **Safe:** required callback name/arity pairs are validated before mutable configuration.
- **Explicit:** the behaviour and generated facade live in one module.
- **Flexible:** choose immutable compile-time configuration, global runtime configuration, or process-isolated test configuration.

## Installation

```elixir
def deps do
  [
    {:maxo_adapt, "~> 0.1"}
  ]
end
```

MaxoAdapt requires Elixir 1.14 or later.

## Quick start

```elixir
defmodule SessionRepo do
  use MaxoAdapt

  behaviour do
    @doc "Look up a session by token."
    @callback get(token :: binary()) :: {:ok, term() | nil} | {:error, atom()}
  end

  @spec get!(binary()) :: term() | nil
  def get!(token) do
    case get(token) do
      {:ok, result} -> result
      {:error, reason} -> raise "SessionRepo: #{reason}"
    end
  end
end

defmodule SessionRepo.PostgreSQL do
  @behaviour SessionRepo

  @impl SessionRepo
  def get(token), do: {:ok, {token, :postgresql}}
end

:ok = SessionRepo.configure(SessionRepo.PostgreSQL)
{:ok, {"token", :postgresql}} = SessionRepo.get("token")
```

## Modes

| Mode | Lookup | Runtime switching | Typical use |
|---|---|---:|---|
| `:compile` (default) | regenerated direct delegates | yes | fast production dispatch |
| `:get_compiled` | `Application.compile_env/3` + direct delegates | no | immutable compile-time choice |
| `:get_env` | `Application.get_env/3` per call | yes | simple global runtime switching |
| `:get_dict` | process dictionary + live ancestors | yes | async test isolation |

Call `YourAdapter.__maxo_adapt__/0` to inspect the effective implementation.

## Guides

- [Introduction and modes](guides/intro.md)
- [Configuration](guides/configuration.md)
- [Debugging](guides/debugging.md)
- [Compatibility and quality checks](guides/compatibility.md)

Published API documentation is available at <https://hexdocs.pm/maxo_adapt>.

## Support

<p>
  <a href="https://quantor.consulting/?utm_source=github&utm_campaign=maxo_adapt">
    <img src="https://raw.githubusercontent.com/maxohq/sponsors/main/assets/quantor_consulting_logo.svg"
      alt="Sponsored by Quantor Consulting" width="210">
  </a>
</p>

## License

MaxoAdapt is available under the [MIT License](https://github.com/maxohq/maxo_adapt/blob/main/LICENCE).
