Rewrite Postgres array type handling (#1385)

… to reduce boilerplate and allow custom types.
This commit is contained in:
Jonas Platte 2021-11-23 02:17:00 +01:00 committed by GitHub
parent 5aef7d7801
commit 12d9f54c7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 208 additions and 413 deletions

View file

@ -37,6 +37,7 @@ pub use row::PgRow;
pub use statement::PgStatement;
pub use transaction::PgTransactionManager;
pub use type_info::{PgTypeInfo, PgTypeKind};
pub use types::PgHasArrayType;
pub use value::{PgValue, PgValueFormat, PgValueRef};
/// An alias for [`Pool`][crate::pool::Pool], specialized for Postgres.

View file

@ -7,29 +7,49 @@ use crate::postgres::type_info::PgType;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::types::Type;
impl<T> Type<Postgres> for [Option<T>]
where
[T]: Type<Postgres>,
{
fn type_info() -> PgTypeInfo {
<[T] as Type<Postgres>>::type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<[T] as Type<Postgres>>::compatible(ty)
pub trait PgHasArrayType {
fn array_type_info() -> PgTypeInfo;
fn array_compatible(ty: &PgTypeInfo) -> bool {
*ty == Self::array_type_info()
}
}
impl<T> Type<Postgres> for Vec<Option<T>>
impl<T> PgHasArrayType for Option<T>
where
Vec<T>: Type<Postgres>,
T: PgHasArrayType,
{
fn array_type_info() -> PgTypeInfo {
T::array_type_info()
}
fn array_compatible(ty: &PgTypeInfo) -> bool {
T::array_compatible(ty)
}
}
impl<T> Type<Postgres> for [T]
where
T: PgHasArrayType,
{
fn type_info() -> PgTypeInfo {
<Vec<T> as Type<Postgres>>::type_info()
T::array_type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<Vec<T> as Type<Postgres>>::compatible(ty)
T::array_compatible(ty)
}
}
impl<T> Type<Postgres> for Vec<T>
where
T: PgHasArrayType,
{
fn type_info() -> PgTypeInfo {
T::array_type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
T::array_compatible(ty)
}
}

View file

@ -8,7 +8,9 @@ use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::types::numeric::{PgNumeric, PgNumericSign};
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
impl Type<Postgres> for BigDecimal {
@ -17,18 +19,12 @@ impl Type<Postgres> for BigDecimal {
}
}
impl Type<Postgres> for [BigDecimal] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for BigDecimal {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::NUMERIC_ARRAY
}
}
impl Type<Postgres> for Vec<BigDecimal> {
fn type_info() -> PgTypeInfo {
<[BigDecimal] as Type<Postgres>>::type_info()
}
}
impl TryFrom<PgNumeric> for BigDecimal {
type Error = BoxDynError;

View file

@ -2,7 +2,7 @@ use crate::{
decode::Decode,
encode::{Encode, IsNull},
error::BoxDynError,
postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres},
postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres},
types::Type,
};
use bit_vec::BitVec;
@ -19,26 +19,16 @@ impl Type<Postgres> for BitVec {
}
}
impl Type<Postgres> for [BitVec] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for BitVec {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::VARBIT_ARRAY
}
fn compatible(ty: &PgTypeInfo) -> bool {
fn array_compatible(ty: &PgTypeInfo) -> bool {
*ty == PgTypeInfo::BIT_ARRAY || *ty == PgTypeInfo::VARBIT_ARRAY
}
}
impl Type<Postgres> for Vec<BitVec> {
fn type_info() -> PgTypeInfo {
<[BitVec] as Type<Postgres>>::type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<[BitVec] as Type<Postgres>>::compatible(ty)
}
}
impl Encode<'_, Postgres> for BitVec {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend(&(self.len() as i32).to_be_bytes());

View file

