Skip to content

Commit feabdf0

Browse files
committed
Rewrite Postgres array type handling
… to reduce boilerplate and allow custom types.
1 parent ed6fdbe commit feabdf0

25 files changed

+184
-389
lines changed

sqlx-core/src/postgres/array.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use crate::postgres::PgTypeInfo;
2+
3+
pub trait PgHasArrayType {
4+
fn array_type_info() -> PgTypeInfo;
5+
fn array_compatible(ty: &PgTypeInfo) -> bool {
6+
*ty == Self::array_type_info()
7+
}
8+
}
9+
10+
impl<T> PgHasArrayType for Option<T>
11+
where
12+
T: PgHasArrayType,
13+
{
14+
fn array_type_info() -> PgTypeInfo {
15+
T::array_type_info()
16+
}
17+
18+
fn array_compatible(ty: &PgTypeInfo) -> bool {
19+
T::array_compatible(ty)
20+
}
21+
}

sqlx-core/src/postgres/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! **PostgreSQL** database driver.
22
33
mod arguments;
4+
mod array;
45
mod column;
56
mod connection;
67
mod database;
@@ -21,6 +22,7 @@ mod value;
2122
mod migrate;
2223

2324
pub use arguments::{PgArgumentBuffer, PgArguments};
25+
pub use array::PgHasArrayType;
2426
pub use column::PgColumn;
2527
pub use connection::{PgConnection, PgConnectionInfo};
2628
pub use database::Postgres;

sqlx-core/src/postgres/types/array.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,34 @@ use crate::decode::Decode;
44
use crate::encode::{Encode, IsNull};
55
use crate::error::BoxDynError;
66
use crate::postgres::type_info::PgType;
7-
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
7+
use crate::postgres::{
8+
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
9+
};
810
use crate::types::Type;
911

10-
impl<T> Type<Postgres> for [Option<T>]
12+
impl<T> Type<Postgres> for [T]
1113
where
12-
[T]: Type<Postgres>,
14+
T: PgHasArrayType,
1315
{
1416
fn type_info() -> PgTypeInfo {
15-
<[T] as Type<Postgres>>::type_info()
17+
T::array_type_info()
1618
}
1719

1820
fn compatible(ty: &PgTypeInfo) -> bool {
19-
<[T] as Type<Postgres>>::compatible(ty)
21+
T::array_compatible(ty)
2022
}
2123
}
2224

23-
impl<T> Type<Postgres> for Vec<Option<T>>
25+
impl<T> Type<Postgres> for Vec<T>
2426
where
25-
Vec<T>: Type<Postgres>,
27+
T: PgHasArrayType,
2628
{
2729
fn type_info() -> PgTypeInfo {
28-
<Vec<T> as Type<Postgres>>::type_info()
30+
T::array_type_info()
2931
}
3032

3133
fn compatible(ty: &PgTypeInfo) -> bool {
32-
<Vec<T> as Type<Postgres>>::compatible(ty)
34+
T::array_compatible(ty)
3335
}
3436
}
3537

sqlx-core/src/postgres/types/bigdecimal.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ use crate::decode::Decode;
88
use crate::encode::{Encode, IsNull};
99
use crate::error::BoxDynError;
1010
use crate::postgres::types::numeric::{PgNumeric, PgNumericSign};
11-
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
11+
use crate::postgres::{
12+
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
13+
};
1214
use crate::types::Type;
1315

1416
impl Type<Postgres> for BigDecimal {
@@ -17,18 +19,12 @@ impl Type<Postgres> for BigDecimal {
1719
}
1820
}
1921

20-
impl Type<Postgres> for [BigDecimal] {
21-
fn type_info() -> PgTypeInfo {
22+
impl PgHasArrayType for BigDecimal {
23+
fn array_type_info() -> PgTypeInfo {
2224
PgTypeInfo::NUMERIC_ARRAY
2325
}
2426
}
2527

26-
impl Type<Postgres> for Vec<BigDecimal> {
27-
fn type_info() -> PgTypeInfo {
28-
<[BigDecimal] as Type<Postgres>>::type_info()
29-
}
30-
}
31-
3228
impl TryFrom<PgNumeric> for BigDecimal {
3329
type Error = BoxDynError;
3430

sqlx-core/src/postgres/types/bit_vec.rs

+4-14
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{
22
decode::Decode,
33
encode::{Encode, IsNull},
44
error::BoxDynError,
5-
postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres},
5+
postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres},
66
types::Type,
77
};
88
use bit_vec::BitVec;
@@ -19,26 +19,16 @@ impl Type<Postgres> for BitVec {
1919
}
2020
}
2121

