Skip to main content

connectorx/transports/
postgres_arrow.rs

1//! Transport from Postgres Source to Arrow Destination.
2
3use crate::destinations::arrow::{
4    typesystem::{
5        ArrowTypeSystem, DateTimeWrapperMicro, NaiveDateTimeWrapperMicro, NaiveTimeWrapperMicro,
6    },
7    ArrowDestination, ArrowDestinationError,
8};
9use crate::sources::postgres::{
10    BinaryProtocol, CSVProtocol, CursorProtocol, PostgresSource, PostgresSourceError,
11    PostgresTypeSystem, SimpleProtocol,
12};
13use crate::typesystem::TypeConversion;
14use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
15use cidr_02::IpInet;
16use num_traits::ToPrimitive;
17use pgvector::{Bit, HalfVector, SparseVector, Vector};
18use postgres::NoTls;
19use postgres_openssl::MakeTlsConnector;
20use rust_decimal::Decimal;
21use serde_json::Value;
22use std::marker::PhantomData;
23use thiserror::Error;
24use uuid::Uuid;
25
26#[derive(Error, Debug)]
27pub enum PostgresArrowTransportError {
28    #[error(transparent)]
29    Source(#[from] PostgresSourceError),
30
31    #[error(transparent)]
32    Destination(#[from] ArrowDestinationError),
33
34    #[error(transparent)]
35    ConnectorX(#[from] crate::errors::ConnectorXError),
36}
37
38/// Convert Postgres data types to Arrow data types.
39pub struct PostgresArrowTransport<P, C>(PhantomData<P>, PhantomData<C>);
40
41macro_rules! impl_postgres_transport {
42    ($proto:ty, $tls:ty) => {
43        impl_transport!(
44            name = PostgresArrowTransport<$proto, $tls>,
45            error = PostgresArrowTransportError,
46            systems = PostgresTypeSystem => ArrowTypeSystem,
47            route = PostgresSource<$proto, $tls> => ArrowDestination,
48            mappings = {
49                { Float4[f32]                        => Float32[f32]                           | conversion auto   }
50                { Float8[f64]                        => Float64[f64]                           | conversion auto   }
51                { Numeric[Decimal]                   => Decimal[Decimal]                       | conversion auto   }
52                { Int2[i16]                          => Int16[i16]                             | conversion auto   }
53                { Int4[i32]                          => Int32[i32]                             | conversion auto   }
54                { Int8[i64]                          => Int64[i64]                             | conversion auto   }
55                { UInt4[u32]                         => UInt32[u32]                            | conversion auto   }
56                { Bool[bool]                         => Boolean[bool]                          | conversion auto   }
57                { Text[&'r str]                      => LargeUtf8[String]                      | conversion owned  }
58                { BpChar[&'r str]                    => LargeUtf8[String]                      | conversion none   }
59                { VarChar[&'r str]                   => LargeUtf8[String]                      | conversion none   }
60                { Name[&'r str]                      => LargeUtf8[String]                      | conversion none   }
61                { Enum[&'r str]                      => LargeUtf8[String]                      | conversion none   }
62                { Timestamp[NaiveDateTime]           => Date64Micro[NaiveDateTimeWrapperMicro] | conversion option }
63                { Date[NaiveDate]                    => Date32[NaiveDate]                      | conversion auto   }
64                { Time[NaiveTime]                    => Time64Micro[NaiveTimeWrapperMicro]     | conversion option }
65                { TimestampTz[DateTime<Utc>]         => DateTimeTzMicro[DateTimeWrapperMicro]  | conversion option }
66                { UUID[Uuid]                         => LargeUtf8[String]                      | conversion option }
67                { Char[&'r str]                      => LargeUtf8[String]                      | conversion none   }
68                { ByteA[Vec<u8>]                     => LargeBinary[Vec<u8>]                   | conversion auto   }
69                { JSON[Value]                        => LargeUtf8[String]                      | conversion option }
70                { JSONB[Value]                       => LargeUtf8[String]                      | conversion none   }
71                { Inet[IpInet]                       => LargeUtf8[String]                      | conversion none   }
72                { Range[&'r str]                     => LargeUtf8[String]                      | conversion none   }
73                { TsVector[&'r str]                  => LargeUtf8[String]                      | conversion none   }
74                { BoolArray[Vec<Option<bool>>]       => BoolArray[Vec<Option<bool>>]           | conversion auto   }
75                { VarcharArray[Vec<Option<String>>]  => Utf8Array[Vec<Option<String>>]         | conversion auto   }
76                { TextArray[Vec<Option<String>>]     => Utf8Array[Vec<Option<String>>]         | conversion none   }
77                { Int2Array[Vec<Option<i16>>]        => Int16Array[Vec<Option<i16>>]           | conversion auto   }
78                { Int4Array[Vec<Option<i32>>]        => Int32Array[Vec<Option<i32>>]           | conversion auto   }
79                { Int8Array[Vec<Option<i64>>]        => Int64Array[Vec<Option<i64>>]           | conversion auto   }
80                { Float4Array[Vec<Option<f32>>]      => Float32Array[Vec<Option<f32>>]         | conversion auto   }
81                { Float8Array[Vec<Option<f64>>]      => Float64Array[Vec<Option<f64>>]         | conversion auto   }
82                { NumericArray[Vec<Option<Decimal>>] => DecimalArray[Vec<Option<Decimal>>]     | conversion auto   }
83                { Vector[Vector]                     => Float32Array[Vec<Option<f32>>]         | conversion option }
84                { HalfVec[HalfVector]                => Float32Array[Vec<Option<f32>>]         | conversion option }
85                { Bit[Bit]                           => LargeBinary[Vec<u8>]                   | conversion option }
86                { SparseVec[SparseVector]            => Float32Array[Vec<Option<f32>>]         | conversion option }
87            }
88        );
89    }
90}
91
92impl_postgres_transport!(BinaryProtocol, NoTls);
93impl_postgres_transport!(BinaryProtocol, MakeTlsConnector);
94impl_postgres_transport!(CSVProtocol, NoTls);
95impl_postgres_transport!(CSVProtocol, MakeTlsConnector);
96impl_postgres_transport!(CursorProtocol, NoTls);
97impl_postgres_transport!(CursorProtocol, MakeTlsConnector);
98impl_postgres_transport!(SimpleProtocol, NoTls);
99impl_postgres_transport!(SimpleProtocol, MakeTlsConnector);
100
101impl<P, C> TypeConversion<IpInet, String> for PostgresArrowTransport<P, C> {
102    fn convert(val: IpInet) -> String {
103        val.to_string()
104    }
105}
106
107impl<P, C> TypeConversion<Option<IpInet>, Option<String>> for PostgresArrowTransport<P, C> {
108    fn convert(val: Option<IpInet>) -> Option<String> {
109        val.map(|val| val.to_string())
110    }
111}
112
113impl<P, C> TypeConversion<NaiveTime, NaiveTimeWrapperMicro> for PostgresArrowTransport<P, C> {
114    fn convert(val: NaiveTime) -> NaiveTimeWrapperMicro {
115        NaiveTimeWrapperMicro(val)
116    }
117}
118
119impl<P, C> TypeConversion<NaiveDateTime, NaiveDateTimeWrapperMicro>
120    for PostgresArrowTransport<P, C>
121{
122    fn convert(val: NaiveDateTime) -> NaiveDateTimeWrapperMicro {
123        NaiveDateTimeWrapperMicro(val)
124    }
125}
126
127impl<P, C> TypeConversion<DateTime<Utc>, DateTimeWrapperMicro> for PostgresArrowTransport<P, C> {
128    fn convert(val: DateTime<Utc>) -> DateTimeWrapperMicro {
129        DateTimeWrapperMicro(val)
130    }
131}
132
133impl<P, C> TypeConversion<Uuid, String> for PostgresArrowTransport<P, C> {
134    fn convert(val: Uuid) -> String {
135        val.to_string()
136    }
137}
138
139impl<P, C> TypeConversion<Decimal, f64> for PostgresArrowTransport<P, C> {
140    fn convert(val: Decimal) -> f64 {
141        val.to_f64()
142            .unwrap_or_else(|| panic!("cannot convert decimal {:?} to float64", val))
143    }
144}
145
146impl<P, C> TypeConversion<Value, String> for PostgresArrowTransport<P, C> {
147    fn convert(val: Value) -> String {
148        val.to_string()
149    }
150}
151
152impl<P, C> TypeConversion<Vector, Vec<Option<f32>>> for PostgresArrowTransport<P, C> {
153    fn convert(val: Vector) -> Vec<Option<f32>> {
154        val.to_vec().into_iter().map(Some).collect()
155    }
156}
157
158impl<P, C> TypeConversion<HalfVector, Vec<Option<f32>>> for PostgresArrowTransport<P, C> {
159    fn convert(val: HalfVector) -> Vec<Option<f32>> {
160        val.to_vec().into_iter().map(|v| Some(v.to_f32())).collect()
161    }
162}
163
164impl<P, C> TypeConversion<Bit, Vec<u8>> for PostgresArrowTransport<P, C> {
165    fn convert(val: Bit) -> Vec<u8> {
166        val.as_bytes().into()
167    }
168}
169
170impl<P, C> TypeConversion<SparseVector, Vec<Option<f32>>> for PostgresArrowTransport<P, C> {
171    fn convert(val: SparseVector) -> Vec<Option<f32>> {
172        val.to_vec().into_iter().map(Some).collect()
173    }
174}