# `DoubleDown.Repo`
[🔗](https://github.com/mccraigmccraig/double_down/blob/main/lib/double_down/repo.ex#L21)

Repo contract for common Ecto Repo operations.

Provides `defcallback` declarations for the standard write and read operations
from `Ecto.Repo`, so that code using `DoubleDown` for database access doesn't
need to redeclare these with identical boilerplate.

## Usage

    # Define a facade in your app:
    defmodule MyApp.Repo do
      use DoubleDown.ContractFacade, contract: DoubleDown.Repo, otp_app: :my_app
    end

    changeset = User.changeset(%User{}, attrs)
    {:ok, user} = MyApp.Repo.insert(changeset)
    user = MyApp.Repo.get!(User, user_id)

## Write Operations

Write operations return `{:ok, struct()} | {:error, Ecto.Changeset.t()}`.

## Bulk Operations

`update_all/3` and `delete_all/2` follow Ecto's return convention of
`{count, nil | list}`.

## Read Operations

Read operations follow Ecto's conventions: `get/2`, `get_by/2`, `one/1`
return `nil` on not-found; `all/1` returns a list; `exists?/1` returns
a boolean; `aggregate/3` returns a term.

Raise-on-not-found variants (`get!/2`, `get_by!/2`, `one!/1`) mirror
Ecto's semantics.

# `aggregate`

```elixir
@callback aggregate(queryable :: Ecto.Queryable.t(), aggregate :: atom(), field :: atom()) ::
  term()
```

# `aggregate`

```elixir
@callback aggregate(
  queryable :: Ecto.Queryable.t(),
  aggregate :: atom(),
  field :: atom(),
  opts :: keyword()
) :: term()
```

# `all`

```elixir
@callback all(queryable :: Ecto.Queryable.t()) :: [struct()]
```

# `all`

```elixir
@callback all(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: [struct()]
```

# `delete`

```elixir
@callback delete(struct_or_changeset :: struct() | Ecto.Changeset.t()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}
```

# `delete`

```elixir
@callback delete(struct_or_changeset :: struct() | Ecto.Changeset.t(), opts :: keyword()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}
```

# `delete!`

```elixir
@callback delete!(struct_or_changeset :: struct() | Ecto.Changeset.t()) :: struct()
```

# `delete!`

```elixir
@callback delete!(struct_or_changeset :: struct() | Ecto.Changeset.t(), opts :: keyword()) ::
  struct()
```

# `delete_all`

```elixir
@callback delete_all(queryable :: Ecto.Queryable.t(), opts :: keyword()) ::
  {non_neg_integer(), nil | list()}
```

# `exists?`

```elixir
@callback exists?(queryable :: Ecto.Queryable.t()) :: boolean()
```

# `exists?`

```elixir
@callback exists?(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: boolean()
```

# `get`

```elixir
@callback get(queryable :: Ecto.Queryable.t(), id :: term()) :: struct() | nil
```

# `get`

```elixir
@callback get(queryable :: Ecto.Queryable.t(), id :: term(), opts :: keyword()) ::
  struct() | nil
```

# `get!`

```elixir
@callback get!(queryable :: Ecto.Queryable.t(), id :: term()) :: struct()
```

# `get!`

```elixir
@callback get!(queryable :: Ecto.Queryable.t(), id :: term(), opts :: keyword()) ::
  struct()
```

# `get_by`

```elixir
@callback get_by(queryable :: Ecto.Queryable.t(), clauses :: keyword() | map()) ::
  struct() | nil
```

# `get_by`

```elixir
@callback get_by(
  queryable :: Ecto.Queryable.t(),
  clauses :: keyword() | map(),
  opts :: keyword()
) ::
  struct() | nil
```

# `get_by!`

```elixir
@callback get_by!(queryable :: Ecto.Queryable.t(), clauses :: keyword() | map()) ::
  struct()
```

# `get_by!`

```elixir
@callback get_by!(
  queryable :: Ecto.Queryable.t(),
  clauses :: keyword() | map(),
  opts :: keyword()
) ::
  struct()
```

# `insert`

```elixir
@callback insert(struct_or_changeset :: Ecto.Changeset.t() | struct()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}
```

# `insert`

```elixir
@callback insert(struct_or_changeset :: Ecto.Changeset.t() | struct(), opts :: keyword()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}
```

# `insert!`

```elixir
@callback insert!(struct_or_changeset :: Ecto.Changeset.t() | struct()) :: struct()
```

# `insert!`

```elixir
@callback insert!(struct_or_changeset :: Ecto.Changeset.t() | struct(), opts :: keyword()) ::
  struct()
```

# `insert_all`

```elixir
@callback insert_all(
  source :: Ecto.Queryable.t() | binary(),
  entries :: [map() | keyword()],
  opts :: keyword()
) :: {non_neg_integer(), nil | list()}
```

# `one`

```elixir
@callback one(queryable :: Ecto.Queryable.t()) :: struct() | nil
```

# `one`

```elixir
@callback one(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: struct() | nil
```

# `one!`

```elixir
@callback one!(queryable :: Ecto.Queryable.t()) :: struct()
```

# `one!`

```elixir
@callback one!(queryable :: Ecto.Queryable.t(), opts :: keyword()) :: struct()
```

# `query`

```elixir
@callback query(sql :: String.t()) :: {:ok, term()} | {:error, term()}
```

# `query`

```elixir
@callback query(sql :: String.t(), params :: list()) :: {:ok, term()} | {:error, term()}
```

# `query`

```elixir
@callback query(sql :: String.t(), params :: list(), opts :: keyword()) ::
  {:ok, term()} | {:error, term()}
```

# `query!`

```elixir
@callback query!(sql :: String.t()) :: term()
```

# `query!`

```elixir
@callback query!(sql :: String.t(), params :: list()) :: term()
```

# `query!`

```elixir
@callback query!(sql :: String.t(), params :: list(), opts :: keyword()) :: term()
```

# `rollback`

```elixir
@callback rollback(value :: term()) :: no_return()
```

# `transact`

```elixir
@callback transact(fun_or_multi :: term(), opts :: keyword()) ::
  {:ok, term()} | {:error, term()} | {:error, term(), term(), term()}
```

# `update`

```elixir
@callback update(changeset :: Ecto.Changeset.t()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}
```

# `update`

```elixir
@callback update(changeset :: Ecto.Changeset.t(), opts :: keyword()) ::
  {:ok, struct()} | {:error, Ecto.Changeset.t()}
```

# `update!`

```elixir
@callback update!(changeset :: Ecto.Changeset.t()) :: struct()
```

# `update!`

```elixir
@callback update!(changeset :: Ecto.Changeset.t(), opts :: keyword()) :: struct()
```

# `update_all`

```elixir
@callback update_all(
  queryable :: Ecto.Queryable.t(),
  updates :: keyword(),
  opts :: keyword()
) ::
  {non_neg_integer(), nil | list()}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
