AuroraMeter. Credits. Money
(Aurora Meter v1.0.0)
View Source
Conversions between the ledger's integer micro-dollars and the units the rest of the world uses.
AuroraMeter.Credits stores every amount as an integer number of
micro-dollars (1 µ$ = 1e-6 USD, so 1_000_000 is one dollar and 10_000 is
one cent). Integers keep the ledger exact under concurrency and let a price
of a few thousandths of a cent (a token, a request, a byte) be charged
without rounding. Convert at the edges:
iex> AuroraMeter.Credits.Money.from_cents(1_235)
12_350_000
iex> AuroraMeter.Credits.Money.to_cents(12_350_000)
1_235
iex> AuroraMeter.Credits.Money.from_decimal(Decimal.new("12.35"))
12_350_000
iex> AuroraMeter.Credits.Money.format(12_350_000)
"$12.35"
iex> AuroraMeter.Credits.Money.format_compact(1_234_000_000)
"$1.2k"
Summary
Functions
Returns amount when it is an integer the ledger can hold, and raises
ArgumentError naming the limit when it is not.
Formats micro-dollars as a dollar string with :precision decimals
(default 2), rounding half away from zero; negative amounts as "-$1.00".
Formats micro-dollars as a short label for a chart axis or a stat tile:
thousands, millions and billions collapse to one decimal ("$1.2k", "$3M"),
ordinary amounts render as dollars and cents ("$0.07"), and a sub-cent
amount keeps just enough precision to stay non-zero ("$0.000015") rather
than rounding away to "$0.00".
Converts cents to micro-dollars.
Converts a Decimal amount of dollars to micro-dollars, rounding half up at
the sixth decimal place.
The largest magnitude assert_range!/1 admits.
Converts micro-dollars to whole cents, rounding with :round (default, half
away from zero), :floor or :ceil.
Types
@type micro() :: integer()
An amount in micro-dollars.
Functions
Returns amount when it is an integer the ledger can hold, and raises
ArgumentError naming the limit when it is not.
The limit is 9000000000000000 micro-dollars either side of zero, which is nine
billion US dollars. AuroraMeter.Credits's grant/3, hold/4, debit/4,
reverse/4, settle/3 and set_low_balance_threshold/2 all call it before
any database work, so an amount out of range is an ArgumentError from the
function the host called rather than a DBConnection.EncodeError from the
driver two layers down.
It is deliberately not called by from_cents/1, to_cents/2 or
from_decimal/1: those are pure conversions, a host may legitimately convert
a figure it is not about to write, and changing them would change the meaning
of code that has nothing to do with the ledger.
Examples
iex> AuroraMeter.Credits.Money.assert_range!(20_000_000)
20_000_000
iex> AuroraMeter.Credits.Money.assert_range!(-20_000_000)
-20_000_000
iex> AuroraMeter.Credits.Money.assert_range!(9_000_000_000_000_001)
** (ArgumentError) amount 9000000000000001 is outside the range AuroraMeter.Credits can hold: at most 9000000000000000 micro-dollars (9,000,000,000 USD) either side of zero
iex> AuroraMeter.Credits.Money.assert_range!(1.5)
** (ArgumentError) amount must be an integer number of micro-dollars, got: 1.5
Formats micro-dollars as a dollar string with :precision decimals
(default 2), rounding half away from zero; negative amounts as "-$1.00".
Examples
iex> AuroraMeter.Credits.Money.format(12_350_000)
"$12.35"
iex> AuroraMeter.Credits.Money.format(-1_000_000)
"-$1.00"
iex> AuroraMeter.Credits.Money.format(15, precision: 6)
"$0.000015"
iex> AuroraMeter.Credits.Money.format(1_999_999, precision: 0)
"$2"
Formats micro-dollars as a short label for a chart axis or a stat tile:
thousands, millions and billions collapse to one decimal ("$1.2k", "$3M"),
ordinary amounts render as dollars and cents ("$0.07"), and a sub-cent
amount keeps just enough precision to stay non-zero ("$0.000015") rather
than rounding away to "$0.00".
Use format/2 wherever the exact amount matters; this is for the places where
space matters more than the last decimal.
Examples
iex> AuroraMeter.Credits.Money.format_compact(1_234_000_000)
"$1.2k"
iex> AuroraMeter.Credits.Money.format_compact(70_000)
"$0.07"
iex> AuroraMeter.Credits.Money.format_compact(0)
"$0"
iex> AuroraMeter.Credits.Money.format_compact(2_000_000_000)
"$2k"
iex> AuroraMeter.Credits.Money.format_compact(-4_500_000_000_000)
"-$4.5M"
iex> AuroraMeter.Credits.Money.format_compact(15)
"$0.000015"
Converts cents to micro-dollars.
Examples
iex> AuroraMeter.Credits.Money.from_cents(100)
1_000_000
iex> AuroraMeter.Credits.Money.from_cents(-50)
-500_000
Converts a Decimal amount of dollars to micro-dollars, rounding half up at
the sixth decimal place.
Examples
iex> AuroraMeter.Credits.Money.from_decimal(Decimal.new("0.000015"))
15
iex> AuroraMeter.Credits.Money.from_decimal(Decimal.new("-2.5"))
-2_500_000
@spec max_micro() :: pos_integer()
The largest magnitude assert_range!/1 admits.
Examples
iex> AuroraMeter.Credits.Money.max_micro()
9_000_000_000_000_000
Converts micro-dollars to whole cents, rounding with :round (default, half
away from zero), :floor or :ceil.
Examples
iex> AuroraMeter.Credits.Money.to_cents(1_234_999)
123
iex> AuroraMeter.Credits.Money.to_cents(1_235_000)
124
iex> AuroraMeter.Credits.Money.to_cents(1_230_001, rounding: :ceil)
124
iex> AuroraMeter.Credits.Money.to_cents(-1_235_000, rounding: :floor)
-124