# `Storehouse.Ecto.Usage`
[🔗](https://github.com/hattoriai/storehouse/blob/v0.2.0/lib/storehouse/ecto/usage.ex#L2)

Which records use each file of a library (`Storehouse.Ecto.Blob`): kept
as the records change, so the library can say what each file is used
by, and refuse to delete one that is used.

A record says which files it uses now, each time it is saved, in the
same transaction: a document whose blocks carry blob ids in JSON, a
page with a cover and a gallery.

    Repo.transaction(fn ->
      story = Repo.update!(changeset)
      ids = for %{"image_id" => id} <- story.blocks, do: id
      {:ok, _} = Storehouse.Ecto.Usage.record(Repo, story, ids)
      story
    end)

A record is named by its table and its primary key, so any schema's
records use files, with no column for each. A record deleted uses none:
`forget/3`.

    Storehouse.Ecto.Usage.used_by(Repo, blob)
    #=> [%{type: "stories", id: "42"}]

    Storehouse.Ecto.Usage.delete(Repo, blob)
    #=> {:error, {:in_use, [%{type: "stories", id: "42"}]}}

The usage table's foreign key refuses the deletion of a blob that is
used in the database itself, so two requests at once never delete a
file a record has just started to use.

Every function takes `:schema`, the blob schema (`Storehouse.Ecto.Blob`
by default); the usage table is the schema's (`use Storehouse.Ecto.Blob.Schema,
usages: …`).

# `user`

```elixir
@type user() :: %{type: String.t(), id: String.t()}
```

A record that uses a file: its table and its primary key.

# `delete`

```elixir
@spec delete(module(), struct(), keyword()) ::
  {:ok, struct()} | {:error, {:in_use, [user()]}} | {:error, Ecto.Changeset.t()}
```

Deletes `blob` from the library, and then its file from the store
(`Storehouse.delete_later/2`), unless a record uses it:
`{:error, {:in_use, records}}`, and nothing is deleted.

Inside a transaction of the app's, the file is not deleted: delete it
after the transaction commits, as a rollback would bring the row back.

# `forget`

```elixir
@spec forget(module(), struct(), keyword()) ::
  {:ok, %{added: 0, removed: non_neg_integer()}}
```

`record` uses no file any more: for a record deleted.

# `record`

```elixir
@spec record(module(), struct(), [String.t()], keyword()) ::
  {:ok, %{added: non_neg_integer(), removed: non_neg_integer()}}
  | {:error, {:unknown, [String.t()]}}
```

Makes `blob_ids` the files `record` uses, all of them: those it used and
no longer does are let go. Gives `{:ok, %{added: n, removed: n}}`, or
`{:error, {:unknown, ids}}` for ids that are no blob, and nothing is
changed.

It does not check whose the files are: check ids from a form or a
document with `Storehouse.Ecto.Blob.owned/4` first.

# `used`

```elixir
@spec used(module(), struct(), keyword()) :: [String.t()]
```

The ids of the files `record` uses.

# `used_by`

```elixir
@spec used_by(module(), struct() | String.t(), keyword()) :: [user()]
```

The records that use `blob` (a blob, or its id).

---

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