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

A library of files: a row a file, owned by someone (an account, a site),
referenced from many records, kept when the record that first used it
is deleted. Its tables are `Storehouse.Ecto.Migrations`'s; which records
use each file is `Storehouse.Ecto.Usage`'s.

For a file a record has alone (an avatar, an invoice), a column of the
record is simpler: `Storehouse.Ecto.File`, with no table.

This module is a schema of `storehouse_blobs`. An app with a table of its
own, or fields of its own (a description, a credit), writes its schema
with the same fields:

    defmodule MyApp.Photo do
      use Storehouse.Ecto.Blob.Schema, usages: "photo_usages"

      schema "photos" do
        Storehouse.Ecto.Blob.Schema.fields()
        field :alt_text, :string
      end
    end

and gives it as `schema:` to this module's functions and
`Storehouse.Ecto.Usage`'s. Its migration is
`Storehouse.Ecto.Migrations.up(blobs: "photos", usages: "photo_usages")`,
then its own columns.

## A file into the library

    {:ok, file} = Storehouse.store(upload.path, owner: "sites/7")
    {:ok, blob} = Storehouse.Ecto.Blob.insert(Repo, file, owner: "sites/7")

The same file again, for the same owner, is the row the library has:
`{:existing, blob}`, by the checksum.

# `t`

```elixir
@type t() :: struct()
```

# `insert`

```elixir
@spec insert(module(), Storehouse.File.t(), keyword()) ::
  {:ok, t()} | {:existing, t()} | {:error, Ecto.Changeset.t()}
```

Puts a stored file in the library: `{:ok, blob}`, or `{:existing, blob}`
when the owner has the same file already (by its checksum), or
`{:error, changeset}`.

## Options

  * `:owner` - whose file it is: the same as `Storehouse.store/2`'s.
  * `:store` - the store it is kept in, a module. The default is
    `Storehouse.adapter/0`.
  * `:schema` - the blob schema. The default is this module.
  * `:attrs` - more fields of the app's schema: `%{alt_text: "…"}`.

# `owned`

```elixir
@spec owned(module(), [String.t()], String.t() | integer() | nil, keyword()) ::
  {:ok, [String.t()]} | {:error, {:not_owned, [String.t()]}}
```

Checks that every id of `ids` is a blob of `owner`, before a record
refers to them: `{:ok, ids}`, or `{:error, {:not_owned, ids}}` with those
that are not (another's, or none at all). For ids a form or a document
sends, which are never to be trusted.

## Options

  * `:schema` - the blob schema. The default is this module.

# `to_file`

```elixir
@spec to_file(struct()) :: Storehouse.File.t()
```

The blob as a `Storehouse.File`, with its URL in its store: to show
it, sign it, make its variants.

# `validate_owned`

```elixir
@spec validate_owned(Ecto.Changeset.t(), atom(), module(), term(), keyword()) ::
  Ecto.Changeset.t()
```

In a changeset, the error `"is not a file of yours"` on `field` (a list
of blob ids) for any id that is not a blob of `owner` (`owned/4`).

---

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