Scalars
The.cstack parser recognises a fixed set of scalar names. Each maps
to a Rust type, a SQL column type, and (where relevant) a serde
representation.
Built-in scalars
Type modifiers
? (optional) and [] (list) apply on top of any scalar
where the underlying SQL type supports it.
Decimal
TheDecimal scalar exists specifically so banking code does not end
up using Float for money. Round-trip through NUMERIC is exact for
any value the chosen backend supports.
Backend selection
The workspace ships two backends, gated by feature flag:
Default:
decimal-rust-decimal.
Banks pick:
- rust_decimal for fixed 128-bit precision, faster arithmetic, and a smaller binary. 28–29 significant digits is enough for retail banking, FX rates, and consumer-facing pricing.
- bigdecimal for arbitrary precision when calculations involve cumulative compounding, very long-duration interest, or settlement workflows where the precision budget grows over time.
cratestack crate
threads the feature through the workspace so downstream code references
cratestack::Decimal regardless of backend.
Serialization
Decimal serializes as a JSON string, not a number. This is
deliberate:
f64 parser and
lose precision. Banks that consume CrateStack responses from other
languages have one well-defined parse path: read the string, parse with
that language’s exact-decimal library.
Use with validators
@range(min, max) on a Decimal field promotes the integer bounds to
Decimal at runtime. @range(min: 0, max: 1000000) on
amount Decimal accepts 123.45, rejects -0.01, and rejects
1000000.01.
See validators for the broader validator surface.
Choosing types for money
The recommended pattern:- amounts are always
Decimal, neverFloat - currency is always
String @iso4217, not an enum — currency lists churn @versionis required for any row that two callers can race on@@auditis required for any row a regulator can ask about