Uni Ecto Plugin May 2026

We plan to evaluate Uni Ecto Plugin against three criteria:

| Criterion | Vanilla Ecto | Uni Plugin | Notes | |-----------|--------------|------------|-------| | Lines of code for 4 plugins (soft-delete, encrypt, audit, tenant) | ~240 LOC | ~60 LOC | Across 5 schemas | | Plugin conflict resolution | Manual | Ordered priority | User defines order | | Query composition (e.g., soft-delete + tenant) | Manual where | Automatic via plugin chain | modify_query composes | | Runtime overhead | 0 | <5% | Macro-expanded per plugin |


defmodule MyApp.Task do use Ecto.Schema use UniEctoPlugin.SoftDelete use UniEctoPlugin.Audit uni ecto plugin

schema "tasks" do field :title, :string timestamps() end end

lib/uni_ecto_plugin/tenancy.ex

defmodule UniEctoPlugin.Tenancy do
  defmacro __using__(opts) do
    tenant_field = Keyword.get(opts, :tenant_field, :tenant_id)
quote do
  import Ecto.Query
  @tenant_field unquote(tenant_field)
field @tenant_field, :integer
def scope_tenant(query, tenant_id) do
    from q in query, where: field(q, ^@tenant_field) == ^tenant_id
  end
def set_tenant(changeset, tenant_id) do
    Ecto.Changeset.put_change(changeset, @tenant_field, tenant_id)
  end
def before_insert(changeset, tenant_id) do
    set_tenant(changeset, tenant_id)
  end
end

end end

Usage:

defmodule MyApp.Blog.Comment do
  use Ecto.Schema
  use UniEctoPlugin.Tenancy, tenant_field: :account_id

schema "comments" do field :content, :string timestamps() end end We plan to evaluate Uni Ecto Plugin against