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}