View Source EctoModel.SoftDelete (EctoModel v0.0.1)

Module responsible for allowing your schemas to opt into soft delete functionality.

Usage

There are two things that need to happen in order to make a schema soft deletable:

  1. You need to ensure your MyApp.Repo module is using the EctoMiddleware behaviour, and you add the EctoModel.SoftDelete middleware to the middleware/2 callback before the EctoMiddleware.Super middleware.

    This will enable EctoModel.SoftDelete to raise errors if users try to hard delete records when schemas have opted into soft deletes.

    In future, we may add support for automatically delegating hard delete operations to transparently behave transparently as soft deletes in an opt in basis.

    You can also optionally add the following code to your MyApp.Repo module to enable easy soft delete operations:

    def soft_delete!(resource, opts \ []) do
      EctoModel.SoftDelete.soft_delete!(resource, Keyword.put(opts, :repo, __MODULE__))
    end
    
    def soft_delete(resource, opts \ []) do
      EctoModel.SoftDelete.soft_delete(resource, Keyword.put(opts, :repo, __MODULE__))
    end
  2. You need to use EctoModel.SoftDelete in your schema, and configure the field and type options.

    The specified field and type must match what is defined on said schema, though there are compile time validations provided for you to ensure this remains in sync with your schema's natural evolution.

    Additionally, if your schema also opts into implementing the EctoModel.Queryable behaviour, we automatically provide a base_query/0 implementation to will apply the neccessary filters to automatically filter out soft deleted records from query results.

    If you need to specify a custom base_query/0 implementation, you can do so while still inheriting the default behaviour provided when using this module by calling super() in your custom implementation like so:

    @impl EctoModel.Queryable
    def base_query do
      from x in ^super(), where: x.show_by_default != false
    end

A full example of how to use EctoModel.SoftDelete is as follows:

defmodule MyApp.Repo do
  use Ecto.Repo, otp_app: :my_app
  use EctoMiddleware

  def middleware(_resource, _resolution) do
    [EctoModel.SoftDelete, EctoMiddleware.Super]
  end
end

defmodule MyApp.User do
  use Ecto.Schema
  use EctoModel.SoftDelete, field: :deleted_at, type: :utc_datetime

  schema "users" do
    field(:name, :string)
    field(:email, :string)
    field(:deleted_at, :utc_datetime)
  end
end

Summary

Functions

After compile hook responsible for validating that a schema is properly configured for soft deletes.

Persists the configuration for soft deletes on the schema, as well as providing a default impl. for EctoModel.Queryable.base_query/0.

Given a schema that has been configured to implement soft deletes, this function will apply the neccessary filters to the query to ensure that soft deleted records are not included in the result set.

Will soft delete a given resource, and persist the changes to the database, based on that resource's configured soft delete field and type.

See Ecto.Repo.soft_delete/2 for more information.

Types

@type soft_delete_type() :: :utc_datetime | :datetime | :boolean

Functions

Link to this function

__after_compile__(env, bytecode)

View Source

After compile hook responsible for validating that a schema is properly configured for soft deletes.

Link to this macro

__using__(opts)

View Source (macro)

Persists the configuration for soft deletes on the schema, as well as providing a default impl. for EctoModel.Queryable.base_query/0.

Link to this function

apply_filter!(schema, query)

View Source
@spec apply_filter!(schema :: module(), query :: Ecto.Query.t() | atom()) ::
  Ecto.Query.t()

Given a schema that has been configured to implement soft deletes, this function will apply the neccessary filters to the query to ensure that soft deleted records are not included in the result set.

Note that the strategy used for soft deletes is determined by the type option when use-ing EctoModel.SoftDelete, and we will apply the appropriate filter against the field option when use-ing EctoModel.SoftDelete.

For example, if a schema is configured to implement soft deletes like so:

defmodule MyApp.User do
  use Ecto.Schema
  use EctoModel.SoftDelete, field: :deleted_at, type: :utc_datetime

  schema "users" do
    field(:name, :string)
    field(:email, :string)
    field(:deleted_at, :utc_datetime)
  end
end

Then the apply_filter!/2 function will apply the following filter to the query:

from(x in query, where: is_nil(x.deleted_at))

However, if the schema is configured to implement soft deletes like so:

defmodule MyApp.User do
  use Ecto.Schema
  use EctoModel.SoftDelete, field: :deleted, type: :boolean

  schema "users" do
    field(:name, :string)
    field(:email, :string)
    field(:deleted, :boolean)
  end
end

Then the apply_filter!/2 function will apply the following filter to the query:

from(x in query, where: is_nil(x.deleted) or x.deleted == false)
Link to this function

soft_delete(resource, opts \\ [])

View Source
@spec soft_delete(resource :: struct(), opts :: Keyword.t()) ::
  {:ok, struct()} | {:error, term()}

Will soft delete a given resource, and persist the changes to the database, based on that resource's configured soft delete field and type.

Will raise if given an entity that does not opt into soft deletes.

Link to this function

soft_delete!(resource, opts \\ [])

View Source
@spec soft_delete!(resource :: struct(), opts :: Keyword.t()) :: struct()

See Ecto.Repo.soft_delete/2 for more information.