@ -1,7 +1,9 @@
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
impl Type<Postgres> for bool {
@ -10,18 +12,12 @@ impl Type<Postgres> for bool {
}
}
impl Type<Postgres> for [bool] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for bool {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::BOOL_ARRAY
}
}
impl Type<Postgres> for Vec<bool> {
fn type_info() -> PgTypeInfo {
<[bool] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for bool {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.push(*self as u8);

View file

@ -1,41 +1,25 @@
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
impl Type<Postgres> for [u8] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for u8 {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::BYTEA
}
}
impl Type<Postgres> for Vec<u8> {
fn type_info() -> PgTypeInfo {
<[u8] as Type<Postgres>>::type_info()
}
}
impl Type<Postgres> for [&'_ [u8]] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for &'_ [u8] {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::BYTEA_ARRAY
}
}
impl Type<Postgres> for [Vec<u8>] {
fn type_info() -> PgTypeInfo {
<[&[u8]] as Type<Postgres>>::type_info()
}
}
impl Type<Postgres> for Vec<&'_ [u8]> {
fn type_info() -> PgTypeInfo {
<[&[u8]] as Type<Postgres>>::type_info()
}
}
impl Type<Postgres> for Vec<Vec<u8>> {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for Vec<u8> {
fn array_type_info() -> PgTypeInfo {
<[&[u8]] as Type<Postgres>>::type_info()
}
}

View file

@ -1,7 +1,9 @@
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
use chrono::{Duration, NaiveDate};
use std::mem;
@ -12,18 +14,12 @@ impl Type<Postgres> for NaiveDate {
}
}
impl Type<Postgres> for [NaiveDate] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for NaiveDate {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::DATE_ARRAY
}
}
impl Type<Postgres> for Vec<NaiveDate> {
fn type_info() -> PgTypeInfo {
<[NaiveDate] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for NaiveDate {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
// DATE is encoded as the days since epoch

View file

@ -1,7 +1,9 @@
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
use chrono::{
DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime, Offset, TimeZone, Utc,
@ -20,30 +22,18 @@ impl<Tz: TimeZone> Type<Postgres> for DateTime<Tz> {
}
}
impl Type<Postgres> for [NaiveDateTime] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for NaiveDateTime {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TIMESTAMP_ARRAY
}
}
impl<Tz: TimeZone> Type<Postgres> for [DateTime<Tz>] {
fn type_info() -> PgTypeInfo {
impl<Tz: TimeZone> PgHasArrayType for DateTime<Tz> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TIMESTAMPTZ_ARRAY
}
}
impl Type<Postgres> for Vec<NaiveDateTime> {
fn type_info() -> PgTypeInfo {
<[NaiveDateTime] as Type<Postgres>>::type_info()
}
}
impl<Tz: TimeZone> Type<Postgres> for Vec<DateTime<Tz>> {
fn type_info() -> PgTypeInfo {
<[DateTime<Tz>] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for NaiveDateTime {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
// FIXME: We should *really* be returning an error, Encode needs to be fallible

View file

@ -1,7 +1,9 @@
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
use chrono::{Duration, NaiveTime};
use std::mem;
@ -12,18 +14,12 @@ impl Type<Postgres> for NaiveTime {
}
}
impl Type<Postgres> for [NaiveTime] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for NaiveTime {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TIME_ARRAY
}
}
impl Type<Postgres> for Vec<NaiveTime> {
fn type_info() -> PgTypeInfo {
<[NaiveTime] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for NaiveTime {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
// TIME is encoded as the microseconds since midnight

View file

@ -9,7 +9,9 @@ use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::types::numeric::{PgNumeric, PgNumericSign};
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
impl Type<Postgres> for Decimal {
@ -18,18 +20,12 @@ impl Type<Postgres> for Decimal {
}
}
impl Type<Postgres> for [Decimal] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for Decimal {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::NUMERIC_ARRAY
}
}
impl Type<Postgres> for Vec<Decimal> {
fn type_info() -> PgTypeInfo {
<[Decimal] as Type<Postgres>>::type_info()
}
}
impl TryFrom<PgNumeric> for Decimal {
type Error = BoxDynError;

View file

@ -3,7 +3,9 @@ use byteorder::{BigEndian, ByteOrder};
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
impl Type<Postgres> for f32 {
@ -12,18 +14,12 @@ impl Type<Postgres> for f32 {
}
}
impl Type<Postgres> for [f32] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for f32 {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::FLOAT4_ARRAY
}
}
impl Type<Postgres> for Vec<f32> {
fn type_info() -> PgTypeInfo {
<[f32] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for f32 {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend(&self.to_be_bytes());
@ -47,18 +43,12 @@ impl Type<Postgres> for f64 {
}
}
impl Type<Postgres> for [f64] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for f64 {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::FLOAT8_ARRAY
}
}
impl Type<Postgres> for Vec<f64> {
fn type_info() -> PgTypeInfo {
<[f64] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for f64 {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend(&self.to_be_bytes());

View file

@ -3,7 +3,9 @@ use byteorder::{BigEndian, ByteOrder};
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
impl Type<Postgres> for i8 {
@ -12,18 +14,12 @@ impl Type<Postgres> for i8 {
}
}
impl Type<Postgres> for [i8] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for i8 {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::CHAR_ARRAY
}
}
impl Type<Postgres> for Vec<i8> {
fn type_info() -> PgTypeInfo {
<[i8] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for i8 {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend(&self.to_be_bytes());
@ -45,18 +41,12 @@ impl Type<Postgres> for i16 {
}
}
impl Type<Postgres> for [i16] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for i16 {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::INT2_ARRAY
}
}
impl Type<Postgres> for Vec<i16> {
fn type_info() -> PgTypeInfo {
<[i16] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for i16 {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend(&self.to_be_bytes());
@ -80,18 +70,12 @@ impl Type<Postgres> for u32 {
}
}
impl Type<Postgres> for [u32] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for u32 {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::OID_ARRAY
}
}
impl Type<Postgres> for Vec<u32> {
fn type_info() -> PgTypeInfo {
<[u32] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for u32 {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend(&self.to_be_bytes());
@ -115,18 +99,12 @@ impl Type<Postgres> for i32 {
}
}
impl Type<Postgres> for [i32] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for i32 {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::INT4_ARRAY
}
}
impl Type<Postgres> for Vec<i32> {
fn type_info() -> PgTypeInfo {
<[i32] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for i32 {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend(&self.to_be_bytes());
@ -150,18 +128,12 @@ impl Type<Postgres> for i64 {
}
}
impl Type<Postgres> for [i64] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for i64 {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::INT8_ARRAY
}
}
impl Type<Postgres> for Vec<i64> {
fn type_info() -> PgTypeInfo {
<[i64] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for i64 {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend(&self.to_be_bytes());

View file

@ -6,7 +6,9 @@ use byteorder::{NetworkEndian, ReadBytesExt};
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
// `PgInterval` is available for direct access to the INTERVAL type
@ -24,8 +26,8 @@ impl Type<Postgres> for PgInterval {
}
}
impl Type<Postgres> for [PgInterval] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgInterval {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::INTERVAL_ARRAY
}
}
@ -77,8 +79,8 @@ impl Type<Postgres> for std::time::Duration {
}
}
impl Type<Postgres> for [std::time::Duration] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for std::time::Duration {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::INTERVAL_ARRAY
}
}
@ -123,8 +125,8 @@ impl Type<Postgres> for chrono::Duration {
}
#[cfg(feature = "chrono")]
impl Type<Postgres> for [chrono::Duration] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for chrono::Duration {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::INTERVAL_ARRAY
}
}
@ -185,8 +187,8 @@ impl Type<Postgres> for time::Duration {
}
#[cfg(feature = "time")]
impl Type<Postgres> for [time::Duration] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for time::Duration {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::INTERVAL_ARRAY
}
}

View file

@ -5,7 +5,9 @@ use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
// https://github.com/rust-lang/rust/search?q=AF_INET&unscoped_q=AF_INET
@ -34,26 +36,16 @@ impl Type<Postgres> for IpNetwork {
}
}
impl Type<Postgres> for [IpNetwork] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for IpNetwork {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::INET_ARRAY
}
fn compatible(ty: &PgTypeInfo) -> bool {
fn array_compatible(ty: &PgTypeInfo) -> bool {
*ty == PgTypeInfo::CIDR_ARRAY || *ty == PgTypeInfo::INET_ARRAY
}
}
impl Type<Postgres> for Vec<IpNetwork> {
fn type_info() -> PgTypeInfo {
<[IpNetwork] as Type<Postgres>>::type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<[IpNetwork] as Type<Postgres>>::compatible(ty)
}
}
impl Encode<'_, Postgres> for IpNetwork {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
// https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/backend/utils/adt/network.c#L293

View file

@ -2,7 +2,9 @@ use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::types::array_compatible;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::{Json, Type};
use serde::{Deserialize, Serialize};
@ -22,26 +24,16 @@ impl<T> Type<Postgres> for Json<T> {
}
}
impl<T> Type<Postgres> for [Json<T>] {
fn type_info() -> PgTypeInfo {
impl<T> PgHasArrayType for Json<T> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::JSONB_ARRAY
}
fn compatible(ty: &PgTypeInfo) -> bool {
fn array_compatible(ty: &PgTypeInfo) -> bool {
array_compatible::<Json<T>>(ty)
}
}
impl<T> Type<Postgres> for Vec<Json<T>> {
fn type_info() -> PgTypeInfo {
<[Json<T>] as Type<Postgres>>::type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<[Json<T>] as Type<Postgres>>::compatible(ty)
}
}
impl<'q, T> Encode<'q, Postgres> for Json<T>
where
T: Serialize,

View file

@ -5,7 +5,9 @@ use std::convert::TryInto;
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
impl Type<Postgres> for MacAddress {
@ -18,22 +20,12 @@ impl Type<Postgres> for MacAddress {
}
}
impl Type<Postgres> for [MacAddress] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for MacAddress {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::MACADDR_ARRAY
}
}
impl Type<Postgres> for Vec<MacAddress> {
fn type_info() -> PgTypeInfo {
<[MacAddress] as Type<Postgres>>::type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<[MacAddress] as Type<Postgres>>::compatible(ty)
}
}
impl Encode<'_, Postgres> for MacAddress {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend_from_slice(&self.bytes()); // write just the address

View file

@ -208,6 +208,7 @@ mod mac_address;
#[cfg(feature = "bit-vec")]
mod bit_vec;
pub use array::PgHasArrayType;
pub use interval::PgInterval;
pub use money::PgMoney;
pub use range::PgRange;

View file

@ -2,7 +2,7 @@ use crate::{
decode::Decode,
encode::{Encode, IsNull},
error::BoxDynError,
postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres},
postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres},
types::Type,
};
use byteorder::{BigEndian, ByteOrder};
@ -151,18 +151,12 @@ impl Type<Postgres> for PgMoney {
}
}
impl Type<Postgres> for [PgMoney] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgMoney {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::MONEY_ARRAY
}
}
impl Type<Postgres> for Vec<PgMoney> {
fn type_info() -> PgTypeInfo {
<[PgMoney] as Type<Postgres>>::type_info()
}
}
impl<T> From<T> for PgMoney
where
T: Into<i64>,

View file

@ -8,7 +8,9 @@ use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::type_info::PgTypeKind;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
// https://github.com/postgres/postgres/blob/2f48ede080f42b97b594fb14102c82ca1001b80c/src/include/utils/rangetypes.h#L35-L44
@ -219,138 +221,70 @@ impl Type<Postgres> for PgRange<time::OffsetDateTime> {
}
}
impl Type<Postgres> for [PgRange<i32>] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgRange<i32> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::INT4_RANGE_ARRAY
}
}
impl Type<Postgres> for [PgRange<i64>] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgRange<i64> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::INT8_RANGE_ARRAY
}
}
#[cfg(feature = "bigdecimal")]
impl Type<Postgres> for [PgRange<bigdecimal::BigDecimal>] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgRange<bigdecimal::BigDecimal> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::NUM_RANGE_ARRAY
}
}
#[cfg(feature = "decimal")]
impl Type<Postgres> for [PgRange<rust_decimal::Decimal>] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgRange<rust_decimal::Decimal> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::NUM_RANGE_ARRAY
}
}
#[cfg(feature = "chrono")]
impl Type<Postgres> for [PgRange<chrono::NaiveDate>] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgRange<chrono::NaiveDate> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::DATE_RANGE_ARRAY
}
}
#[cfg(feature = "chrono")]
impl Type<Postgres> for [PgRange<chrono::NaiveDateTime>] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgRange<chrono::NaiveDateTime> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TS_RANGE_ARRAY
}
}
#[cfg(feature = "chrono")]
impl<Tz: chrono::TimeZone> Type<Postgres> for [PgRange<chrono::DateTime<Tz>>] {
fn type_info() -> PgTypeInfo {
impl<Tz: chrono::TimeZone> PgHasArrayType for PgRange<chrono::DateTime<Tz>> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TSTZ_RANGE_ARRAY
}
}
#[cfg(feature = "time")]
impl Type<Postgres> for [PgRange<time::Date>] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgRange<time::Date> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::DATE_RANGE_ARRAY
}
}
#[cfg(feature = "time")]
impl Type<Postgres> for [PgRange<time::PrimitiveDateTime>] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgRange<time::PrimitiveDateTime> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TS_RANGE_ARRAY
}
}
#[cfg(feature = "time")]
impl Type<Postgres> for [PgRange<time::OffsetDateTime>] {
fn type_info() -> PgTypeInfo {
PgTypeInfo::TSTZ_RANGE_ARRAY
}
}
impl Type<Postgres> for Vec<PgRange<i32>> {
fn type_info() -> PgTypeInfo {
PgTypeInfo::INT4_RANGE_ARRAY
}
}
impl Type<Postgres> for Vec<PgRange<i64>> {
fn type_info() -> PgTypeInfo {
PgTypeInfo::INT8_RANGE_ARRAY
}
}
#[cfg(feature = "bigdecimal")]
impl Type<Postgres> for Vec<PgRange<bigdecimal::BigDecimal>> {
fn type_info() -> PgTypeInfo {
PgTypeInfo::NUM_RANGE_ARRAY
}
}
#[cfg(feature = "decimal")]
impl Type<Postgres> for Vec<PgRange<rust_decimal::Decimal>> {
fn type_info() -> PgTypeInfo {
PgTypeInfo::NUM_RANGE_ARRAY
}
}
#[cfg(feature = "chrono")]
impl Type<Postgres> for Vec<PgRange<chrono::NaiveDate>> {
fn type_info() -> PgTypeInfo {
PgTypeInfo::DATE_RANGE_ARRAY
}
}
#[cfg(feature = "chrono")]
impl Type<Postgres> for Vec<PgRange<chrono::NaiveDateTime>> {
fn type_info() -> PgTypeInfo {
PgTypeInfo::TS_RANGE_ARRAY
}
}
#[cfg(feature = "chrono")]
impl<Tz: chrono::TimeZone> Type<Postgres> for Vec<PgRange<chrono::DateTime<Tz>>> {
fn type_info() -> PgTypeInfo {
PgTypeInfo::TSTZ_RANGE_ARRAY
}
}
#[cfg(feature = "time")]
impl Type<Postgres> for Vec<PgRange<time::Date>> {
fn type_info() -> PgTypeInfo {
PgTypeInfo::DATE_RANGE_ARRAY
}
}
#[cfg(feature = "time")]
impl Type<Postgres> for Vec<PgRange<time::PrimitiveDateTime>> {
fn type_info() -> PgTypeInfo {
PgTypeInfo::TS_RANGE_ARRAY
}
}
#[cfg(feature = "time")]
impl Type<Postgres> for Vec<PgRange<time::OffsetDateTime>> {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PgRange<time::OffsetDateTime> {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TSTZ_RANGE_ARRAY
}
}

