MaxoUniRepo
helps you to support multiple DB engines with runtime DB switching all with a single Ecto Repo module.
# 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"
}}
The package can be installed by adding maxo_uni_repo
to your list of dependencies in mix.exs
:
def deps do
[
{:maxo_uni_repo, "~> 0.1"}
]
end
The docs can be found at https://hexdocs.pm/maxo_uni_repo.
The lib is available as open source under the terms of the MIT License.