tank_postgres/
value_holder.rs

1use crate::PostgresSqlWriter;
2use postgres_types::Type;
3use std::{error::Error, fmt::Write, io::Read};
4use tank_core::{SqlWriter, Value};
5use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
6use tokio_postgres::types::{FromSql, IsNull, ToSql, private::BytesMut};
7
8#[derive(Debug)]
9pub(crate) struct ValueHolder(pub(crate) Value);
10
11impl From<Value> for ValueHolder {
12    fn from(value: Value) -> Self {
13        ValueHolder(value)
14    }
15}
16
17impl<'a> FromSql<'a> for ValueHolder {
18    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
19        Self::from_sql_nullable(ty, Some(raw))
20    }
21    fn from_sql_null(ty: &Type) -> Result<Self, Box<dyn Error + Sync + Send>> {
22        Self::from_sql_nullable(ty, None)
23    }
24    fn from_sql_nullable(
25        ty: &Type,
26        raw: Option<&'a [u8]>,
27    ) -> Result<Self, Box<dyn Error + Sync + Send>> {
28        macro_rules! to_value {
29            ($ty_var:ident, $raw:ident, $($($ty:path)|+ => ( $value:path, $source:ty ) ,)+) => {
30                match *$ty_var {
31                    $($($ty)|+ => $value(if let Some($raw) = $raw { Some(<$source>::from_sql($ty_var, $raw)?.into()) } else { None }),)+
32                    _ => {
33                        if let Some(mut raw) = $raw {
34                            let mut buf = String::new();
35                            raw.read_to_string(&mut buf);
36                            return Err(tank_core::Error::msg(format!("Unknown value type {}: `{}`", $ty_var, buf)).into());
37                        }
38                        Value::Null
39                    }
40                }
41            };
42        }
43        let value = to_value!(ty, raw,
44            Type::BOOL => (Value::Boolean, bool),
45            Type::BYTEA => (Value::Blob, Vec<u8>),
46            Type::CHAR => (Value::Int8, i8),
47            Type::VARCHAR | Type::TEXT | Type::NAME | Type::JSON | Type::XML => (Value::Varchar, String),
48            Type::INT8 => (Value::Int64, i64),
49            Type::INT2 => (Value::Int16, i16),
50            Type::INT4 => (Value::Int32, i32),
51            Type::OID => (Value::UInt32, u32),
52            Type::FLOAT4 => (Value::Float32, f32),
53            Type::FLOAT8 => (Value::Float64, f64),
54            Type::DATE => (Value::Date, Date),
55            Type::TIME => (Value::Time, Time),
56            Type::TIMESTAMP => (Value::Timestamp, PrimitiveDateTime),
57            Type::TIMESTAMPTZ => (Value::TimestampWithTimezone, OffsetDateTime),
58        );
59        Ok(value.into())
60    }
61
62    fn accepts(_ty: &Type) -> bool {
63        true
64    }
65}
66
67impl ToSql for ValueHolder {
68    fn to_sql(&self, _ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>>
69    where
70        Self: Sized,
71    {
72        let mut sql = String::new();
73        PostgresSqlWriter {}.write_value(Default::default(), &mut sql, &self.0);
74        out.write_str(&sql)?;
75        Ok(if self.0.is_null() {
76            IsNull::Yes
77        } else {
78            IsNull::No
79        })
80    }
81
82    fn accepts(_ty: &Type) -> bool
83    where
84        Self: Sized,
85    {
86        todo!()
87    }
88
89    fn to_sql_checked(
90        &self,
91        _ty: &Type,
92        _out: &mut BytesMut,
93    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
94        todo!()
95    }
96}
97
98pub fn value_to_type(value: &Value) -> Type {
99    match value {
100        Value::Null => Type::UNKNOWN,
101        Value::Boolean(..) => Type::BOOL,
102        Value::Int8(..) => Type::CHAR,
103        Value::Int16(..) => Type::INT2,
104        Value::Int32(..) => Type::INT4,
105        Value::Int64(..) => Type::INT8,
106        Value::Int128(..) => Type::UNKNOWN,
107        Value::UInt8(..) => Type::INT2,
108        Value::UInt16(..) => Type::INT4,
109        Value::UInt32(..) => Type::INT8,
110        Value::UInt64(..) => Type::INT8,
111        Value::UInt128(..) => Type::UNKNOWN,
112        Value::Float32(..) => Type::FLOAT4,
113        Value::Float64(..) => Type::FLOAT8,
114        Value::Decimal(..) => Type::NUMERIC,
115        Value::Char(..) => Type::CHAR,
116        Value::Varchar(..) => Type::TEXT,
117        Value::Blob(..) => Type::BYTEA,
118        Value::Date(..) => Type::DATE,
119        Value::Time(..) => Type::TIME,
120        Value::Timestamp(..) => Type::TIMESTAMP,
121        Value::TimestampWithTimezone(..) => Type::TIMESTAMPTZ,
122        Value::Interval(..) => Type::INTERVAL,
123        Value::Uuid(..) => Type::UUID,
124        Value::Array(.., ty, _) => match **ty {
125            Value::Null => Type::UNKNOWN,
126            Value::Boolean(..) => Type::BOOL_ARRAY,
127            Value::Int8(..) => Type::INT2_ARRAY,
128            Value::Int16(..) => Type::INT2_ARRAY,
129            Value::Int32(..) => Type::INT4_ARRAY,
130            Value::Int64(..) => Type::INT8_ARRAY,
131            Value::Int128(..) => Type::UNKNOWN,
132            Value::UInt8(..) => Type::INT2_ARRAY,
133            Value::UInt16(..) => Type::INT4_ARRAY,
134            Value::UInt32(..) => Type::INT8_ARRAY,
135            Value::UInt64(..) => Type::INT8_ARRAY,
136            Value::UInt128(..) => Type::UNKNOWN,
137            Value::Float32(..) => Type::FLOAT4_ARRAY,
138            Value::Float64(..) => Type::FLOAT8_ARRAY,
139            Value::Decimal(..) => Type::NUMERIC_ARRAY,
140            Value::Char(..) => Type::CHAR_ARRAY,
141            Value::Varchar(..) => Type::TEXT_ARRAY,
142            Value::Blob(..) => Type::BYTEA_ARRAY,
143            Value::Date(..) => Type::DATE_ARRAY,
144            Value::Time(..) => Type::TIME_ARRAY,
145            Value::Timestamp(..) => Type::TIMESTAMP_ARRAY,
146            Value::TimestampWithTimezone(..) => Type::TIMESTAMPTZ_ARRAY,
147            Value::Interval(..) => Type::INTERVAL_ARRAY,
148            Value::Uuid(..) => Type::UUID_ARRAY,
149            _ => Type::ANYARRAY,
150        },
151        _ => Type::UNKNOWN,
152    }
153}