View file

@ -2,7 +2,7 @@ use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::types::array_compatible;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueRef, Postgres};
use crate::postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres};
use crate::types::Type;
use std::borrow::Cow;
@ -33,23 +33,43 @@ impl Type<Postgres> for Cow<'_, str> {
}
}
impl Type<Postgres> for [&'_ str] {
impl Type<Postgres> for String {
fn type_info() -> PgTypeInfo {
PgTypeInfo::TEXT_ARRAY
<&str as Type<Postgres>>::type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<&str as Type<Postgres>>::compatible(ty)
}
}
impl PgHasArrayType for &'_ str {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TEXT_ARRAY
}
fn array_compatible(ty: &PgTypeInfo) -> bool {
array_compatible::<&str>(ty)
}
}
impl Type<Postgres> for Vec<&'_ str> {
fn type_info() -> PgTypeInfo {
<[&str] as Type<Postgres>>::type_info()
impl PgHasArrayType for Cow<'_, str> {
fn array_type_info() -> PgTypeInfo {
<&str as PgHasArrayType>::array_type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<[&str] as Type<Postgres>>::compatible(ty)
fn array_compatible(ty: &PgTypeInfo) -> bool {
<&str as PgHasArrayType>::array_compatible(ty)
}
}
impl PgHasArrayType for String {
fn array_type_info() -> PgTypeInfo {
<&str as PgHasArrayType>::array_type_info()
}
fn array_compatible(ty: &PgTypeInfo) -> bool {
<&str as PgHasArrayType>::array_compatible(ty)
}
}
@ -88,36 +108,6 @@ impl<'r> Decode<'r, Postgres> for Cow<'r, str> {
}
}
impl Type<Postgres> for String {
fn type_info() -> PgTypeInfo {
<&str as Type<Postgres>>::type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<&str as Type<Postgres>>::compatible(ty)
}
}
impl Type<Postgres> for [String] {
fn type_info() -> PgTypeInfo {
<[&str] as Type<Postgres>>::type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<[&str] as Type<Postgres>>::compatible(ty)
}
}
impl Type<Postgres> for Vec<String> {
fn type_info() -> PgTypeInfo {
<[String] as Type<Postgres>>::type_info()
}
fn compatible(ty: &PgTypeInfo) -> bool {
<[String] as Type<Postgres>>::compatible(ty)
}
}
impl Decode<'_, Postgres> for String {
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
Ok(value.as_str()?.to_owned())

