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