kura_repo behaviour (kura v2.17.1)

View Source

Behaviour for defining a repository (database connection).

Implement otp_app/0 to tell Kura which application owns the repo's migrations.

-module(my_repo).
-behaviour(kura_repo).
-export([otp_app/0]).

otp_app() -> my_app.

Configure the database connection under the kura application env. Repos go in a {repos, #{Name => Cfg}} map; Kura starts the pool for each repo automatically during application startup.

[{kura, [
    {repos, #{
        my_repo => #{
            backend => kura_backend_postgres,
            host => "localhost",
            port => 5432,
            database => "my_db",
            user => "postgres",
            password => "secret",
            pool_size => 10
        }
    }}
]}].

The same form scales to multiple repos (e.g. a Postgres primary plus a SQLite analytics store):

[{kura, [
    {repos, #{
        my_repo => #{
            backend => kura_backend_postgres,
            host => "localhost",
            database => "my_db",
            pool_size => 10
        },
        analytics_repo => #{
            backend => kura_backend_sqlite,
            database => <<":memory:">>
        }
    }}
]}].

Each repo's dialect, pool, and driver are resolved from its backend key. Queries through different repos use their own dialects; the query cache is keyed per repo.

For backward compatibility, Kura also accepts the flat single-repo form ({repo, _}/{backend, _}/{host, _} at the kura env level) and the per-app form (application:get_env(OtpApp, RepoModule)). The {repos, ...} map is checked first, then the flat env, then the per-app form. New projects should prefer the map form.

Optionally implement init/1 to modify config at runtime - useful for reading secrets from files, environment variables, or external services:

-module(my_repo).
-behaviour(kura_repo).
-export([otp_app/0, init/1]).

otp_app() -> my_app.

init(Config) ->
    Config#{
        password => list_to_binary(os:getenv("DB_PASSWORD", "postgres"))
    }.

Summary

Functions

Read the repo configuration from application environment.

Return true if the repo is configured read_only => true.

Pick a replica repo for RepoMod from its replicas => [Repo] config.

Callbacks

init(Config)

(optional)
-callback init(Config :: map()) -> map().

otp_app()

-callback otp_app() -> atom().

Functions

config(RepoMod)

-spec config(module()) -> map().

Read the repo configuration from application environment.

read_only(RepoMod)

-spec read_only(module()) -> boolean().

Return true if the repo is configured read_only => true.

A read-only repo rejects writes (insert/update/delete and the bulk and soft-delete variants return {error, read_only}). Reads are unaffected. Intended for a replica repo pointed at a read replica.

replica(RepoMod)

-spec replica(module()) -> module().

Pick a replica repo for RepoMod from its replicas => [Repo] config.

Returns a randomly-chosen replica, or RepoMod itself when none are configured. Routing is explicit: the caller runs reads through the returned repo ((kura_repo:replica(MyRepo)):all(Q)), so the caller owns read-after-write consistency. There is no automatic write/read split.