1mod conversions;
4mod drivers;
5mod insert;
6mod owned;
7mod update;
8
9pub use insert::*;
10pub use owned::*;
11pub use update::*;
12
13use drizzle_core::{error::DrizzleError, sql::SQL, traits::SQLParam};
14
15#[cfg(feature = "uuid")]
16use uuid::Uuid;
17
18#[cfg(feature = "chrono")]
19use chrono::{DateTime, Duration, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime};
20
21#[cfg(feature = "cidr")]
22use cidr::{IpCidr, IpInet};
23
24#[cfg(feature = "geo-types")]
25use geo_types::{LineString, Point, Rect};
26
27#[cfg(feature = "bit-vec")]
28use bit_vec::BitVec;
29
30use std::borrow::Cow;
31
32use crate::traits::{FromPostgresValue, PostgresEnum};
33
34#[derive(Debug, Clone, PartialEq, Default)]
60pub enum PostgresValue<'a> {
61 Smallint(i16),
63 Integer(i32),
65 Bigint(i64),
67 Real(f32),
69 DoublePrecision(f64),
71 Text(Cow<'a, str>),
73 Bytea(Cow<'a, [u8]>),
75 Boolean(bool),
77 #[cfg(feature = "uuid")]
79 Uuid(Uuid),
80 #[cfg(feature = "serde")]
82 Json(serde_json::Value),
83 #[cfg(feature = "serde")]
85 Jsonb(serde_json::Value),
86 Enum(Box<dyn PostgresEnum>),
88
89 #[cfg(feature = "chrono")]
92 Date(NaiveDate),
93 #[cfg(feature = "chrono")]
95 Time(NaiveTime),
96 #[cfg(feature = "chrono")]
98 Timestamp(NaiveDateTime),
99 #[cfg(feature = "chrono")]
101 TimestampTz(DateTime<FixedOffset>),
102 #[cfg(feature = "chrono")]
104 Interval(Duration),
105
106 #[cfg(feature = "cidr")]
109 Inet(IpInet),
110 #[cfg(feature = "cidr")]
112 Cidr(IpCidr),
113 #[cfg(feature = "cidr")]
115 MacAddr([u8; 6]),
116 #[cfg(feature = "cidr")]
118 MacAddr8([u8; 8]),
119
120 #[cfg(feature = "geo-types")]
123 Point(Point<f64>),
124 #[cfg(feature = "geo-types")]
126 LineString(LineString<f64>),
127 #[cfg(feature = "geo-types")]
129 Rect(Rect<f64>),
130
131 #[cfg(feature = "bit-vec")]
134 BitVec(BitVec),
135
136 Array(Vec<PostgresValue<'a>>),
139
140 #[default]
142 Null,
143}
144
145impl<'a> std::fmt::Display for PostgresValue<'a> {
146 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147 let value = match self {
148 PostgresValue::Smallint(i) => i.to_string(),
149 PostgresValue::Integer(i) => i.to_string(),
150 PostgresValue::Bigint(i) => i.to_string(),
151 PostgresValue::Real(r) => r.to_string(),
152 PostgresValue::DoublePrecision(r) => r.to_string(),
153 PostgresValue::Text(cow) => cow.to_string(),
154 PostgresValue::Bytea(cow) => format!(
155 "\\x{}",
156 cow.iter().map(|b| format!("{:02x}", b)).collect::<String>()
157 ),
158 PostgresValue::Boolean(b) => b.to_string(),
159 #[cfg(feature = "uuid")]
160 PostgresValue::Uuid(uuid) => uuid.to_string(),
161 #[cfg(feature = "serde")]
162 PostgresValue::Json(json) => json.to_string(),
163 #[cfg(feature = "serde")]
164 PostgresValue::Jsonb(json) => json.to_string(),
165 PostgresValue::Enum(enum_val) => enum_val.variant_name().to_string(),
166
167 #[cfg(feature = "chrono")]
169 PostgresValue::Date(date) => date.format("%Y-%m-%d").to_string(),
170 #[cfg(feature = "chrono")]
171 PostgresValue::Time(time) => time.format("%H:%M:%S%.f").to_string(),
172 #[cfg(feature = "chrono")]
173 PostgresValue::Timestamp(ts) => ts.format("%Y-%m-%d %H:%M:%S%.f").to_string(),
174 #[cfg(feature = "chrono")]
175 PostgresValue::TimestampTz(ts) => ts.format("%Y-%m-%d %H:%M:%S%.f %:z").to_string(),
176 #[cfg(feature = "chrono")]
177 PostgresValue::Interval(dur) => format!("{} seconds", dur.num_seconds()),
178
179 #[cfg(feature = "cidr")]
181 PostgresValue::Inet(net) => net.to_string(),
182 #[cfg(feature = "cidr")]
183 PostgresValue::Cidr(net) => net.to_string(),
184 #[cfg(feature = "cidr")]
185 PostgresValue::MacAddr(mac) => format!(
186 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
187 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
188 ),
189 #[cfg(feature = "cidr")]
190 PostgresValue::MacAddr8(mac) => format!(
191 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
192 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], mac[6], mac[7]
193 ),
194
195 #[cfg(feature = "geo-types")]
197 PostgresValue::Point(point) => format!("({},{})", point.x(), point.y()),
198 #[cfg(feature = "geo-types")]
199 PostgresValue::LineString(line) => {
200 let coords: Vec<String> = line
201 .coords()
202 .map(|coord| format!("({},{})", coord.x, coord.y))
203 .collect();
204 format!("[{}]", coords.join(","))
205 }
206 #[cfg(feature = "geo-types")]
207 PostgresValue::Rect(rect) => {
208 format!(
209 "(({},{}),({},{}))",
210 rect.min().x,
211 rect.min().y,
212 rect.max().x,
213 rect.max().y
214 )
215 }
216
217 #[cfg(feature = "bit-vec")]
219 PostgresValue::BitVec(bv) => bv
220 .iter()
221 .map(|b| if b { '1' } else { '0' })
222 .collect::<String>(),
223
224 PostgresValue::Array(arr) => {
226 let elements: Vec<String> = arr.iter().map(|v| v.to_string()).collect();
227 format!("{{{}}}", elements.join(","))
228 }
229
230 PostgresValue::Null => String::new(),
231 };
232 write!(f, "{value}")
233 }
234}
235
236impl<'a> PostgresValue<'a> {
237 #[inline]
239 pub const fn is_null(&self) -> bool {
240 matches!(self, PostgresValue::Null)
241 }
242
243 #[inline]
245 pub const fn as_bool(&self) -> Option<bool> {
246 match self {
247 PostgresValue::Boolean(value) => Some(*value),
248 _ => None,
249 }
250 }
251
252 #[inline]
254 pub const fn as_i16(&self) -> Option<i16> {
255 match self {
256 PostgresValue::Smallint(value) => Some(*value),
257 _ => None,
258 }
259 }
260
261 #[inline]
263 pub const fn as_i32(&self) -> Option<i32> {
264 match self {
265 PostgresValue::Integer(value) => Some(*value),
266 _ => None,
267 }
268 }
269
270 #[inline]
272 pub const fn as_i64(&self) -> Option<i64> {
273 match self {
274 PostgresValue::Bigint(value) => Some(*value),
275 _ => None,
276 }
277 }
278
279 #[inline]
281 pub const fn as_f32(&self) -> Option<f32> {
282 match self {
283 PostgresValue::Real(value) => Some(*value),
284 _ => None,
285 }
286 }
287
288 #[inline]
290 pub const fn as_f64(&self) -> Option<f64> {
291 match self {
292 PostgresValue::DoublePrecision(value) => Some(*value),
293 _ => None,
294 }
295 }
296
297 #[inline]
299 pub fn as_str(&self) -> Option<&str> {
300 match self {
301 PostgresValue::Text(value) => Some(value.as_ref()),
302 _ => None,
303 }
304 }
305
306 #[inline]
308 pub fn as_bytes(&self) -> Option<&[u8]> {
309 match self {
310 PostgresValue::Bytea(value) => Some(value.as_ref()),
311 _ => None,
312 }
313 }
314
315 #[inline]
317 #[cfg(feature = "uuid")]
318 pub fn as_uuid(&self) -> Option<Uuid> {
319 match self {
320 PostgresValue::Uuid(value) => Some(*value),
321 _ => None,
322 }
323 }
324
325 #[inline]
327 #[cfg(feature = "serde")]
328 pub fn as_json(&self) -> Option<&serde_json::Value> {
329 match self {
330 PostgresValue::Json(value) => Some(value),
331 _ => None,
332 }
333 }
334
335 #[inline]
337 #[cfg(feature = "serde")]
338 pub fn as_jsonb(&self) -> Option<&serde_json::Value> {
339 match self {
340 PostgresValue::Jsonb(value) => Some(value),
341 _ => None,
342 }
343 }
344
345 #[inline]
347 pub fn as_enum(&self) -> Option<&dyn PostgresEnum> {
348 match self {
349 PostgresValue::Enum(value) => Some(value.as_ref()),
350 _ => None,
351 }
352 }
353
354 #[inline]
356 #[cfg(feature = "chrono")]
357 pub fn as_date(&self) -> Option<&NaiveDate> {
358 match self {
359 PostgresValue::Date(value) => Some(value),
360 _ => None,
361 }
362 }
363
364 #[inline]
366 #[cfg(feature = "chrono")]
367 pub fn as_time(&self) -> Option<&NaiveTime> {
368 match self {
369 PostgresValue::Time(value) => Some(value),
370 _ => None,
371 }
372 }
373
374 #[inline]
376 #[cfg(feature = "chrono")]
377 pub fn as_timestamp(&self) -> Option<&NaiveDateTime> {
378 match self {
379 PostgresValue::Timestamp(value) => Some(value),
380 _ => None,
381 }
382 }
383
384 #[inline]
386 #[cfg(feature = "chrono")]
387 pub fn as_timestamp_tz(&self) -> Option<&DateTime<FixedOffset>> {
388 match self {
389 PostgresValue::TimestampTz(value) => Some(value),
390 _ => None,
391 }
392 }
393
394 #[inline]
396 #[cfg(feature = "chrono")]
397 pub fn as_interval(&self) -> Option<&Duration> {
398 match self {
399 PostgresValue::Interval(value) => Some(value),
400 _ => None,
401 }
402 }
403
404 #[inline]
406 #[cfg(feature = "cidr")]
407 pub fn as_inet(&self) -> Option<&IpInet> {
408 match self {
409 PostgresValue::Inet(value) => Some(value),
410 _ => None,
411 }
412 }
413
414 #[inline]
416 #[cfg(feature = "cidr")]
417 pub fn as_cidr(&self) -> Option<&IpCidr> {
418 match self {
419 PostgresValue::Cidr(value) => Some(value),
420 _ => None,
421 }
422 }
423
424 #[inline]
426 #[cfg(feature = "cidr")]
427 pub const fn as_macaddr(&self) -> Option<[u8; 6]> {
428 match self {
429 PostgresValue::MacAddr(value) => Some(*value),
430 _ => None,
431 }
432 }
433
434 #[inline]
436 #[cfg(feature = "cidr")]
437 pub const fn as_macaddr8(&self) -> Option<[u8; 8]> {
438 match self {
439 PostgresValue::MacAddr8(value) => Some(*value),
440 _ => None,
441 }
442 }
443
444 #[inline]
446 #[cfg(feature = "geo-types")]
447 pub fn as_point(&self) -> Option<&Point<f64>> {
448 match self {
449 PostgresValue::Point(value) => Some(value),
450 _ => None,
451 }
452 }
453
454 #[inline]
456 #[cfg(feature = "geo-types")]
457 pub fn as_line_string(&self) -> Option<&LineString<f64>> {
458 match self {
459 PostgresValue::LineString(value) => Some(value),
460 _ => None,
461 }
462 }
463
464 #[inline]
466 #[cfg(feature = "geo-types")]
467 pub fn as_rect(&self) -> Option<&Rect<f64>> {
468 match self {
469 PostgresValue::Rect(value) => Some(value),
470 _ => None,
471 }
472 }
473
474 #[inline]
476 #[cfg(feature = "bit-vec")]
477 pub fn as_bitvec(&self) -> Option<&BitVec> {
478 match self {
479 PostgresValue::BitVec(value) => Some(value),
480 _ => None,
481 }
482 }
483
484 #[inline]
486 pub fn as_array(&self) -> Option<&[PostgresValue<'a>]> {
487 match self {
488 PostgresValue::Array(values) => Some(values),
489 _ => None,
490 }
491 }
492
493 #[inline]
495 pub fn into_owned(self) -> OwnedPostgresValue {
496 self.into()
497 }
498
499 pub fn convert<T: FromPostgresValue>(self) -> Result<T, DrizzleError> {
501 match self {
502 PostgresValue::Boolean(value) => T::from_postgres_bool(value),
503 PostgresValue::Smallint(value) => T::from_postgres_i16(value),
504 PostgresValue::Integer(value) => T::from_postgres_i32(value),
505 PostgresValue::Bigint(value) => T::from_postgres_i64(value),
506 PostgresValue::Real(value) => T::from_postgres_f32(value),
507 PostgresValue::DoublePrecision(value) => T::from_postgres_f64(value),
508 PostgresValue::Text(value) => T::from_postgres_text(&value),
509 PostgresValue::Bytea(value) => T::from_postgres_bytes(&value),
510 #[cfg(feature = "uuid")]
511 PostgresValue::Uuid(value) => T::from_postgres_uuid(value),
512 #[cfg(feature = "serde")]
513 PostgresValue::Json(value) => T::from_postgres_json(value),
514 #[cfg(feature = "serde")]
515 PostgresValue::Jsonb(value) => T::from_postgres_jsonb(value),
516 PostgresValue::Enum(value) => T::from_postgres_text(value.variant_name()),
517 #[cfg(feature = "chrono")]
518 PostgresValue::Date(value) => T::from_postgres_date(value),
519 #[cfg(feature = "chrono")]
520 PostgresValue::Time(value) => T::from_postgres_time(value),
521 #[cfg(feature = "chrono")]
522 PostgresValue::Timestamp(value) => T::from_postgres_timestamp(value),
523 #[cfg(feature = "chrono")]
524 PostgresValue::TimestampTz(value) => T::from_postgres_timestamptz(value),
525 #[cfg(feature = "chrono")]
526 PostgresValue::Interval(value) => T::from_postgres_interval(value),
527 #[cfg(feature = "cidr")]
528 PostgresValue::Inet(value) => T::from_postgres_inet(value),
529 #[cfg(feature = "cidr")]
530 PostgresValue::Cidr(value) => T::from_postgres_cidr(value),
531 #[cfg(feature = "cidr")]
532 PostgresValue::MacAddr(value) => T::from_postgres_macaddr(value),
533 #[cfg(feature = "cidr")]
534 PostgresValue::MacAddr8(value) => T::from_postgres_macaddr8(value),
535 #[cfg(feature = "geo-types")]
536 PostgresValue::Point(value) => T::from_postgres_point(value),
537 #[cfg(feature = "geo-types")]
538 PostgresValue::LineString(value) => T::from_postgres_linestring(value),
539 #[cfg(feature = "geo-types")]
540 PostgresValue::Rect(value) => T::from_postgres_rect(value),
541 #[cfg(feature = "bit-vec")]
542 PostgresValue::BitVec(value) => T::from_postgres_bitvec(value),
543 PostgresValue::Array(value) => T::from_postgres_array(value),
544 PostgresValue::Null => T::from_postgres_null(),
545 }
546 }
547
548 pub fn convert_ref<T: FromPostgresValue>(&self) -> Result<T, DrizzleError> {
550 match self {
551 PostgresValue::Boolean(value) => T::from_postgres_bool(*value),
552 PostgresValue::Smallint(value) => T::from_postgres_i16(*value),
553 PostgresValue::Integer(value) => T::from_postgres_i32(*value),
554 PostgresValue::Bigint(value) => T::from_postgres_i64(*value),
555 PostgresValue::Real(value) => T::from_postgres_f32(*value),
556 PostgresValue::DoublePrecision(value) => T::from_postgres_f64(*value),
557 PostgresValue::Text(value) => T::from_postgres_text(value),
558 PostgresValue::Bytea(value) => T::from_postgres_bytes(value),
559 #[cfg(feature = "uuid")]
560 PostgresValue::Uuid(value) => T::from_postgres_uuid(*value),
561 #[cfg(feature = "serde")]
562 PostgresValue::Json(value) => T::from_postgres_json(value.clone()),
563 #[cfg(feature = "serde")]
564 PostgresValue::Jsonb(value) => T::from_postgres_jsonb(value.clone()),
565 PostgresValue::Enum(value) => T::from_postgres_text(value.variant_name()),
566 #[cfg(feature = "chrono")]
567 PostgresValue::Date(value) => T::from_postgres_date(*value),
568 #[cfg(feature = "chrono")]
569 PostgresValue::Time(value) => T::from_postgres_time(*value),
570 #[cfg(feature = "chrono")]
571 PostgresValue::Timestamp(value) => T::from_postgres_timestamp(*value),
572 #[cfg(feature = "chrono")]
573 PostgresValue::TimestampTz(value) => T::from_postgres_timestamptz(*value),
574 #[cfg(feature = "chrono")]
575 PostgresValue::Interval(value) => T::from_postgres_interval(*value),
576 #[cfg(feature = "cidr")]
577 PostgresValue::Inet(value) => T::from_postgres_inet(*value),
578 #[cfg(feature = "cidr")]
579 PostgresValue::Cidr(value) => T::from_postgres_cidr(*value),
580 #[cfg(feature = "cidr")]
581 PostgresValue::MacAddr(value) => T::from_postgres_macaddr(*value),
582 #[cfg(feature = "cidr")]
583 PostgresValue::MacAddr8(value) => T::from_postgres_macaddr8(*value),
584 #[cfg(feature = "geo-types")]
585 PostgresValue::Point(value) => T::from_postgres_point(*value),
586 #[cfg(feature = "geo-types")]
587 PostgresValue::LineString(value) => T::from_postgres_linestring(value.clone()),
588 #[cfg(feature = "geo-types")]
589 PostgresValue::Rect(value) => T::from_postgres_rect(*value),
590 #[cfg(feature = "bit-vec")]
591 PostgresValue::BitVec(value) => T::from_postgres_bitvec(value.clone()),
592 PostgresValue::Array(value) => T::from_postgres_array(value.clone()),
593 PostgresValue::Null => T::from_postgres_null(),
594 }
595 }
596}
597
598impl<'a> SQLParam for PostgresValue<'a> {
600 const DIALECT: drizzle_core::dialect::Dialect = drizzle_core::dialect::Dialect::PostgreSQL;
601}
602
603impl<'a> From<PostgresValue<'a>> for SQL<'a, PostgresValue<'a>> {
604 fn from(value: PostgresValue<'a>) -> Self {
605 SQL::param(value)
606 }
607}
608
609impl<'a> From<PostgresValue<'a>> for Cow<'a, PostgresValue<'a>> {
611 fn from(value: PostgresValue<'a>) -> Self {
612 Cow::Owned(value)
613 }
614}
615
616impl<'a> From<&'a PostgresValue<'a>> for Cow<'a, PostgresValue<'a>> {
617 fn from(value: &'a PostgresValue<'a>) -> Self {
618 Cow::Borrowed(value)
619 }
620}