View file

@ -2,7 +2,9 @@ use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::types::time::PG_EPOCH;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
use std::mem;
use time::{Date, Duration};
@ -13,18 +15,12 @@ impl Type<Postgres> for Date {
}
}
impl Type<Postgres> for [Date] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for Date {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::DATE_ARRAY
}
}
impl Type<Postgres> for Vec<Date> {
fn type_info() -> PgTypeInfo {
<[Date] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for Date {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
// DATE is encoded as the days since epoch

View file

@ -2,7 +2,9 @@ use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::types::time::PG_EPOCH;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
use std::borrow::Cow;
use std::mem;
@ -20,30 +22,18 @@ impl Type<Postgres> for OffsetDateTime {
}
}
impl Type<Postgres> for [PrimitiveDateTime] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for PrimitiveDateTime {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TIMESTAMP_ARRAY
}
}
impl Type<Postgres> for [OffsetDateTime] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for OffsetDateTime {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TIMESTAMPTZ_ARRAY
}
}
impl Type<Postgres> for Vec<PrimitiveDateTime> {
fn type_info() -> PgTypeInfo {
<[PrimitiveDateTime] as Type<Postgres>>::type_info()
}
}
impl Type<Postgres> for Vec<OffsetDateTime> {
fn type_info() -> PgTypeInfo {
<[OffsetDateTime] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for PrimitiveDateTime {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
// TIMESTAMP is encoded as the microseconds since the epoch

View file

@ -1,7 +1,9 @@
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
use std::borrow::Cow;
use std::mem;
@ -13,18 +15,12 @@ impl Type<Postgres> for Time {
}
}
impl Type<Postgres> for [Time] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for Time {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::TIME_ARRAY
}
}
impl Type<Postgres> for Vec<Time> {
fn type_info() -> PgTypeInfo {
<[Time] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for Time {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
// TIME is encoded as the microseconds since midnight

View file

@ -1,7 +1,7 @@
use crate::decode::Decode;
use crate::error::BoxDynError;
use crate::postgres::types::PgRecordDecoder;
use crate::postgres::{PgTypeInfo, PgValueRef, Postgres};
use crate::postgres::{PgHasArrayType, PgTypeInfo, PgValueRef, Postgres};
use crate::types::Type;
macro_rules! impl_type_for_tuple {
@ -13,20 +13,13 @@ macro_rules! impl_type_for_tuple {
}
}
impl<$($T,)*> Type<Postgres> for [($($T,)*)] {
impl<$($T,)*> PgHasArrayType for ($($T,)*) {
#[inline]
fn type_info() -> PgTypeInfo {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::RECORD_ARRAY
}
}
impl<$($T,)*> Type<Postgres> for Vec<($($T,)*)> {
#[inline]
fn type_info() -> PgTypeInfo {
<[($($T,)*)] as Type<Postgres>>::type_info()
}
}
impl<'r, $($T,)*> Decode<'r, Postgres> for ($($T,)*)
where
$($T: 'r,)*

View file

@ -3,7 +3,9 @@ use uuid::Uuid;
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
use crate::postgres::{
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
};
use crate::types::Type;
impl Type<Postgres> for Uuid {
@ -12,18 +14,12 @@ impl Type<Postgres> for Uuid {
}
}
impl Type<Postgres> for [Uuid] {
fn type_info() -> PgTypeInfo {
impl PgHasArrayType for Uuid {
fn array_type_info() -> PgTypeInfo {
PgTypeInfo::UUID_ARRAY
}
}
impl Type<Postgres> for Vec<Uuid> {
fn type_info() -> PgTypeInfo {
<[Uuid] as Type<Postgres>>::type_info()
}
}
impl Encode<'_, Postgres> for Uuid {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend_from_slice(self.as_bytes());