Uni Ecto Plugin

Since “UNI” is ambiguous in open-source contexts (e.g., Uniswap’s UNI token, UNI Protocol for universal identity, or internal naming), I will assume UNI here refers to a unified schema or universal identifier pattern — commonly used in multi-tenant, cross-service, or federated data systems. The write-up treats the plugin as a conceptual tool for integrating such a UNI scheme with Ecto.


Option B – Standalone library

mix new uni_ecto_plugin
cd uni_ecto_plugin

Add same deps + :decimal, "~> 2.0".

Part 5: Building Your First Pipeline

Let’s build a complete user registration pipeline that: uni ecto plugin

  1. Validates input parameters.
  2. Inserts a user.
  3. Assigns a default role.
  4. Sends a welcome email (simulated).
  5. Returns the user.

3.1 Plugin Behaviour

Each plugin implements:

defmodule Uni.Plugin do
  @callback prepare_changeset(changeset :: Ecto.Changeset.t(), opts :: keyword()) :: Ecto.Changeset.t()
  @callback before_action(action :: :insert | :update | :delete, struct :: struct(), opts :: keyword()) :: :ok, struct() | :error, term()
  @callback after_action(action :: atom(), result :: term(), opts :: keyword()) :: term()
  @callback modify_query(query :: Ecto.Query.t(), opts :: keyword()) :: Ecto.Query.t()
end

4. Integration with Ecto’s Features

| Ecto Feature | UNI Plugin Support | |--------------|--------------------| | Changeset validation | Custom validate_uni/3 to check resolvability or format | | Preloading | Works with belongs_to_uni like normal associations | | Streams | UNI fields are streamed as structs, no extra overhead | | Multi-tenancy | UNI origin can act as tenant ID; plugin can scope queries automatically | | Migrations | add :customer_uni, :string + optional generated columns via uni_add_components/2 | Since “UNI” is ambiguous in open-source contexts (e

Later, preload the customer record (fetched from Stripe API)

payment_with_customer = Repo.get(Payment, payment.id) |> Repo.preload(:customer) IO.inspect(payment_with_customer.customer.name) # "Jane Doe"

Option B: Mock the Entire Pipeline at the Step Level

Uni allows overriding any step’s implementation during testing: Option B – Standalone library mix new uni_ecto_plugin

test "handles email failure" do
  Uni.Test.stub(UserRegistration, :send_welcome, fn _ctx -> :error, :email_down end)

assert :error, :send_welcome, _, _ = UserRegistration.run(%email: "x@x.com") end

5. list/2 – Fetch Multiple Records

step = Ecto.list(MyApp.User)
# Or with a query
step = Ecto.list(from(u in User, where: u.active == true))