Ecto.DevLogger.PrintableParameter protocol (ecto_dev_logger v0.15.0)

View Source

A 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.DevLogger operates below Ecto.Type casting 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/1 and have to_expression/1 wrap it in single quotes.
  • If it must be rendered as a structured SQL expression (e.g. ROW(...), casts, or constructor functions), implement to_expression/1 directly and return nil from to_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
end

Arrays 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 using ARRAY[...] and ROW(...), with each element formatted via to_expression/1.

to_expression/1 is the main function and to_string_literal/1 is an optional helper for it.

Summary

Types

t()

All the types that implement this protocol.

Functions

Converts term to a valid SQL expression.

Converts term to a string literal.

Types

t()

@type t() :: term()

All the types that implement this protocol.

Functions

to_expression(term)

@spec to_expression(any()) :: String.t()

Converts term to a valid SQL expression.

to_string_literal(term)

@spec to_string_literal(any()) :: String.t() | nil

Converts term to a string literal.