Skip to content

Commit ace9687

Browse files
committed
Break type-related code out of Postgres client to more focused modules
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
1 parent 7bf9067 commit ace9687

File tree

7 files changed

+1111
-571
lines changed

7 files changed

+1111
-571
lines changed

crates/factor-outbound-pg/src/client.rs

Lines changed: 435 additions & 571 deletions
Large diffs are not rendered by default.

crates/factor-outbound-pg/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod client;
22
mod host;
3+
mod types;
34

45
use client::Client;
56
use spin_factor_outbound_networking::{
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
use spin_world::spin::postgres4_0_0::postgres::{DbDataType, DbValue, ParameterValue};
2+
use tokio_postgres::types::{FromSql, Type};
3+
use tokio_postgres::{types::ToSql, Row};
4+
5+
mod convert;
6+
mod decimal;
7+
mod interval;
8+
mod pg_null;
9+
10+
use convert::{
11+
date_pg_to_wit, date_wit_to_pg, datetime_pg_to_wit, datetime_wit_to_pg,
12+
decimal_array_pg_to_wit, decimal_array_wit_to_pg, decimal_range_pg_to_wit,
13+
decimal_range_wit_to_pg, decimal_wit_to_pg, jsonb_pg_to_wit, jsonb_wit_to_pg, range_pg_to_wit,
14+
range_wit_to_pg, time_pg_to_wit, time_wit_to_pg, timestamp_wit_to_pg, uuid_wit_to_pg,
15+
};
16+
use interval::Interval;
17+
use pg_null::PgNull;
18+
19+
pub fn convert_data_type(pg_type: &Type) -> DbDataType {
20+
match *pg_type {
21+
Type::BOOL => DbDataType::Boolean,
22+
Type::BYTEA => DbDataType::Binary,
23+
Type::FLOAT4 => DbDataType::Floating32,
24+
Type::FLOAT8 => DbDataType::Floating64,
25+
Type::INT2 => DbDataType::Int16,
26+
Type::INT4 => DbDataType::Int32,
27+
Type::INT8 => DbDataType::Int64,
28+
Type::TEXT | Type::VARCHAR | Type::BPCHAR => DbDataType::Str,
29+
Type::TIMESTAMP | Type::TIMESTAMPTZ => DbDataType::Datetime,
30+
Type::DATE => DbDataType::Date,
31+
Type::TIME => DbDataType::Time,
32+
Type::UUID => DbDataType::Uuid,
33+
Type::JSONB => DbDataType::Jsonb,
34+
Type::NUMERIC => DbDataType::Decimal,
35+
Type::INT4_RANGE => DbDataType::RangeInt32,
36+
Type::INT8_RANGE => DbDataType::RangeInt64,
37+
Type::NUM_RANGE => DbDataType::RangeDecimal,
38+
Type::INT4_ARRAY => DbDataType::ArrayInt32,
39+
Type::INT8_ARRAY => DbDataType::ArrayInt64,
40+
Type::NUMERIC_ARRAY => DbDataType::ArrayDecimal,
41+
Type::TEXT_ARRAY | Type::VARCHAR_ARRAY | Type::BPCHAR_ARRAY => DbDataType::ArrayStr,
42+
Type::INTERVAL => DbDataType::Interval,
43+
_ => {
44+
tracing::debug!("Couldn't convert Postgres type {} to WIT", pg_type.name(),);
45+
DbDataType::Other
46+
}
47+
}
48+
}
49+
50+
fn db_value<'a, T: FromSql<'a>>(
51+
row: &'a Row,
52+
index: usize,
53+
convert_fn: impl Fn(T) -> DbValue,
54+
) -> anyhow::Result<DbValue> {
55+
let value: Option<T> = row.try_get(index)?;
56+
Ok(match value {
57+
Some(v) => convert_fn(v),
58+
None => DbValue::DbNull,
59+
})
60+
}
61+
62+
fn map_db_value<'a, T: FromSql<'a>, W>(
63+
row: &'a Row,
64+
index: usize,
65+
ctor: impl Fn(W) -> DbValue,
66+
convert_fn: impl Fn(T) -> W,
67+
) -> anyhow::Result<DbValue> {
68+
let value: Option<T> = row.try_get(index)?;
69+
Ok(match value {
70+
Some(v) => ctor(convert_fn(v)),
71+
None => DbValue::DbNull,
72+
})
73+
}
74+
75+
fn try_map_db_value<'a, T: FromSql<'a>, W>(
76+
row: &'a Row,
77+
index: usize,
78+
ctor: impl Fn(W) -> DbValue,
79+
convert_fn: impl Fn(T) -> anyhow::Result<W>,
80+
) -> anyhow::Result<DbValue> {
81+
let value: Option<T> = row.try_get(index)?;
82+
Ok(match value {
83+
Some(v) => ctor(convert_fn(v)?),
84+
None => DbValue::DbNull,
85+
})
86+
}
87+
88+
pub fn convert_entry(row: &Row, index: usize) -> anyhow::Result<DbValue> {
89+
let column = &row.columns()[index];
90+
match column.type_() {
91+
&Type::BOOL => db_value(row, index, DbValue::Boolean),
92+
&Type::BYTEA => db_value(row, index, DbValue::Binary),
93+
&Type::FLOAT4 => db_value(row, index, DbValue::Floating32),
94+
&Type::FLOAT8 => db_value(row, index, DbValue::Floating64),
95+
&Type::INT2 => db_value(row, index, DbValue::Int16),
96+
&Type::INT4 => db_value(row, index, DbValue::Int32),
97+
&Type::INT8 => db_value(row, index, DbValue::Int64),
98+
&Type::TEXT | &Type::VARCHAR | &Type::BPCHAR => db_value(row, index, DbValue::Str),
99+
&Type::TIMESTAMP | &Type::TIMESTAMPTZ => {
100+
try_map_db_value(row, index, DbValue::Datetime, datetime_pg_to_wit)
101+
}
102+
&Type::DATE => try_map_db_value(row, index, DbValue::Date, date_pg_to_wit),
103+
&Type::TIME => try_map_db_value(row, index, DbValue::Time, time_pg_to_wit),
104+
&Type::UUID => map_db_value(row, index, DbValue::Uuid, |v: uuid::Uuid| v.to_string()),
105+
&Type::JSONB => try_map_db_value(row, index, DbValue::Jsonb, jsonb_pg_to_wit),
106+
&Type::NUMERIC => map_db_value(row, index, DbValue::Decimal, |v: rust_decimal::Decimal| {
107+
v.to_string()
108+
}),
109+
&Type::INT4_RANGE => map_db_value(row, index, DbValue::RangeInt32, range_pg_to_wit),
110+
&Type::INT8_RANGE => map_db_value(row, index, DbValue::RangeInt64, range_pg_to_wit),
111+
&Type::NUM_RANGE => {
112+
map_db_value(row, index, DbValue::RangeDecimal, decimal_range_pg_to_wit)
113+
}
114+
&Type::INT4_ARRAY => db_value(row, index, DbValue::ArrayInt32),
115+
&Type::INT8_ARRAY => db_value(row, index, DbValue::ArrayInt64),
116+
&Type::NUMERIC_ARRAY => {
117+
map_db_value(row, index, DbValue::ArrayDecimal, decimal_array_pg_to_wit)
118+
}
119+
&Type::TEXT_ARRAY | &Type::VARCHAR_ARRAY | &Type::BPCHAR_ARRAY => {
120+
db_value(row, index, DbValue::ArrayStr)
121+
}
122+
&Type::INTERVAL => map_db_value(row, index, DbValue::Interval, |v: Interval| v.into()),
123+
t => {
124+
tracing::debug!(
125+
"Couldn't convert Postgres type {} in column {}",
126+
t.name(),
127+
column.name()
128+
);
129+
Ok(DbValue::Unsupported)
130+
}
131+
}
132+
}
133+
134+
pub fn to_sql_parameter(value: &ParameterValue) -> anyhow::Result<Box<dyn ToSql + Send + Sync>> {
135+
match value {
136+
ParameterValue::Boolean(v) => Ok(Box::new(*v)),
137+
ParameterValue::Int32(v) => Ok(Box::new(*v)),
138+
ParameterValue::Int64(v) => Ok(Box::new(*v)),
139+
ParameterValue::Int8(v) => Ok(Box::new(*v)),
140+
ParameterValue::Int16(v) => Ok(Box::new(*v)),
141+
ParameterValue::Floating32(v) => Ok(Box::new(*v)),
142+
ParameterValue::Floating64(v) => Ok(Box::new(*v)),
143+
ParameterValue::Str(v) => Ok(Box::new(v.clone())),
144+
ParameterValue::Binary(v) => Ok(Box::new(v.clone())),
145+
ParameterValue::Date(v) => Ok(Box::new(date_wit_to_pg(v)?)),
146+
ParameterValue::Time(v) => Ok(Box::new(time_wit_to_pg(v)?)),
147+
ParameterValue::Datetime(v) => Ok(Box::new(datetime_wit_to_pg(v)?)),
148+
ParameterValue::Timestamp(v) => Ok(Box::new(timestamp_wit_to_pg(*v)?)),
149+
ParameterValue::Uuid(v) => Ok(Box::new(uuid_wit_to_pg(v)?)),
150+
ParameterValue::Jsonb(v) => Ok(Box::new(jsonb_wit_to_pg(v)?)),
151+
ParameterValue::Decimal(v) => Ok(Box::new(decimal_wit_to_pg(v)?)),
152+
ParameterValue::RangeInt32(v) => Ok(Box::new(range_wit_to_pg(*v))),
153+
ParameterValue::RangeInt64(v) => Ok(Box::new(range_wit_to_pg(*v))),
154+
ParameterValue::RangeDecimal(v) => Ok(Box::new(decimal_range_wit_to_pg(v)?)),
155+
ParameterValue::ArrayInt32(vs) => Ok(Box::new(vs.to_owned())),
156+
ParameterValue::ArrayInt64(vs) => Ok(Box::new(vs.to_owned())),
157+
ParameterValue::ArrayDecimal(vs) => Ok(Box::new(decimal_array_wit_to_pg(vs)?)),
158+
ParameterValue::ArrayStr(vs) => Ok(Box::new(vs.to_owned())),
159+
ParameterValue::Interval(v) => Ok(Box::new(Interval(*v))),
160+
ParameterValue::DbNull => Ok(Box::new(PgNull)),
161+
}
162+
}

0 commit comments

Comments
 (0)