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
- Validates input parameters.
- Inserts a user.
- Assigns a default role.
- Sends a welcome email (simulated).
- 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))