Support for money type in Postgres

Reading is possible as `i64`, presenting the number of cents with the
default setting. The fractional precision depends on the `lc_monetary`
setting. By default the setting gives a fractional precision of 2.

Writing works with `i32`, `i64` or a numeric type such as `BigDecimal`.
When using an integer to write, it is not possible to represent cents.
Writing `123` to a money field stores a value of 12300.

When writing with a numeric type, cents can be represented. Reading
should still be done to an integer and if needed, converted to a numeric
type in the application to get the correct fractional precision.
This commit is contained in:
Julius de Bruijn 2020-07-02 17:16:07 +02:00 committed by Ryan Leckey
parent 65222a62aa
commit 0c01ca966c
2 changed files with 24 additions and 0 deletions

View file

@ -113,6 +113,8 @@ pub enum PgType {
Int8RangeArray,
Jsonpath,
JsonpathArray,
Money,
MoneyArray,
// A realized user-defined type. When a connection sees a DeclareXX variant it resolves
// into this one before passing it along to `accepts` or inside of `Value` objects.
@ -254,6 +256,8 @@ impl PgType {
719 => PgType::CircleArray,
774 => PgType::Macaddr8,
775 => PgType::Macaddr8Array,
790 => PgType::Money,
791 => PgType::MoneyArray,
829 => PgType::Macaddr,
869 => PgType::Inet,
1000 => PgType::BoolArray,
@ -359,6 +363,8 @@ impl PgType {
PgType::CircleArray => 719,
PgType::Macaddr8 => 774,
PgType::Macaddr8Array => 775,
PgType::Money => 790,
PgType::MoneyArray => 791,
PgType::Macaddr => 829,
PgType::Inet => 869,
PgType::BoolArray => 1000,
@ -521,6 +527,8 @@ impl PgType {
PgType::Int8RangeArray => "INT8RANGE[]",
PgType::Jsonpath => "JSONPATH",
PgType::JsonpathArray => "JSONPATH[]",
PgType::Money => "MONEY",
PgType::MoneyArray => "MONEY[]",
PgType::Custom(ty) => &*ty.name,
PgType::DeclareWithOid(_) => "?",
PgType::DeclareWithName(name) => name,
@ -618,6 +626,8 @@ impl PgType {
PgType::Int8RangeArray => "_int8range",
PgType::Jsonpath => "jsonpath",
PgType::JsonpathArray => "_jsonpath",
PgType::Money => "money",
PgType::MoneyArray => "_money",
PgType::Custom(ty) => &*ty.name,
PgType::DeclareWithOid(_) => "?",
PgType::DeclareWithName(name) => name,
@ -715,6 +725,8 @@ impl PgType {
PgType::Int8RangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::Int8Range)),
PgType::Jsonpath => &PgTypeKind::Simple,
PgType::JsonpathArray => &PgTypeKind::Array(PgTypeInfo(PgType::Jsonpath)),
PgType::Money => &PgTypeKind::Simple,
PgType::MoneyArray => &PgTypeKind::Array(PgTypeInfo(PgType::Money)),
PgType::Custom(ty) => &ty.kind,
PgType::DeclareWithOid(_) | PgType::DeclareWithName(_) => {
@ -845,6 +857,10 @@ impl PgTypeInfo {
pub(crate) const NUMERIC: Self = Self(PgType::Numeric);
pub(crate) const NUMERIC_ARRAY: Self = Self(PgType::NumericArray);
// user-specified precision, exact
pub(crate) const MONEY: Self = Self(PgType::Money);
pub(crate) const MONEY_ARRAY: Self = Self(PgType::MoneyArray);
//
// date/time types
// https://www.postgresql.org/docs/current/datatype-datetime.html

View file

@ -148,12 +148,20 @@ impl Type<Postgres> for i64 {
fn type_info() -> PgTypeInfo {
PgTypeInfo::INT8
}
fn compatible(ty: &PgTypeInfo) -> bool {
*ty == PgTypeInfo::INT8 || *ty == PgTypeInfo::MONEY
}
}
impl Type<Postgres> for [i64] {
fn type_info() -> PgTypeInfo {
PgTypeInfo::INT8_ARRAY
}
fn compatible(ty: &PgTypeInfo) -> bool {
*ty == PgTypeInfo::INT8_ARRAY || *ty == PgTypeInfo::MONEY_ARRAY
}
}
impl Type<Postgres> for Vec<i64> {