sqlint/connector/postgres/
conversion.rs

1#[cfg(feature = "bigdecimal")]
2mod decimal;
3
4use crate::{
5    ast::Value,
6    connector::queryable::{GetRow, ToColumnNames},
7    error::{Error, ErrorKind},
8};
9#[cfg(feature = "bigdecimal")]
10use bigdecimal::{num_bigint::BigInt, BigDecimal, FromPrimitive, ToPrimitive};
11use bit_vec::BitVec;
12use bytes::BytesMut;
13#[cfg(feature = "chrono")]
14use chrono::{DateTime, NaiveDateTime, Utc};
15#[cfg(feature = "bigdecimal")]
16pub(crate) use decimal::DecimalWrapper;
17use postgres_types::{FromSql, ToSql, WrongType};
18use std::{convert::TryFrom, error::Error as StdError};
19use tokio_postgres::{
20    types::{self, IsNull, Kind, Type as PostgresType},
21    Row as PostgresRow, Statement as PostgresStatement,
22};
23
24#[cfg(feature = "uuid")]
25use uuid::Uuid;
26
27pub(crate) fn conv_params<'a>(params: &'a [Value<'a>]) -> Vec<&'a (dyn types::ToSql + Sync)> {
28    params.iter().map(|x| x as &(dyn ToSql + Sync)).collect::<Vec<_>>()
29}
30
31/// Maps a list of query parameter values to a list of Postgres type.
32pub(crate) fn params_to_types(params: &[Value<'_>]) -> Vec<PostgresType> {
33    params
34        .iter()
35        .map(|p| -> PostgresType {
36            // While we can infer the underlying type of a null, Khulnasoft can't.
37            // Therefore, we let PG infer the underlying type.
38            if p.is_null() {
39                return PostgresType::UNKNOWN;
40            }
41
42            match p {
43                Value::Int32(_) => PostgresType::INT4,
44                Value::Int64(_) => PostgresType::INT8,
45                Value::Float(_) => PostgresType::FLOAT4,
46                Value::Double(_) => PostgresType::FLOAT8,
47                Value::Text(_) => PostgresType::TEXT,
48                // Enums are special types, we can't statically infer them, so we let PG infer it
49                Value::Enum(_) => PostgresType::UNKNOWN,
50                Value::Bytes(_) => PostgresType::BYTEA,
51                Value::Boolean(_) => PostgresType::BOOL,
52                Value::Char(_) => PostgresType::CHAR,
53                #[cfg(feature = "bigdecimal")]
54                Value::Numeric(_) => PostgresType::NUMERIC,
55                #[cfg(feature = "json")]
56                Value::Json(_) => PostgresType::JSONB,
57                Value::Xml(_) => PostgresType::XML,
58                #[cfg(feature = "uuid")]
59                Value::Uuid(_) => PostgresType::UUID,
60                #[cfg(feature = "chrono")]
61                Value::DateTime(_) => PostgresType::TIMESTAMPTZ,
62                #[cfg(feature = "chrono")]
63                Value::Date(_) => PostgresType::TIMESTAMP,
64                #[cfg(feature = "chrono")]
65                Value::Time(_) => PostgresType::TIME,
66                Value::Array(ref arr) => {
67                    let arr = arr.as_ref().unwrap();
68
69                    // If the array is empty, we can't infer the type so we let PG infer it
70                    if arr.is_empty() {
71                        return PostgresType::UNKNOWN;
72                    }
73
74                    let first = arr.first().unwrap();
75
76                    // If the array does not contain the same types of values, we let PG infer the type
77                    if arr.iter().any(|val| std::mem::discriminant(first) != std::mem::discriminant(val)) {
78                        return PostgresType::UNKNOWN;
79                    }
80
81                    match first {
82                        Value::Int32(_) => PostgresType::INT4_ARRAY,
83                        Value::Int64(_) => PostgresType::INT8_ARRAY,
84                        Value::Float(_) => PostgresType::FLOAT4_ARRAY,
85                        Value::Double(_) => PostgresType::FLOAT8_ARRAY,
86                        Value::Text(_) => PostgresType::TEXT_ARRAY,
87                        // Enums are special types, we can't statically infer them, so we let PG infer it
88                        Value::Enum(_) => PostgresType::UNKNOWN,
89                        Value::Bytes(_) => PostgresType::BYTEA_ARRAY,
90                        Value::Boolean(_) => PostgresType::BOOL_ARRAY,
91                        Value::Char(_) => PostgresType::CHAR_ARRAY,
92                        #[cfg(feature = "bigdecimal")]
93                        Value::Numeric(_) => PostgresType::NUMERIC_ARRAY,
94                        #[cfg(feature = "json")]
95                        Value::Json(_) => PostgresType::JSONB_ARRAY,
96                        Value::Xml(_) => PostgresType::XML_ARRAY,
97                        #[cfg(feature = "uuid")]
98                        Value::Uuid(_) => PostgresType::UUID_ARRAY,
99                        #[cfg(feature = "chrono")]
100                        Value::DateTime(_) => PostgresType::TIMESTAMPTZ_ARRAY,
101                        #[cfg(feature = "chrono")]
102                        Value::Date(_) => PostgresType::TIMESTAMP_ARRAY,
103                        #[cfg(feature = "chrono")]
104                        Value::Time(_) => PostgresType::TIME_ARRAY,
105                        // In the case of nested arrays, we let PG infer the type
106                        Value::Array(_) => PostgresType::UNKNOWN,
107                    }
108                }
109            }
110        })
111        .collect()
112}
113
114struct XmlString(pub String);
115
116impl<'a> FromSql<'a> for XmlString {
117    fn from_sql(_ty: &PostgresType, raw: &'a [u8]) -> Result<XmlString, Box<dyn std::error::Error + Sync + Send>> {
118        Ok(XmlString(String::from_utf8(raw.to_owned()).unwrap()))
119    }
120
121    fn accepts(ty: &PostgresType) -> bool {
122        ty == &PostgresType::XML
123    }
124}
125
126struct EnumString {
127    value: String,
128}
129
130impl<'a> FromSql<'a> for EnumString {
131    fn from_sql(_ty: &PostgresType, raw: &'a [u8]) -> Result<EnumString, Box<dyn std::error::Error + Sync + Send>> {
132        Ok(EnumString { value: String::from_utf8(raw.to_owned()).unwrap() })
133    }
134
135    fn accepts(_ty: &PostgresType) -> bool {
136        true
137    }
138}
139
140#[cfg(feature = "chrono")]
141struct TimeTz(chrono::NaiveTime);
142
143#[cfg(feature = "chrono")]
144impl<'a> FromSql<'a> for TimeTz {
145    fn from_sql(_ty: &PostgresType, raw: &'a [u8]) -> Result<TimeTz, Box<dyn std::error::Error + Sync + Send>> {
146        // We assume UTC.
147        let time: chrono::NaiveTime = chrono::NaiveTime::from_sql(&PostgresType::TIMETZ, &raw[..8])?;
148        Ok(TimeTz(time))
149    }
150
151    fn accepts(ty: &PostgresType) -> bool {
152        ty == &PostgresType::TIMETZ
153    }
154}
155
156/// This implementation of FromSql assumes that the precision for money fields is configured to the default
157/// of 2 decimals.
158///
159/// Postgres docs: https://www.postgresql.org/docs/current/datatype-money.html
160#[cfg(feature = "bigdecimal")]
161struct NaiveMoney(BigDecimal);
162
163#[cfg(feature = "bigdecimal")]
164impl<'a> FromSql<'a> for NaiveMoney {
165    fn from_sql(_ty: &PostgresType, raw: &'a [u8]) -> Result<NaiveMoney, Box<dyn std::error::Error + Sync + Send>> {
166        let cents = i64::from_sql(&PostgresType::INT8, raw)?;
167
168        Ok(NaiveMoney(BigDecimal::new(BigInt::from_i64(cents).unwrap(), 2)))
169    }
170
171    fn accepts(ty: &PostgresType) -> bool {
172        ty == &PostgresType::MONEY
173    }
174}
175
176impl GetRow for PostgresRow {
177    fn get_result_row(&self) -> crate::Result<Vec<Value<'static>>> {
178        fn convert(row: &PostgresRow, i: usize) -> crate::Result<Value<'static>> {
179            let result = match *row.columns()[i].type_() {
180                PostgresType::BOOL => Value::Boolean(row.try_get(i)?),
181                PostgresType::INT2 => match row.try_get(i)? {
182                    Some(val) => {
183                        let val: i16 = val;
184                        Value::int32(val)
185                    }
186                    None => Value::Int32(None),
187                },
188                PostgresType::INT4 => match row.try_get(i)? {
189                    Some(val) => {
190                        let val: i32 = val;
191                        Value::int32(val)
192                    }
193                    None => Value::Int32(None),
194                },
195                PostgresType::INT8 => match row.try_get(i)? {
196                    Some(val) => {
197                        let val: i64 = val;
198                        Value::int64(val)
199                    }
200                    None => Value::Int64(None),
201                },
202                PostgresType::FLOAT4 => match row.try_get(i)? {
203                    Some(val) => {
204                        let val: f32 = val;
205                        Value::float(val)
206                    }
207                    None => Value::Float(None),
208                },
209                PostgresType::FLOAT8 => match row.try_get(i)? {
210                    Some(val) => {
211                        let val: f64 = val;
212                        Value::double(val)
213                    }
214                    None => Value::Double(None),
215                },
216                PostgresType::BYTEA => match row.try_get(i)? {
217                    Some(val) => {
218                        let val: &[u8] = val;
219                        Value::bytes(val.to_owned())
220                    }
221                    None => Value::Bytes(None),
222                },
223                PostgresType::BYTEA_ARRAY => match row.try_get(i)? {
224                    Some(val) => {
225                        let val: Vec<Option<Vec<u8>>> = val;
226                        let byteas = val.into_iter().map(|b| Value::Bytes(b.map(Into::into)));
227
228                        Value::array(byteas)
229                    }
230                    None => Value::Array(None),
231                },
232                #[cfg(feature = "bigdecimal")]
233                PostgresType::NUMERIC => {
234                    let dw: Option<DecimalWrapper> = row.try_get(i)?;
235
236                    Value::Numeric(dw.map(|dw| dw.0))
237                }
238                #[cfg(feature = "bigdecimal")]
239                PostgresType::MONEY => match row.try_get(i)? {
240                    Some(val) => {
241                        let val: NaiveMoney = val;
242                        Value::numeric(val.0)
243                    }
244                    None => Value::Numeric(None),
245                },
246                #[cfg(feature = "chrono")]
247                PostgresType::TIMESTAMP => match row.try_get(i)? {
248                    Some(val) => {
249                        let ts: NaiveDateTime = val;
250                        let dt = DateTime::<Utc>::from_utc(ts, Utc);
251                        Value::datetime(dt)
252                    }
253                    None => Value::DateTime(None),
254                },
255                #[cfg(feature = "chrono")]
256                PostgresType::TIMESTAMPTZ => match row.try_get(i)? {
257                    Some(val) => {
258                        let ts: DateTime<Utc> = val;
259                        Value::datetime(ts)
260                    }
261                    None => Value::DateTime(None),
262                },
263                #[cfg(feature = "chrono")]
264                PostgresType::DATE => match row.try_get(i)? {
265                    Some(val) => Value::date(val),
266                    None => Value::Date(None),
267                },
268                #[cfg(feature = "chrono")]
269                PostgresType::TIME => match row.try_get(i)? {
270                    Some(val) => Value::time(val),
271                    None => Value::Time(None),
272                },
273                #[cfg(feature = "chrono")]
274                PostgresType::TIMETZ => match row.try_get(i)? {
275                    Some(val) => {
276                        let time: TimeTz = val;
277                        Value::time(time.0)
278                    }
279                    None => Value::Time(None),
280                },
281                #[cfg(feature = "uuid")]
282                PostgresType::UUID => match row.try_get(i)? {
283                    Some(val) => {
284                        let val: Uuid = val;
285                        Value::uuid(val)
286                    }
287                    None => Value::Uuid(None),
288                },
289                #[cfg(feature = "uuid")]
290                PostgresType::UUID_ARRAY => match row.try_get(i)? {
291                    Some(val) => {
292                        let val: Vec<Option<Uuid>> = val;
293                        let val = val.into_iter().map(Value::Uuid);
294
295                        Value::array(val)
296                    }
297                    None => Value::Array(None),
298                },
299                #[cfg(feature = "json")]
300                PostgresType::JSON | PostgresType::JSONB => Value::Json(row.try_get(i)?),
301                PostgresType::INT2_ARRAY => match row.try_get(i)? {
302                    Some(val) => {
303                        let val: Vec<Option<i16>> = val;
304                        let ints = val.into_iter().map(|i| Value::Int32(i.map(|i| i as i32)));
305
306                        Value::array(ints)
307                    }
308                    None => Value::Array(None),
309                },
310                PostgresType::INT4_ARRAY => match row.try_get(i)? {
311                    Some(val) => {
312                        let val: Vec<Option<i32>> = val;
313                        let ints = val.into_iter().map(Value::Int32);
314
315                        Value::array(ints)
316                    }
317                    None => Value::Array(None),
318                },
319                PostgresType::INT8_ARRAY => match row.try_get(i)? {
320                    Some(val) => {
321                        let val: Vec<Option<i64>> = val;
322                        let ints = val.into_iter().map(Value::Int64);
323
324                        Value::array(ints)
325                    }
326                    None => Value::Array(None),
327                },
328                PostgresType::FLOAT4_ARRAY => match row.try_get(i)? {
329                    Some(val) => {
330                        let val: Vec<Option<f32>> = val;
331                        let floats = val.into_iter().map(Value::Float);
332
333                        Value::array(floats)
334                    }
335                    None => Value::Array(None),
336                },
337                PostgresType::FLOAT8_ARRAY => match row.try_get(i)? {
338                    Some(val) => {
339                        let val: Vec<Option<f64>> = val;
340                        let floats = val.into_iter().map(Value::Double);
341
342                        Value::array(floats)
343                    }
344                    None => Value::Array(None),
345                },
346                PostgresType::BOOL_ARRAY => match row.try_get(i)? {
347                    Some(val) => {
348                        let val: Vec<Option<bool>> = val;
349                        let bools = val.into_iter().map(Value::Boolean);
350
351                        Value::array(bools)
352                    }
353                    None => Value::Array(None),
354                },
355                #[cfg(feature = "chrono")]
356                PostgresType::TIMESTAMP_ARRAY => match row.try_get(i)? {
357                    Some(val) => {
358                        let val: Vec<Option<NaiveDateTime>> = val;
359
360                        let dates =
361                            val.into_iter().map(|dt| Value::DateTime(dt.map(|dt| DateTime::<Utc>::from_utc(dt, Utc))));
362
363                        Value::array(dates)
364                    }
365                    None => Value::Array(None),
366                },
367                #[cfg(feature = "bigdecimal")]
368                PostgresType::NUMERIC_ARRAY => match row.try_get(i)? {
369                    Some(val) => {
370                        let val: Vec<Option<DecimalWrapper>> = val;
371
372                        let decimals = val
373                            .into_iter()
374                            .map(|dec| Value::Numeric(dec.map(|dec| dec.0.to_string().parse().unwrap())));
375
376                        Value::array(decimals)
377                    }
378                    None => Value::Array(None),
379                },
380                PostgresType::TEXT_ARRAY | PostgresType::NAME_ARRAY | PostgresType::VARCHAR_ARRAY => {
381                    match row.try_get(i)? {
382                        Some(val) => {
383                            let strings: Vec<Option<&str>> = val;
384
385                            Value::array(strings.into_iter().map(|s| s.map(|s| s.to_string())))
386                        }
387                        None => Value::Array(None),
388                    }
389                }
390                #[cfg(feature = "bigdecimal")]
391                PostgresType::MONEY_ARRAY => match row.try_get(i)? {
392                    Some(val) => {
393                        let val: Vec<Option<NaiveMoney>> = val;
394                        let nums = val.into_iter().map(|num| Value::Numeric(num.map(|num| num.0)));
395
396                        Value::array(nums)
397                    }
398                    None => Value::Array(None),
399                },
400                PostgresType::OID_ARRAY => match row.try_get(i)? {
401                    Some(val) => {
402                        let val: Vec<Option<u32>> = val;
403                        let nums = val.into_iter().map(|oid| Value::Int64(oid.map(|oid| oid as i64)));
404
405                        Value::array(nums)
406                    }
407                    None => Value::Array(None),
408                },
409                #[cfg(feature = "chrono")]
410                PostgresType::TIMESTAMPTZ_ARRAY => match row.try_get(i)? {
411                    Some(val) => {
412                        let val: Vec<Option<DateTime<Utc>>> = val;
413                        let dates = val.into_iter().map(Value::DateTime);
414
415                        Value::array(dates)
416                    }
417                    None => Value::Array(None),
418                },
419                #[cfg(feature = "chrono")]
420                PostgresType::DATE_ARRAY => match row.try_get(i)? {
421                    Some(val) => {
422                        let val: Vec<Option<chrono::NaiveDate>> = val;
423                        let dates = val.into_iter().map(Value::Date);
424
425                        Value::array(dates)
426                    }
427                    None => Value::Array(None),
428                },
429                #[cfg(feature = "chrono")]
430                PostgresType::TIME_ARRAY => match row.try_get(i)? {
431                    Some(val) => {
432                        let val: Vec<Option<chrono::NaiveTime>> = val;
433                        let times = val.into_iter().map(Value::Time);
434
435                        Value::array(times)
436                    }
437                    None => Value::Array(None),
438                },
439                #[cfg(feature = "chrono")]
440                PostgresType::TIMETZ_ARRAY => match row.try_get(i)? {
441                    Some(val) => {
442                        let val: Vec<Option<TimeTz>> = val;
443                        let timetzs = val.into_iter().map(|time| Value::Time(time.map(|time| time.0)));
444
445                        Value::array(timetzs)
446                    }
447                    None => Value::Array(None),
448                },
449                #[cfg(feature = "json")]
450                PostgresType::JSON_ARRAY => match row.try_get(i)? {
451                    Some(val) => {
452                        let val: Vec<Option<serde_json::Value>> = val;
453                        let jsons = val.into_iter().map(Value::Json);
454
455                        Value::array(jsons)
456                    }
457                    None => Value::Array(None),
458                },
459                #[cfg(feature = "json")]
460                PostgresType::JSONB_ARRAY => match row.try_get(i)? {
461                    Some(val) => {
462                        let val: Vec<Option<serde_json::Value>> = val;
463                        let jsons = val.into_iter().map(Value::Json);
464
465                        Value::array(jsons)
466                    }
467                    None => Value::Array(None),
468                },
469                PostgresType::OID => match row.try_get(i)? {
470                    Some(val) => {
471                        let val: u32 = val;
472                        Value::int64(val)
473                    }
474                    None => Value::Int64(None),
475                },
476                PostgresType::CHAR => match row.try_get(i)? {
477                    Some(val) => {
478                        let val: i8 = val;
479                        Value::character((val as u8) as char)
480                    }
481                    None => Value::Char(None),
482                },
483                PostgresType::INET | PostgresType::CIDR => match row.try_get(i)? {
484                    Some(val) => {
485                        let val: std::net::IpAddr = val;
486                        Value::text(val.to_string())
487                    }
488                    None => Value::Text(None),
489                },
490                PostgresType::INET_ARRAY | PostgresType::CIDR_ARRAY => match row.try_get(i)? {
491                    Some(val) => {
492                        let val: Vec<Option<std::net::IpAddr>> = val;
493                        let addrs = val.into_iter().map(|ip| Value::Text(ip.map(|ip| ip.to_string().into())));
494
495                        Value::array(addrs)
496                    }
497                    None => Value::Array(None),
498                },
499                PostgresType::BIT | PostgresType::VARBIT => match row.try_get(i)? {
500                    Some(val) => {
501                        let val: BitVec = val;
502                        Value::text(bits_to_string(&val)?)
503                    }
504                    None => Value::Text(None),
505                },
506                PostgresType::BIT_ARRAY | PostgresType::VARBIT_ARRAY => match row.try_get(i)? {
507                    Some(val) => {
508                        let val: Vec<Option<BitVec>> = val;
509                        let stringified = val
510                            .into_iter()
511                            .map(|bits| match bits {
512                                Some(bits) => bits_to_string(&bits).map(Value::text),
513                                None => Ok(Value::Text(None)),
514                            })
515                            .collect::<crate::Result<Vec<_>>>()?;
516
517                        Value::array(stringified)
518                    }
519                    None => Value::Array(None),
520                },
521                PostgresType::XML => match row.try_get(i)? {
522                    Some(val) => {
523                        let val: XmlString = val;
524                        Value::xml(val.0)
525                    }
526                    None => Value::Xml(None),
527                },
528                PostgresType::XML_ARRAY => match row.try_get(i)? {
529                    Some(val) => {
530                        let val: Vec<Option<XmlString>> = val;
531                        let xmls = val.into_iter().map(|xml| xml.map(|xml| xml.0));
532
533                        Value::array(xmls)
534                    }
535                    None => Value::Array(None),
536                },
537                ref x => match x.kind() {
538                    Kind::Enum(_) => match row.try_get(i)? {
539                        Some(val) => {
540                            let val: EnumString = val;
541
542                            Value::enum_variant(val.value)
543                        }
544                        None => Value::Enum(None),
545                    },
546                    Kind::Array(inner) => match inner.kind() {
547                        Kind::Enum(_) => match row.try_get(i)? {
548                            Some(val) => {
549                                let val: Vec<Option<EnumString>> = val;
550                                let variants = val.into_iter().map(|x| Value::Enum(x.map(|x| x.value.into())));
551
552                                Ok(Value::array(variants))
553                            }
554                            None => Ok(Value::Array(None)),
555                        },
556                        _ => match row.try_get(i) {
557                            Ok(Some(val)) => {
558                                let val: Vec<Option<String>> = val;
559                                let strings = val.into_iter().map(|str| Value::Text(str.map(Into::into)));
560
561                                Ok(Value::array(strings))
562                            }
563                            Ok(None) => Ok(Value::Array(None)),
564                            Err(err) => {
565                                if err.source().map(|err| err.is::<WrongType>()).unwrap_or(false) {
566                                    let kind = ErrorKind::UnsupportedColumnType { column_type: x.to_string() };
567
568                                    return Err(Error::builder(kind).build());
569                                } else {
570                                    Err(err)
571                                }
572                            }
573                        },
574                    }?,
575                    _ => match row.try_get(i) {
576                        Ok(Some(val)) => {
577                            let val: String = val;
578
579                            Ok(Value::text(val))
580                        }
581                        Ok(None) => Ok(Value::Text(None)),
582                        Err(err) => {
583                            if err.source().map(|err| err.is::<WrongType>()).unwrap_or(false) {
584                                let kind = ErrorKind::UnsupportedColumnType { column_type: x.to_string() };
585
586                                return Err(Error::builder(kind).build());
587                            } else {
588                                Err(err)
589                            }
590                        }
591                    }?,
592                },
593            };
594
595            Ok(result)
596        }
597
598        let num_columns = self.columns().len();
599        let mut row = Vec::with_capacity(num_columns);
600
601        for i in 0..num_columns {
602            row.push(convert(self, i)?);
603        }
604
605        Ok(row)
606    }
607}
608
609impl ToColumnNames for PostgresStatement {
610    fn to_column_names(&self) -> Vec<String> {
611        self.columns().iter().map(|c| c.name().into()).collect()
612    }
613}
614
615impl<'a> ToSql for Value<'a> {
616    fn to_sql(
617        &self,
618        ty: &PostgresType,
619        out: &mut BytesMut,
620    ) -> Result<IsNull, Box<dyn StdError + 'static + Send + Sync>> {
621        let res = match (self, ty) {
622            (Value::Int32(integer), &PostgresType::INT2) => match integer {
623                Some(i) => {
624                    let integer = i16::try_from(*i).map_err(|_| {
625                        let kind = ErrorKind::conversion(format!(
626                            "Unable to fit integer value '{i}' into an INT2 (16-bit signed integer)."
627                        ));
628
629                        Error::builder(kind).build()
630                    })?;
631
632                    Some(integer.to_sql(ty, out))
633                }
634                _ => None,
635            },
636            (Value::Int32(integer), &PostgresType::INT4) => integer.map(|integer| integer.to_sql(ty, out)),
637            (Value::Int32(integer), &PostgresType::INT8) => integer.map(|integer| (integer as i64).to_sql(ty, out)),
638            (Value::Int64(integer), &PostgresType::INT2) => match integer {
639                Some(i) => {
640                    let integer = i16::try_from(*i).map_err(|_| {
641                        let kind = ErrorKind::conversion(format!(
642                            "Unable to fit integer value '{i}' into an INT2 (16-bit signed integer)."
643                        ));
644
645                        Error::builder(kind).build()
646                    })?;
647
648                    Some(integer.to_sql(ty, out))
649                }
650                _ => None,
651            },
652            (Value::Int64(integer), &PostgresType::INT4) => match integer {
653                Some(i) => {
654                    let integer = i32::try_from(*i).map_err(|_| {
655                        let kind = ErrorKind::conversion(format!(
656                            "Unable to fit integer value '{i}' into an INT4 (32-bit signed integer)."
657                        ));
658
659                        Error::builder(kind).build()
660                    })?;
661
662                    Some(integer.to_sql(ty, out))
663                }
664                _ => None,
665            },
666            (Value::Int64(integer), &PostgresType::INT8) => integer.map(|integer| integer.to_sql(ty, out)),
667            #[cfg(feature = "bigdecimal")]
668            (Value::Int32(integer), &PostgresType::NUMERIC) => integer
669                .map(|integer| BigDecimal::from_i32(integer).unwrap())
670                .map(DecimalWrapper)
671                .map(|dw| dw.to_sql(ty, out)),
672            #[cfg(feature = "bigdecimal")]
673            (Value::Int64(integer), &PostgresType::NUMERIC) => integer
674                .map(|integer| BigDecimal::from_i64(integer).unwrap())
675                .map(DecimalWrapper)
676                .map(|dw| dw.to_sql(ty, out)),
677            (Value::Int32(integer), &PostgresType::TEXT) => integer.map(|integer| format!("{integer}").to_sql(ty, out)),
678            (Value::Int64(integer), &PostgresType::TEXT) => integer.map(|integer| format!("{integer}").to_sql(ty, out)),
679            (Value::Int32(integer), &PostgresType::OID) => match integer {
680                Some(i) => {
681                    let integer = u32::try_from(*i).map_err(|_| {
682                        let kind = ErrorKind::conversion(format!(
683                            "Unable to fit integer value '{i}' into an OID (32-bit unsigned integer)."
684                        ));
685
686                        Error::builder(kind).build()
687                    })?;
688
689                    Some(integer.to_sql(ty, out))
690                }
691                _ => None,
692            },
693            (Value::Int64(integer), &PostgresType::OID) => match integer {
694                Some(i) => {
695                    let integer = u32::try_from(*i).map_err(|_| {
696                        let kind = ErrorKind::conversion(format!(
697                            "Unable to fit integer value '{i}' into an OID (32-bit unsigned integer)."
698                        ));
699
700                        Error::builder(kind).build()
701                    })?;
702
703                    Some(integer.to_sql(ty, out))
704                }
705                _ => None,
706            },
707            (Value::Int32(integer), _) => integer.map(|integer| integer.to_sql(ty, out)),
708            (Value::Int64(integer), _) => integer.map(|integer| integer.to_sql(ty, out)),
709            (Value::Float(float), &PostgresType::FLOAT8) => float.map(|float| (float as f64).to_sql(ty, out)),
710            #[cfg(feature = "bigdecimal")]
711            (Value::Float(float), &PostgresType::NUMERIC) => {
712                float.map(|float| BigDecimal::from_f32(float).unwrap()).map(DecimalWrapper).map(|dw| dw.to_sql(ty, out))
713            }
714            (Value::Float(float), _) => float.map(|float| float.to_sql(ty, out)),
715            (Value::Double(double), &PostgresType::FLOAT4) => double.map(|double| (double as f32).to_sql(ty, out)),
716            #[cfg(feature = "bigdecimal")]
717            (Value::Double(double), &PostgresType::NUMERIC) => double
718                .map(|double| BigDecimal::from_f64(double).unwrap())
719                .map(DecimalWrapper)
720                .map(|dw| dw.to_sql(ty, out)),
721            (Value::Double(double), _) => double.map(|double| double.to_sql(ty, out)),
722            #[cfg(feature = "bigdecimal")]
723            (Value::Numeric(decimal), &PostgresType::FLOAT4) => decimal.as_ref().map(|decimal| {
724                let f = decimal.to_string().parse::<f32>().expect("decimal to f32 conversion");
725                f.to_sql(ty, out)
726            }),
727            #[cfg(feature = "bigdecimal")]
728            (Value::Numeric(decimal), &PostgresType::FLOAT8) => decimal.as_ref().map(|decimal| {
729                let f = decimal.to_string().parse::<f64>().expect("decimal to f64 conversion");
730                f.to_sql(ty, out)
731            }),
732            #[cfg(feature = "bigdecimal")]
733            (Value::Array(values), &PostgresType::FLOAT4_ARRAY) => values.as_ref().map(|values| {
734                let mut floats = Vec::with_capacity(values.len());
735
736                for value in values.iter() {
737                    let float = match value {
738                        Value::Numeric(n) => n.as_ref().and_then(|n| n.to_string().parse::<f32>().ok()),
739                        Value::Int64(n) => n.map(|n| n as f32),
740                        Value::Float(f) => *f,
741                        Value::Double(d) => d.map(|d| d as f32),
742                        v if v.is_null() => None,
743                        v => {
744                            let kind = ErrorKind::conversion(format!(
745                                "Couldn't add value of type `{v:?}` into a float array."
746                            ));
747
748                            return Err(Error::builder(kind).build().into());
749                        }
750                    };
751
752                    floats.push(float);
753                }
754
755                floats.to_sql(ty, out)
756            }),
757            #[cfg(feature = "bigdecimal")]
758            (Value::Array(values), &PostgresType::FLOAT8_ARRAY) => values.as_ref().map(|values| {
759                let mut floats = Vec::with_capacity(values.len());
760
761                for value in values.iter() {
762                    let float = match value {
763                        Value::Numeric(n) => n.as_ref().and_then(|n| n.to_string().parse::<f64>().ok()),
764                        Value::Int64(n) => n.map(|n| n as f64),
765                        Value::Float(f) => f.map(|f| f as f64),
766                        Value::Double(d) => *d,
767                        v if v.is_null() => None,
768                        v => {
769                            let kind = ErrorKind::conversion(format!(
770                                "Couldn't add value of type `{v:?}` into a double array."
771                            ));
772
773                            return Err(Error::builder(kind).build().into());
774                        }
775                    };
776
777                    floats.push(float);
778                }
779
780                floats.to_sql(ty, out)
781            }),
782            #[cfg(feature = "bigdecimal")]
783            (Value::Numeric(decimal), &PostgresType::MONEY) => decimal.as_ref().map(|decimal| {
784                let decimal = (decimal * BigInt::from_i32(100).unwrap()).round(0);
785
786                let i = decimal.to_i64().ok_or_else(|| {
787                    let kind = ErrorKind::conversion("Couldn't convert BigDecimal to i64.");
788                    Error::builder(kind).build()
789                })?;
790
791                i.to_sql(ty, out)
792            }),
793            #[cfg(feature = "bigdecimal")]
794            (Value::Numeric(decimal), &PostgresType::NUMERIC) => {
795                decimal.as_ref().map(|decimal| DecimalWrapper(decimal.clone()).to_sql(ty, out))
796            }
797            #[cfg(feature = "bigdecimal")]
798            (Value::Numeric(float), _) => float.as_ref().map(|float| DecimalWrapper(float.clone()).to_sql(ty, out)),
799            #[cfg(feature = "uuid")]
800            (Value::Text(string), &PostgresType::UUID) => string.as_ref().map(|string| {
801                let parsed_uuid: Uuid = string.parse()?;
802                parsed_uuid.to_sql(ty, out)
803            }),
804            #[cfg(feature = "uuid")]
805            (Value::Array(values), &PostgresType::UUID_ARRAY) => values.as_ref().map(|values| {
806                let parsed_uuid: Vec<Option<Uuid>> =
807                    values.iter().map(<Option<Uuid>>::try_from).collect::<crate::Result<Vec<_>>>()?;
808
809                parsed_uuid.to_sql(ty, out)
810            }),
811            (Value::Text(string), &PostgresType::INET) | (Value::Text(string), &PostgresType::CIDR) => {
812                string.as_ref().map(|string| {
813                    let parsed_ip_addr: std::net::IpAddr = string.parse()?;
814                    parsed_ip_addr.to_sql(ty, out)
815                })
816            }
817            (Value::Array(values), &PostgresType::INET_ARRAY) | (Value::Array(values), &PostgresType::CIDR_ARRAY) => {
818                values.as_ref().map(|values| {
819                    let parsed_ip_addr: Vec<Option<std::net::IpAddr>> =
820                        values.iter().map(<Option<std::net::IpAddr>>::try_from).collect::<crate::Result<_>>()?;
821
822                    parsed_ip_addr.to_sql(ty, out)
823                })
824            }
825            #[cfg(feature = "json")]
826            (Value::Text(string), &PostgresType::JSON) | (Value::Text(string), &PostgresType::JSONB) => {
827                string.as_ref().map(|string| serde_json::from_str::<serde_json::Value>(string)?.to_sql(ty, out))
828            }
829            (Value::Text(string), &PostgresType::BIT) | (Value::Text(string), &PostgresType::VARBIT) => {
830                string.as_ref().map(|string| {
831                    let bits: BitVec = string_to_bits(string)?;
832
833                    bits.to_sql(ty, out)
834                })
835            }
836            (Value::Text(string), _) => string.as_ref().map(|ref string| string.to_sql(ty, out)),
837            (Value::Array(values), &PostgresType::BIT_ARRAY) | (Value::Array(values), &PostgresType::VARBIT_ARRAY) => {
838                values.as_ref().map(|values| {
839                    let bitvecs: Vec<Option<BitVec>> =
840                        values.iter().map(<Option<BitVec>>::try_from).collect::<crate::Result<Vec<_>>>()?;
841
842                    bitvecs.to_sql(ty, out)
843                })
844            }
845            (Value::Bytes(bytes), _) => bytes.as_ref().map(|bytes| bytes.as_ref().to_sql(ty, out)),
846            (Value::Enum(string), _) => string.as_ref().map(|string| {
847                out.extend_from_slice(string.as_bytes());
848                Ok(IsNull::No)
849            }),
850            (Value::Boolean(boo), _) => boo.map(|boo| boo.to_sql(ty, out)),
851            (Value::Char(c), _) => c.map(|c| (c as i8).to_sql(ty, out)),
852            (Value::Array(vec), typ) if matches!(typ.kind(), Kind::Array(_)) => {
853                vec.as_ref().map(|vec| vec.to_sql(ty, out))
854            }
855            (Value::Array(vec), typ) => {
856                let kind = ErrorKind::conversion(format!(
857                    "Couldn't serialize value `{vec:?}` into a `{typ}`. Value is a list but `{typ}` is not."
858                ));
859
860                return Err(Error::builder(kind).build().into());
861            }
862            #[cfg(feature = "json")]
863            (Value::Json(value), _) => value.as_ref().map(|value| value.to_sql(ty, out)),
864            (Value::Xml(value), _) => value.as_ref().map(|value| value.to_sql(ty, out)),
865            #[cfg(feature = "uuid")]
866            (Value::Uuid(value), _) => value.map(|value| value.to_sql(ty, out)),
867            #[cfg(feature = "chrono")]
868            (Value::DateTime(value), &PostgresType::DATE) => value.map(|value| value.date_naive().to_sql(ty, out)),
869            #[cfg(feature = "chrono")]
870            (Value::Date(value), _) => value.map(|value| value.to_sql(ty, out)),
871            #[cfg(feature = "chrono")]
872            (Value::Time(value), _) => value.map(|value| value.to_sql(ty, out)),
873            #[cfg(feature = "chrono")]
874            (Value::DateTime(value), &PostgresType::TIME) => value.map(|value| value.time().to_sql(ty, out)),
875            #[cfg(feature = "chrono")]
876            (Value::DateTime(value), &PostgresType::TIMETZ) => value.map(|value| {
877                let result = value.time().to_sql(ty, out)?;
878                // We assume UTC. see https://www.postgresql.org/docs/9.5/datatype-datetime.html
879                out.extend_from_slice(&[0; 4]);
880                Ok(result)
881            }),
882            #[cfg(feature = "chrono")]
883            (Value::DateTime(value), _) => value.map(|value| value.naive_utc().to_sql(ty, out)),
884        };
885
886        match res {
887            Some(res) => res,
888            None => Ok(IsNull::Yes),
889        }
890    }
891
892    fn accepts(_: &PostgresType) -> bool {
893        true // Please check later should we make this to be more restricted
894    }
895
896    tokio_postgres::types::to_sql_checked!();
897}
898
899fn string_to_bits(s: &str) -> crate::Result<BitVec> {
900    use bit_vec::*;
901
902    let mut bits = BitVec::with_capacity(s.len());
903
904    for c in s.chars() {
905        match c {
906            '0' => bits.push(false),
907            '1' => bits.push(true),
908            _ => {
909                let msg = "Unexpected character for bits input. Expected only 1 and 0.";
910                let kind = ErrorKind::conversion(msg);
911
912                return Err(Error::builder(kind).build());
913            }
914        }
915    }
916
917    Ok(bits)
918}
919
920fn bits_to_string(bits: &BitVec) -> crate::Result<String> {
921    let mut s = String::with_capacity(bits.len());
922
923    for bit in bits {
924        if bit {
925            s.push('1');
926        } else {
927            s.push('0');
928        }
929    }
930
931    Ok(s)
932}
933
934impl<'a> TryFrom<&Value<'a>> for Option<BitVec> {
935    type Error = Error;
936
937    fn try_from(value: &Value<'a>) -> Result<Option<BitVec>, Self::Error> {
938        match value {
939            val @ Value::Text(Some(_)) => {
940                let text = val.as_str().unwrap();
941
942                string_to_bits(text).map(Option::Some)
943            }
944            val @ Value::Bytes(Some(_)) => {
945                let text = val.as_str().unwrap();
946
947                string_to_bits(text).map(Option::Some)
948            }
949            v if v.is_null() => Ok(None),
950            v => {
951                let kind = ErrorKind::conversion(format!("Couldn't convert value of type `{v:?}` to bit_vec::BitVec."));
952
953                Err(Error::builder(kind).build())
954            }
955        }
956    }
957}