README.md

# MaxoUniRepo

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

`MaxoUniRepo` helps you to support multiple DB engines with runtime DB switching all with a single Ecto Repo module.

## Usage

```elixir
# Step 1: define your main repo
# - it will proxy requests to DB-specific repos
defmodule MiniApp.Repo do
  use MaxoUniRepo.EctoBehaviour, validate: false
end


# Step 2: define how your DB specific repos should look
# - will generate 3 in-memory repo modules for each DB type(psql / mysql / sqlite)
# - if you need any modifications (like pagination / soft-delete, etc), this is the place to implements it
defmodule MiniApp.RepoSetup do
  use MaxoUniRepo.RepoSetup

  common do
    @impl true
    def init(_context, config), do: {:ok, config}
  end
end


# Step 3: Configure the application to start the RepoSupervisor + setup default DB
defmodule MiniApp.Application do
  @moduledoc false
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      # Do not start the main repo directly, but start the RepoSupervisor to manage our repos
      MaxoUniRepo.RepoSupervisor
    ]

    opts = [strategy: :one_for_one, name: MiniApp.Supervisor]
    res = Supervisor.start_link(children, opts)

    # Configure the default in-memory Sqlite DB after the RepoSupervisor started
    MaxoUniRepo.Setup.to_sqlite(true)
    res
  end
end


# Step 4: now provide the config for maxo_uni_repo + our default repo:
## in config/config.exs
import Config

## Configure maxo_uni_repo to use our "proxy" Repo + which app we are targetting
config :maxo_uni_repo, main_repo: MiniApp.Repo
config :maxo_uni_repo, main_app: :mini_app

## Default setup for mini_app repos, so mix generators work properly
config :mini_app, ecto_repos: [MiniApp.Repo.SqliteRepo]

config :mini_app, MiniApp.Repo.SqliteRepo,
  database: "./data/sqlite.db",
  priv: "priv/repo"

##########################################################################
### Now you can start using the MiniApp.Repo with the configured Sqlite DB
### and also switch at runtime to any other DB
##########################################################################

# Use the pre-configured Sqlite DB
iex> MiniApp.Repo.query("create table users(id, name)")
{:ok, %Exqlite.Result{command: :execute, columns: [], rows: [], num_rows: 0}}

iex> MiniApp.Repo.query("insert into users(id, name) values (1, 'first')")
{:ok, %Exqlite.Result{command: :execute, columns: [], rows: [], num_rows: 0}}

iex> MiniApp.Repo.query("select count(id) from users")
{:ok,
 %Exqlite.Result{
   command: :execute,
   columns: ["count(id)"],
   rows: [[1]],
   num_rows: 1
 }}

# switch to an in-memory Sqlite db
iex> MaxoUniRepo.Connector.connect("file:new.db?mode=memory&cache=shared")
[debug] [MaxoAdapt] Linked `MiniApp.Repo` to implementation `MiniApp.Repo.SqliteRepo`.
:ok


iex> MiniApp.Repo.query("select count(id) from users")
{:error,
 %Exqlite.Error{
   message: "no such table: users",
   statement: "select count(id) from users"
 }}


# Switch to a Postgres DB
iex> MaxoUniRepo.Connector.connect("postgres://postgres:postgres@localhost:5432/postgres")
[debug] [MaxoAdapt] Linked `MiniApp.Repo` to implementation `MiniApp.Repo.PsqlRepo`.
:ok

# The users table does not exist here
iex> MiniApp.Repo.query("select count(id) from users")
{:error,
 %Postgrex.Error{
   message: nil,
   postgres: %{
     code: :undefined_table,
     file: "parse_relation.c",
     line: "1384",
     message: "relation \"users\" does not exist",
     pg_code: "42P01",
     position: "23",
     routine: "parserOpenTable",
     severity: "ERROR",
     unknown: "ERROR"
   },
   connection_id: 978,
   query: "select count(id) from users"
 }}
```

## Installation

The package can be installed by adding `maxo_uni_repo` to your list of dependencies in `mix.exs`:

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

The docs can be found at <https://hexdocs.pm/maxo_uni_repo>.

## Support

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

## License

The lib is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).