Skip to content

Money: Rename cents to minor units, ISO 4217 exponent-aware formatting - #89

Merged
sklinkert merged 3 commits into
mainfrom
sklinkert/money-minor-units
Jul 20, 2026
Merged

Money: Rename cents to minor units, ISO 4217 exponent-aware formatting#89
sklinkert merged 3 commits into
mainfrom
sklinkert/money-minor-units

Conversation

@sklinkert

Copy link
Copy Markdown
Owner

What & why

"Cents" is only the correct word for currencies with two decimal places. ISO 4217 defines a minor-unit exponent per currency: JPY, KRW, CLP and ISK have 0 (there is no sub-yen), BHD, JOD, KWD, OMR and TND have 3. A field named cents invites whoever adds JPY to the whitelist to divide by 100 and turn ¥5000 into ¥50.

This came directly out of reader feedback on the Money article. Changes:

  • Money.centsMoney.minorUnits, accessor Cents()MinorUnits(). No deprecated alias: clean break, all callers updated.
  • The currency whitelist now carries each currency's ISO 4217 exponent, with the non-obvious exponents documented next to it. Adding a currency forces looking up the right exponent.
  • String() formats from the exponent table instead of a hardcoded 100. New test pins JPY-style (exponent 0) and BHD-style (exponent 3) formatting.
  • Wire format: price_centsprice_minor_units (JSON, DTOs, OpenAPI spec). Breaking API change, intentional — the template has no API consumers to migrate.
  • Migration 000004 renames the DB column price_centsprice_minor_units; sqlc regenerated.
  • Tutorial chapter 3, READMEs (EN + zh-CN) and code excerpts updated to match.

How to test

make test    # full suite incl. testcontainers — passes
make lint    # 0 issues
mkdocs build --strict   # docs still build clean

The new TestMoney_String_ExponentAware covers the exponent-0 and exponent-3 formatting paths.

Checklist

  • make test passes (needs Docker)
  • make lint passes
  • Schema changes include up + down migrations and regenerated sqlc code
  • New behavior is covered by tests

ISO 4217 minor-unit exponents are not always 2 (JPY has 0, BHD has 3).
The cents naming invites a divide-by-100 bug the day a non-exponent-2
currency lands in the whitelist. Field, accessor, JSON, wire format, DB
column and docs now say minor units, and formatting derives from a
per-currency exponent table.
Review follow-ups: migration 000004 now rewrites PriceCents to
PriceMinorUnits in unpublished product.created payloads so consumers
never read a silent zero price, and Money.UnmarshalJSON fails loudly on
the old cents field instead of decoding it as zero.
The migration rewrites all stored payloads, so no old-format JSON can
exist. Code stays free of legacy awareness.
@sklinkert
sklinkert merged commit 1028139 into main Jul 20, 2026
2 checks passed
@sklinkert
sklinkert deleted the sklinkert/money-minor-units branch July 20, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant