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: …).
Summary
Functions
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.
record uses no file any more: for a record deleted.
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.
The ids of the files record uses.
The records that use blob (a blob, or its id).
Types
Functions
@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.
@spec forget(module(), struct(), keyword()) :: {:ok, %{added: 0, removed: non_neg_integer()}}
record uses no file any more: for a record deleted.
@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.
The ids of the files record uses.
The records that use blob (a blob, or its id).