Two storage shapes for %Accrue.Money{} in Ecto schemas — both shipped
in Phase 1 per D-02 and RESEARCH Open Question 5.
1. Custom Ecto.Type — single-column jsonb form
For places where a money value is one of many properties inside a
jsonb blob (e.g., accrue_events.data), this module implements the
Ecto.Type callbacks and serializes as
%{"amount_minor" => integer, "currency" => string}.
field :snapshot, Accrue.Ecto.MoneyThis form is convenient but is NOT the canonical storage shape for
first-class money columns. Use money_field/1 for those.
2. money_field/1 macro — two-column canonical form (D-02)
The canonical form: one money value expands to TWO physical Ecto fields plus a virtual accessor.
defmodule MyApp.Billing.Subscription do
use Ecto.Schema
import Accrue.Ecto.Money, only: [money_field: 1]
schema "subscriptions" do
money_field :price
timestamps()
end
endThat expansion produces:
field :price_amount_minor, :integer
field :price_currency, :string
field :price, :any, virtual: trueOn load, a changeset/2 or post-load helper (Phase 2 wires this) sets
the virtual :price field via
Accrue.Money.new(row.price_amount_minor, String.to_existing_atom(row.price_currency))
so callers see a %Accrue.Money{} struct.
This two-column shape plays well with zero-decimal (JPY) and three-decimal (KWD) currencies, is indexable, and is analytics-friendly — see Pitfall #1 in 01-RESEARCH.md for why we reject the ex_money Postgres composite type as a canonical storage shape.
Summary
Functions
Callback implementation for Ecto.Type.embed_as/1.
Callback implementation for Ecto.Type.equal?/2.
Two-column macro — canonical storage shape per D-02.
Functions
Callback implementation for Ecto.Type.embed_as/1.
Callback implementation for Ecto.Type.equal?/2.
Two-column macro — canonical storage shape per D-02.