View Source AshPostgres.Repo behaviour (ash_postgres v2.4.16)

Resources that use AshPostgres.DataLayer use a Repo to access the database.

This repo is a thin wrapper around an Ecto.Repo.

You can use Ecto.Repo's init/2 to configure your repo like normal, but instead of returning {:ok, config}, use super(config) to pass the configuration to the AshPostgres.Repo implementation.

Installed Extensions

To configure your list of installed extensions, define installed_extensions/0

Extensions can be a string, representing a standard postgres extension, or a module that implements AshPostgres.CustomExtension. That custom extension will be called to generate migrations that serve a specific purpose.

Extensions that are relevant to ash_postgres:

def installed_extensions() do
  ["pg_trgm", "uuid-ossp", "vector", YourCustomExtension]
end

Transaction Hooks

You can define on_transaction_begin/1, which will be invoked whenever a transaction is started for Ash.

This will be invoked with a map containing a type key and metadata.

%{type: :create, %{resource: YourApp.YourResource, action: :action}}

Additional Repo Configuration

Because an AshPostgres.Repo is also an Ecto.Repo, it has all of the same callbacks.

In the Ecto.Repo.init/2 callback, you can configure the following additional items:

  • :tenant_migrations_path - The path where your tenant migrations are stored (only relevant for a multitenant implementation)
  • :snapshots_path - The path where the resource snapshots for the migration generator are stored.

Summary

Callbacks

Return a list of all schema names (only relevant for a multitenant implementation)

Should the repo should be created by mix ash_postgres.create?

The default prefix(postgres schema) to use when building queries

Should the repo should be dropped by mix ash_postgres.drop?

Use this to inform the data layer about what extensions are installed

The path where your migrations are stored

Configure the version of postgres that is being used.

Use this to inform the data layer about the oldest potential postgres version it will be run on.

Allows overriding a given migration type for all fields, for example if you wanted to always use :timestamptz for :utc_datetime fields

Whether or not to explicitly start and close a transaction for each action, even if there are no transaction hooks. Defaults to true.

Whether or not to explicitly start and close a transaction for each atomic update action, even if there are no transaction hooks. Defaults to false.

The path where your tenant migrations are stored (only relevant for a multitenant implementation)

Callbacks

all_tenants()

@callback all_tenants() :: [String.t()]

Return a list of all schema names (only relevant for a multitenant implementation)

create?()

@callback create?() :: boolean()

Should the repo should be created by mix ash_postgres.create?

default_prefix()

@callback default_prefix() :: String.t()

The default prefix(postgres schema) to use when building queries

drop?()

@callback drop?() :: boolean()

Should the repo should be dropped by mix ash_postgres.drop?

installed_extensions()

@callback installed_extensions() :: [String.t() | module()]

Use this to inform the data layer about what extensions are installed

migrations_path()

@callback migrations_path() :: String.t() | nil

The path where your migrations are stored

min_pg_version()

@callback min_pg_version() :: Version.t()

Configure the version of postgres that is being used.

on_transaction_begin(reason)

@callback on_transaction_begin(reason :: Ash.DataLayer.transaction_reason()) :: term()

Use this to inform the data layer about the oldest potential postgres version it will be run on.

Must be an integer greater than or equal to 13.

Combining with other tools

For things like Fly.Repo, where you might need to have more fine grained control over the repo module, you can use the define_ecto_repo?: false option to use AshPostgres.Repo.

override_migration_type(atom)

@callback override_migration_type(atom()) :: atom()

Allows overriding a given migration type for all fields, for example if you wanted to always use :timestamptz for :utc_datetime fields

prefer_transaction?()

@callback prefer_transaction?() :: boolean()

Whether or not to explicitly start and close a transaction for each action, even if there are no transaction hooks. Defaults to true.

prefer_transaction_for_atomic_updates?()

@callback prefer_transaction_for_atomic_updates?() :: boolean()

Whether or not to explicitly start and close a transaction for each atomic update action, even if there are no transaction hooks. Defaults to false.

tenant_migrations_path()

@callback tenant_migrations_path() :: String.t() | nil

The path where your tenant migrations are stored (only relevant for a multitenant implementation)