22-
impl Type<Postgres> for [BitVec] {
23-
fn type_info() -> PgTypeInfo {
22+
impl PgHasArrayType for BitVec {
23+
fn array_type_info() -> PgTypeInfo {
2424
PgTypeInfo::VARBIT_ARRAY
2525
}
2626

27-
fn compatible(ty: &PgTypeInfo) -> bool {
27+
fn array_compatible(ty: &PgTypeInfo) -> bool {
2828
*ty == PgTypeInfo::BIT_ARRAY || *ty == PgTypeInfo::VARBIT_ARRAY
2929
}
3030
}
3131

32-
impl Type<Postgres> for Vec<BitVec> {
33-
fn type_info() -> PgTypeInfo {
34-
<[BitVec] as Type<Postgres>>::type_info()
35-
}
36-
37-
fn compatible(ty: &PgTypeInfo) -> bool {
38-
<[BitVec] as Type<Postgres>>::compatible(ty)
39-
}
40-
}
41-
4232
impl Encode<'_, Postgres> for BitVec {
4333
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
4434
buf.extend(&(self.len() as i32).to_be_bytes());

sqlx-core/src/postgres/types/bool.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::decode::Decode;
22
use crate::encode::{Encode, IsNull};
33
use crate::error::BoxDynError;
4-
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
4+
use crate::postgres::{
5+
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
6+
};
57
use crate::types::Type;
68

79
impl Type<Postgres> for bool {
@@ -10,18 +12,12 @@ impl Type<Postgres> for bool {
1012
}
1113
}
1214

13-
impl Type<Postgres> for [bool] {
14-
fn type_info() -> PgTypeInfo {
15+
impl PgHasArrayType for bool {
16+
fn array_type_info() -> PgTypeInfo {
1517
PgTypeInfo::BOOL_ARRAY
1618
}
1719
}
1820

19-
impl Type<Postgres> for Vec<bool> {
20-
fn type_info() -> PgTypeInfo {
21-
<[bool] as Type<Postgres>>::type_info()
22-
}
23-
}
24-
2521
impl Encode<'_, Postgres> for bool {
2622
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
2723
buf.push(*self as u8);

sqlx-core/src/postgres/types/bytes.rs

+9-25
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,25 @@
11
use crate::decode::Decode;
22
use crate::encode::{Encode, IsNull};
33
use crate::error::BoxDynError;
4-
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
4+
use crate::postgres::{
5+
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
6+
};
57
use crate::types::Type;
68

7-
impl Type<Postgres> for [u8] {
8-
fn type_info() -> PgTypeInfo {
9+
impl PgHasArrayType for u8 {
10+
fn array_type_info() -> PgTypeInfo {
911
PgTypeInfo::BYTEA
1012
}
1113
}
1214

13-
impl Type<Postgres> for Vec<u8> {
14-
fn type_info() -> PgTypeInfo {
15-
<[u8] as Type<Postgres>>::type_info()
16-
}
17-
}
18-
19-
impl Type<Postgres> for [&'_ [u8]] {
20-
fn type_info() -> PgTypeInfo {
15+
impl PgHasArrayType for &'_ [u8] {
16+
fn array_type_info() -> PgTypeInfo {
2117
PgTypeInfo::BYTEA_ARRAY
2218
}
2319
}
2420

25-
impl Type<Postgres> for [Vec<u8>] {
26-
fn type_info() -> PgTypeInfo {
27-
<[&[u8]] as Type<Postgres>>::type_info()
28-
}
29-
}
30-
31-
impl Type<Postgres> for Vec<&'_ [u8]> {
32-
fn type_info() -> PgTypeInfo {
33-
<[&[u8]] as Type<Postgres>>::type_info()
34-
}
35-
}
36-
37-
impl Type<Postgres> for Vec<Vec<u8>> {
38-
fn type_info() -> PgTypeInfo {
21+
impl PgHasArrayType for Vec<u8> {
22+
fn array_type_info() -> PgTypeInfo {
3923
<[&[u8]] as Type<Postgres>>::type_info()
4024
}
4125
}

sqlx-core/src/postgres/types/chrono/date.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::decode::Decode;
22
use crate::encode::{Encode, IsNull};
33
use crate::error::BoxDynError;
4-
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
4+
use crate::postgres::{
5+
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
6+
};
57
use crate::types::Type;
68
use chrono::{Duration, NaiveDate};
79
use std::mem;
@@ -12,18 +14,12 @@ impl Type<Postgres> for NaiveDate {
1214
}
1315
}
1416

15-
impl Type<Postgres> for [NaiveDate] {
16-
fn type_info() -> PgTypeInfo {
17+
impl PgHasArrayType for NaiveDate {
18+
fn array_type_info() -> PgTypeInfo {
1719
PgTypeInfo::DATE_ARRAY
1820
}
1921
}
2022

21-
impl Type<Postgres> for Vec<NaiveDate> {
22-
fn type_info() -> PgTypeInfo {
23-
<[NaiveDate] as Type<Postgres>>::type_info()
24-
}
25-
}
26-
2723
impl Encode<'_, Postgres> for NaiveDate {
2824
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
2925
// DATE is encoded as the days since epoch

sqlx-core/src/postgres/types/chrono/datetime.rs

+7-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::decode::Decode;
22
use crate::encode::{Encode, IsNull};
33
use crate::error::BoxDynError;
4-
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
4+
use crate::postgres::{
5+
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
6+
};
57
use crate::types::Type;
68
use chrono::{
79
DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime, Offset, TimeZone, Utc,
@@ -20,30 +22,18 @@ impl<Tz: TimeZone> Type<Postgres> for DateTime<Tz> {
2022
}
2123
}
2224

23-
impl Type<Postgres> for [NaiveDateTime] {
24-
fn type_info() -> PgTypeInfo {
25+
impl PgHasArrayType for NaiveDateTime {
26+
fn array_type_info() -> PgTypeInfo {
2527
PgTypeInfo::TIMESTAMP_ARRAY
2628
}
2729
}
2830

29-
impl<Tz: TimeZone> Type<Postgres> for [DateTime<Tz>] {
30-
fn type_info() -> PgTypeInfo {
31+
impl<Tz: TimeZone> PgHasArrayType for DateTime<Tz> {
32+
fn array_type_info() -> PgTypeInfo {
3133
PgTypeInfo::TIMESTAMPTZ_ARRAY
3234
}
3335
}
3436

35-
impl Type<Postgres> for Vec<NaiveDateTime> {
36-
fn type_info() -> PgTypeInfo {
37-
<[NaiveDateTime] as Type<Postgres>>::type_info()
38-
}
39-
}
40-
41-
impl<Tz: TimeZone> Type<Postgres> for Vec<DateTime<Tz>> {
42-
fn type_info() -> PgTypeInfo {
43-
<[DateTime<Tz>] as Type<Postgres>>::type_info()
44-
}
45-
}
46-
4737
impl Encode<'_, Postgres> for NaiveDateTime {
4838
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
4939
// FIXME: We should *really* be returning an error, Encode needs to be fallible

sqlx-core/src/postgres/types/chrono/time.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::decode::Decode;
22
use crate::encode::{Encode, IsNull};
33
use crate::error::BoxDynError;
4-
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
4+
use crate::postgres::{
5+
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
6+
};
57
use crate::types::Type;
68
use chrono::{Duration, NaiveTime};
79
use std::mem;
@@ -12,18 +14,12 @@ impl Type<Postgres> for NaiveTime {
1214
}
1315
}
1416

15-
impl Type<Postgres> for [NaiveTime] {
16-
fn type_info() -> PgTypeInfo {
17+
impl PgHasArrayType for NaiveTime {
18+
fn array_type_info() -> PgTypeInfo {
1719
PgTypeInfo::TIME_ARRAY
1820
}
1921
}
2022

21-
impl Type<Postgres> for Vec<NaiveTime> {
22-
fn type_info() -> PgTypeInfo {
23-
<[NaiveTime] as Type<Postgres>>::type_info()
24-
}
25-
}
26-
2723
impl Encode<'_, Postgres> for NaiveTime {
2824
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
2925
// TIME is encoded as the microseconds since midnight

sqlx-core/src/postgres/types/decimal.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use crate::decode::Decode;
99
use crate::encode::{Encode, IsNull};
1010
use crate::error::BoxDynError;
1111
use crate::postgres::types::numeric::{PgNumeric, PgNumericSign};
12-
use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};
12+
use crate::postgres::{
13+
PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,
14+
};
1315
use crate::types::Type;
1416

1517
impl Type<Postgres> for Decimal {
@@ -18,18 +20,12 @@ impl Type<Postgres> for Decimal {
1820
}
1921
}
2022

21-
impl Type<Postgres> for [Decimal] {
22-
fn type_info() -> PgTypeInfo {
23+
impl PgHasArrayType for Decimal {
24+
fn array_type_info() -> PgTypeInfo {
2325
PgTypeInfo::NUMERIC_ARRAY
2426
}
2527
}
2628

27-
impl Type<Postgres> for Vec<Decimal> {
28-
fn type_info() -> PgTypeInfo {
29-
<[Decimal] as Type<Postgres>>::type_info()
30-
}
31-
}
32-
3329
impl TryFrom<PgNumeric> for Decimal {
3430
type Error = BoxDynError;
3531

0 commit comments

Comments
 (0)