Ecto.DevLogger.PrintableParameter protocol (ecto_dev_logger v0.15.0)
View SourceA protocol for rendering values as valid, copy‑pastable SQL expressions.
Ecto.DevLogger calls this protocol for every bound parameter when it inlines values
into the logged SQL.
When should I implement this?
- When a value you pass as a query parameter is a struct or type that does not have a built‑in implementation.
- This is common with driver‑level custom/extension types (for example, structs from database
driver libraries) or domain‑specific structs that ultimately become such driver types.
Ecto.DevLoggeroperates belowEcto.Typecasting and only sees the post‑cast values.
Without an implementation, the logger falls back to inspect/1, which may not be
valid SQL and therefore not directly runnable.
How to implement
- If your value can be represented as a single string literal that your database accepts,
implement
to_string_literal/1and haveto_expression/1wrap it in single quotes. - If it must be rendered as a structured SQL expression (e.g.
ROW(...), casts, or constructor functions), implementto_expression/1directly and returnnilfromto_string_literal/1.
Example: PostgreSQL composite type represented by a struct
defmodule MyApp.Money do
defstruct [:currency, :amount]
end
defimpl Ecto.DevLogger.PrintableParameter, for: MyApp.Money do
def to_expression(%MyApp.Money{} = money) do
string = to_string_literal(money)
"'#{String.replace(string, "'", "''")}'"
end
def to_string_literal(%MyApp.Money{currency: cur, amount: amt}) do
"(#{cur},#{amt})"
end
endArrays and tuples
- When all elements implement
to_string_literal/1, lists and tuples are formatted as PostgreSQL array and composite string literals ('{...}'and'(...)'). Otherwise, they are rendered usingARRAY[...]andROW(...), with each element formatted viato_expression/1.
to_expression/1 is the main function and to_string_literal/1 is an optional helper for it.
Summary
Types
@type t() :: term()
All the types that implement this protocol.