View Source BitcrowdEcto.Repo behaviour (bitcrowd_ecto v1.0.0)

Extensions for Ecto repos.

Usage

defmodule MyApp.Repo do
  use Ecto.Repo, otp_app: :my_app, adapter: Ecto.Adapters.Postgres

  use BitcrowdEcto.Repo
end

Summary

Callbacks

Acquires an advisory lock for a named resource.

Allows to conveniently count a queryable.

Allows to conveniently count a queryable.

Fetches a record by primary key or returns a "tagged" error tuple.

Fetches a record by given clauses or returns a "tagged" error tuple.

Fetches a record by given clauses or returns a "tagged" error tuple.

Fetches a record by given clauses or returns a "tagged" error tuple.

Types

Link to this type

ecto_option()

View Source (since 0.1.0)
@type ecto_option() ::
  {:prefix, binary()}
  | {:timeout, integer() | :infinity}
  | {:log, Logger.level() | false}
  | {:telemetry_event, any()}
  | {:telemetry_options, any()}
Link to this type

fetch_option()

View Source (since 0.1.0)
@type fetch_option() ::
  {:lock, lock_mode() | false}
  | {:preload, atom() | list()}
  | {:error_tag, any()}
  | {:raise_cast_error, boolean()}
  | ecto_option()
Link to this type

fetch_result()

View Source (since 0.1.0)
@type fetch_result() ::
  {:ok, Ecto.Schema.t()} | {:error, {:not_found, Ecto.Queryable.t() | any()}}
Link to this type

lock_mode()

View Source (since 0.1.0)
@type lock_mode() :: :no_key_update | :update

Callbacks

Link to this callback

advisory_xact_lock(arg1)

View Source (since 0.1.0)
@callback advisory_xact_lock(atom() | binary()) :: :ok

Acquires an advisory lock for a named resource.

Advisory locks are helpful when you don't have a specific row to lock, but also don't want to lock an entire table.

See https://www.postgresql.org/docs/9.4/explicit-locking.html#ADVISORY-LOCKS

Example

MyApp.Repo.transaction(fn ->
  MyApp.Repo.advisory_lock(:foo)
  # Advisory lock is held until end of transaction
end)

A note on the advisory lock key

pg_advisory_xact_lock() has two versions: One which you pass a 64-bit signed integer as the lock key, and one which you pass two 32-bit integers as the keys (e.g., one "application" key and one specific lock key), in which case PostgreSQL concatenates them into a 64-bit value. In any case you need to pass integers.

We decided that we wanted to have atom or string keys for better readability. Hence, in= order to make PostgreSQL happy, we hash these strings into 64 bits signed ints.

64 bits make a pretty big number already, so it is quite unlikely that two of our keys (or keys of other libraries that use advisory locks, e.g. Oban) collide. But for an extra false sense of safety we use a crypto hash algorithm to ensure that keys spread out over the domain uniformly. Luckily, taking a prefix of a cryptographic hash does not break its uniformity.

Link to this callback

count(queryable)

View Source (since 0.1.0)
@callback count(queryable :: Ecto.Queryable.t()) :: non_neg_integer()

Allows to conveniently count a queryable.

See count/2 for options.

Link to this callback

count(queryable, list)

View Source (since 0.15.0)
@callback count(queryable :: Ecto.Queryable.t(), [ecto_option()]) :: non_neg_integer()

Allows to conveniently count a queryable.

Ecto options

Link to this callback

fetch(schema, id)

View Source (since 0.1.0)
@callback fetch(schema :: module(), id :: any()) :: fetch_result()

Fetches a record by primary key or returns a "tagged" error tuple.

See fetch_by/3.

Link to this callback

fetch(schema, id, list)

View Source (since 0.1.0)
@callback fetch(schema :: module(), id :: any(), [fetch_option()]) :: fetch_result()

Fetches a record by given clauses or returns a "tagged" error tuple.

See fetch_by/3 for options.

Link to this callback

fetch_by(queryable, clauses)

View Source (since 0.1.0)
@callback fetch_by(queryable :: Ecto.Queryable.t(), clauses :: map() | keyword()) ::
  fetch_result()

Fetches a record by given clauses or returns a "tagged" error tuple.

See fetch_by/3 for options.

Link to this callback

fetch_by(queryable, clauses, list)

View Source (since 0.1.0)
@callback fetch_by(queryable :: Ecto.Queryable.t(), clauses :: map() | keyword(), [
  fetch_option()
]) ::
  fetch_result()

Fetches a record by given clauses or returns a "tagged" error tuple.

  • On success, the record is wrapped in a :ok tuple.
  • On error, a "tagged" error tuple is returned that contains the original queryable or module as the tag, e.g. {:error, {:not_found, Account}} for a fetch_by(Account, id: 1) call.

Passing invalid values that would normally result in an Ecto.Query.CastError will result in a :not_found error tuple as well.

This function can also apply row locks.

Options

  • lock any of [:no_key_update, :update] (defaults to false)
  • preload allows to preload associations
  • error_tag allows to specify a custom "tag" value (instead of the queryable)
  • raise_cast_error raise CastError instead of converting to :not_found (defaults to false)

Ecto options