1use std::borrow::Cow;
6use std::fmt;
7
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
12#[non_exhaustive]
13pub enum Value {
14 #[default]
16 Null,
17
18 Bool(bool),
20
21 I8(i8),
23
24 I16(i16),
26
27 I32(i32),
29
30 I64(i64),
32
33 U8(u8),
35
36 U16(u16),
38
39 U32(u32),
41
42 U64(u64),
44
45 F32(f32),
47
48 F64(f64),
50
51 Decimal(String),
53
54 String(String),
56
57 Bytes(Vec<u8>),
59
60 Uuid(String),
62
63 Date(String),
65
66 DateTime(String),
68
69 Time(String),
71
72 Json(String),
74
75 Array(Vec<Value>),
77
78 Object(std::collections::HashMap<String, Value>),
80}
81
82pub trait FromQueryResult: Sized {
110 fn from_value(_value: &Value) -> Result<Self, String> {
116 Err(
117 "from_value not implemented for this type; use from_query_result for structs"
118 .to_string(),
119 )
120 }
121
122 fn from_row(row: &std::collections::HashMap<String, Value>) -> Result<Self, String> {
124 Self::from_query_result(row)
125 }
126
127 fn from_query_result(_row: &std::collections::HashMap<String, Value>) -> Result<Self, String> {
129 Err("from_query_result not implemented for this type".to_string())
130 }
131
132 fn row_desc() -> Vec<&'static str> {
137 Vec::new()
138 }
139
140 fn column_types() -> &'static [(&'static str, &'static str)] {
149 &[]
150 }
151}
152
153pub trait ColumnTrait {
166 fn as_str(&self) -> &'static str;
168 fn all() -> Vec<Self>
170 where
171 Self: Sized;
172}
173
174pub const fn __sz_orm_const_str_eq(a: &str, b: &str) -> bool {
179 if a.len() != b.len() {
180 return false;
181 }
182 let ab = a.as_bytes();
183 let bb = b.as_bytes();
184 let mut i = 0;
185 while i < ab.len() {
186 if ab[i] != bb[i] {
187 return false;
188 }
189 i += 1;
190 }
191 true
192}
193
194pub const fn __sz_orm_const_types_compatible(
200 actual_db_type: &str,
201 expected_rust_type: &str,
202) -> bool {
203 const fn ci_eq(t: &str, pat: &[u8]) -> bool {
205 let tb = t.as_bytes();
206 if tb.len() != pat.len() {
207 return false;
208 }
209 let mut i = 0;
210 while i < tb.len() {
211 let c = tb[i];
212 let u = if c >= b'a' && c <= b'z' { c - 32 } else { c };
213 if u != pat[i] {
214 return false;
215 }
216 i += 1;
217 }
218 true
219 }
220 const fn classify(t: &str) -> u8 {
221 if ci_eq(t, b"BOOLEAN") || ci_eq(t, b"BOOL") {
222 1
223 } else if ci_eq(t, b"TINYINT") {
224 2
225 } else if ci_eq(t, b"SMALLINT") || ci_eq(t, b"INT2") {
226 3
227 } else if ci_eq(t, b"INT")
228 || ci_eq(t, b"INT4")
229 || ci_eq(t, b"OID")
230 || ci_eq(t, b"MEDIUMINT")
231 || ci_eq(t, b"INTEGER")
232 {
233 4
234 } else if ci_eq(t, b"BIGINT") || ci_eq(t, b"INT8") {
235 5
236 } else if ci_eq(t, b"TINYINT UNSIGNED") {
237 6
238 } else if ci_eq(t, b"SMALLINT UNSIGNED") {
239 7
240 } else if ci_eq(t, b"INT UNSIGNED") || ci_eq(t, b"MEDIUMINT UNSIGNED") {
241 8
242 } else if ci_eq(t, b"BIGINT UNSIGNED") {
243 9
244 } else if ci_eq(t, b"FLOAT") || ci_eq(t, b"FLOAT4") || ci_eq(t, b"REAL") {
245 10
246 } else if ci_eq(t, b"DOUBLE") || ci_eq(t, b"FLOAT8") {
247 11
248 } else if ci_eq(t, b"DECIMAL")
249 || ci_eq(t, b"NUMERIC")
250 || ci_eq(t, b"NEWDECIMAL")
251 || ci_eq(t, b"MONEY")
252 {
253 12
254 } else if ci_eq(t, b"TEXT")
255 || ci_eq(t, b"VARCHAR")
256 || ci_eq(t, b"CHAR")
257 || ci_eq(t, b"NAME")
258 || ci_eq(t, b"CLOB")
259 || ci_eq(t, b"STRING")
260 {
261 13
262 } else if ci_eq(t, b"BLOB")
263 || ci_eq(t, b"BYTEA")
264 || ci_eq(t, b"BINARY")
265 || ci_eq(t, b"VARBINARY")
266 {
267 14
268 } else if ci_eq(t, b"DATE") {
269 15
270 } else if ci_eq(t, b"DATETIME") || ci_eq(t, b"TIMESTAMP") || ci_eq(t, b"TIMESTAMPTZ") {
271 16
272 } else if ci_eq(t, b"TIME") || ci_eq(t, b"TIMETZ") {
273 17
274 } else if ci_eq(t, b"JSON") || ci_eq(t, b"JSONB") {
275 18
276 } else if ci_eq(t, b"UUID") {
277 19
278 } else {
279 0
280 }
281 }
282 let a = classify(actual_db_type);
283 let b = classify(expected_rust_type);
284 a == b || a == 0 || b == 0
285}
286
287macro_rules! impl_from_query_result_int {
290 ($t:ty, $variant:ident) => {
291 impl FromQueryResult for $t {
292 fn from_value(value: &Value) -> Result<Self, String> {
293 match value {
294 Value::$variant(n) => Ok(*n as $t),
297 Value::Null => Err("NULL value cannot be converted to integer".to_string()),
298 other => Err(format!("cannot convert {:?} to {}", other, stringify!($t))),
299 }
300 }
301 }
302 };
303}
304
305impl_from_query_result_int!(i64, I64);
306impl_from_query_result_int!(i32, I32);
307impl_from_query_result_int!(i16, I16);
308impl_from_query_result_int!(i8, I8);
309impl_from_query_result_int!(u64, U64);
310impl_from_query_result_int!(u32, U32);
311impl_from_query_result_int!(u16, U16);
312impl_from_query_result_int!(u8, U8);
313
314macro_rules! impl_from_query_result_float {
315 ($t:ty, $variant:ident) => {
316 impl FromQueryResult for $t {
317 fn from_value(value: &Value) -> Result<Self, String> {
318 match value {
319 Value::$variant(n) => Ok(*n as $t),
320 Value::Null => Err("NULL value cannot be converted to float".to_string()),
321 other => Err(format!("cannot convert {:?} to {}", other, stringify!($t))),
322 }
323 }
324 }
325 };
326}
327
328impl_from_query_result_float!(f64, F64);
329impl_from_query_result_float!(f32, F32);
330
331impl FromQueryResult for bool {
332 fn from_value(value: &Value) -> Result<Self, String> {
333 match value {
334 Value::Bool(b) => Ok(*b),
335 Value::I64(n) => Ok(*n != 0),
336 Value::Null => Err("NULL value cannot be converted to bool".to_string()),
337 other => Err(format!("cannot convert {:?} to bool", other)),
338 }
339 }
340}
341
342impl FromQueryResult for String {
343 fn from_value(value: &Value) -> Result<Self, String> {
344 match value {
345 Value::String(s) => Ok(s.clone()),
346 Value::Decimal(s) => Ok(s.clone()),
347 Value::Uuid(s) => Ok(s.clone()),
348 Value::Date(s) => Ok(s.clone()),
349 Value::DateTime(s) => Ok(s.clone()),
350 Value::Time(s) => Ok(s.clone()),
351 Value::Json(s) => Ok(s.clone()),
352 Value::Null => Err("NULL value cannot be converted to String".to_string()),
353 other => Err(format!("cannot convert {:?} to String", other)),
354 }
355 }
356}
357
358impl<T: FromQueryResult> FromQueryResult for Option<T> {
359 fn from_value(value: &Value) -> Result<Self, String> {
360 match value {
361 Value::Null => Ok(None),
362 other => T::from_value(other).map(Some),
363 }
364 }
365}
366
367impl FromQueryResult for () {
369 fn from_value(_value: &Value) -> Result<Self, String> {
370 Ok(())
371 }
372}
373
374pub fn rows_to<T: FromQueryResult>(rows: &crate::pool::QueryRows) -> Result<Vec<T>, String> {
386 rows.iter().map(T::from_query_result).collect()
387}
388
389impl Value {
390 pub fn is_null(&self) -> bool {
392 matches!(self, Value::Null)
393 }
394
395 pub fn is_bool(&self) -> bool {
397 matches!(self, Value::Bool(_))
398 }
399
400 pub fn is_i64(&self) -> bool {
402 matches!(self, Value::I64(_))
403 }
404
405 pub fn is_f64(&self) -> bool {
407 matches!(self, Value::F64(_))
408 }
409
410 pub fn is_string(&self) -> bool {
412 matches!(self, Value::String(_))
413 }
414
415 pub fn is_bytes(&self) -> bool {
417 matches!(self, Value::Bytes(_))
418 }
419
420 pub fn is_object(&self) -> bool {
422 matches!(self, Value::Object(_))
423 }
424
425 pub fn from_map(map: std::collections::HashMap<String, Value>) -> Self {
427 Value::Object(map)
428 }
429
430 pub fn as_str(&self) -> Option<&str> {
432 match self {
433 Value::String(s) => Some(s),
434 Value::Decimal(s) => Some(s),
435 _ => None,
436 }
437 }
438
439 pub fn as_i64(&self) -> Option<i64> {
443 match self {
444 Value::I8(v) => Some(*v as i64),
445 Value::I16(v) => Some(*v as i64),
446 Value::I32(v) => Some(*v as i64),
447 Value::I64(v) => Some(*v),
448 Value::U8(v) => Some(*v as i64),
449 Value::U16(v) => Some(*v as i64),
450 Value::U32(v) => Some(*v as i64),
451 Value::U64(v) => i64::try_from(*v).ok(),
452 Value::F32(v) => Some(*v as i64),
453 Value::F64(v) => Some(*v as i64),
454 Value::Bool(v) => Some(if *v { 1 } else { 0 }),
455 Value::String(s) => s.parse::<i64>().ok(),
456 Value::Decimal(s) => s.parse::<i64>().ok(),
457 _ => None,
458 }
459 }
460
461 pub fn as_f64(&self) -> Option<f64> {
464 match self {
465 Value::F32(v) => Some(*v as f64),
466 Value::F64(v) => Some(*v),
467 Value::I8(v) => Some(*v as f64),
468 Value::I16(v) => Some(*v as f64),
469 Value::I32(v) => Some(*v as f64),
470 Value::I64(v) => Some(*v as f64),
471 Value::U8(v) => Some(*v as f64),
472 Value::U16(v) => Some(*v as f64),
473 Value::U32(v) => Some(*v as f64),
474 Value::U64(v) => Some(*v as f64),
475 Value::Bool(v) => Some(if *v { 1.0 } else { 0.0 }),
476 Value::Decimal(s) => s.parse::<f64>().ok(),
477 _ => None,
478 }
479 }
480
481 pub fn as_bool(&self) -> Option<bool> {
484 match self {
485 Value::Bool(v) => Some(*v),
486 Value::I8(v) => Some(*v != 0),
487 Value::I16(v) => Some(*v != 0),
488 Value::I32(v) => Some(*v != 0),
489 Value::I64(v) => Some(*v != 0),
490 Value::U8(v) => Some(*v != 0),
491 Value::U16(v) => Some(*v != 0),
492 Value::U32(v) => Some(*v != 0),
493 Value::U64(v) => Some(*v != 0),
494 Value::F32(v) => Some(*v != 0.0),
495 Value::F64(v) => Some(*v != 0.0),
496 Value::String(s) => match s.to_lowercase().as_str() {
497 "1" | "true" | "yes" | "on" => Some(true),
498 "0" | "false" | "no" | "off" => Some(false),
499 _ => None,
500 },
501 Value::Null => Some(false),
502 _ => None,
503 }
504 }
505
506 pub fn as_bytes(&self) -> Option<&[u8]> {
509 match self {
510 Value::Bytes(v) => Some(v),
511 Value::String(s) => Some(s.as_bytes()),
512 _ => None,
513 }
514 }
515
516 pub fn to_param(&self) -> Cow<'_, str> {
526 match self {
527 Value::Null => Cow::Borrowed("NULL"),
528 Value::Bool(b) => Cow::Owned(if *b { "TRUE" } else { "FALSE" }.to_string()),
529 Value::I8(v) => Cow::Owned(v.to_string()),
530 Value::I16(v) => Cow::Owned(v.to_string()),
531 Value::I32(v) => Cow::Owned(v.to_string()),
532 Value::I64(v) => Cow::Owned(v.to_string()),
533 Value::U8(v) => Cow::Owned(v.to_string()),
534 Value::U16(v) => Cow::Owned(v.to_string()),
535 Value::U32(v) => Cow::Owned(v.to_string()),
536 Value::U64(v) => Cow::Owned(v.to_string()),
537 Value::F32(v) => Cow::Owned(v.to_string()),
538 Value::F64(v) => Cow::Owned(v.to_string()),
539 Value::Decimal(s) => Cow::Owned(s.clone()),
540 Value::String(s) => Cow::Owned(format!("'{}'", escape_string(s))),
541 Value::Bytes(b) => Cow::Owned(format!("X'{}'", hex_encode(b))),
542 Value::Uuid(s) => Cow::Owned(format!("'{}'", escape_string(s))),
543 Value::Date(s) => Cow::Owned(format!("'{}'", escape_string(s))),
544 Value::DateTime(s) => Cow::Owned(format!("'{}'", escape_string(s))),
545 Value::Time(s) => Cow::Owned(format!("'{}'", escape_string(s))),
546 Value::Json(s) => Cow::Owned(format!("'{}'", escape_string(s))),
547 Value::Array(arr) => {
548 let params: Vec<String> = arr.iter().map(|v| v.to_param().into_owned()).collect();
549 Cow::Owned(format!("({})", params.join(", ")))
550 }
551 Value::Object(_) => Cow::Borrowed("NULL"),
552 }
553 }
554
555 pub fn to_param_with_dialect(&self, dialect: &dyn crate::dialect::Dialect) -> Cow<'_, str> {
573 match self {
574 Value::Null => Cow::Borrowed("NULL"),
575 Value::Bool(b) => Cow::Owned(if *b { "TRUE" } else { "FALSE" }.to_string()),
576 Value::I8(v) => Cow::Owned(v.to_string()),
577 Value::I16(v) => Cow::Owned(v.to_string()),
578 Value::I32(v) => Cow::Owned(v.to_string()),
579 Value::I64(v) => Cow::Owned(v.to_string()),
580 Value::U8(v) => Cow::Owned(v.to_string()),
581 Value::U16(v) => Cow::Owned(v.to_string()),
582 Value::U32(v) => Cow::Owned(v.to_string()),
583 Value::U64(v) => Cow::Owned(v.to_string()),
584 Value::F32(v) => Cow::Owned(v.to_string()),
585 Value::F64(v) => Cow::Owned(v.to_string()),
586 Value::Decimal(s) => Cow::Owned(s.clone()),
587 Value::String(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
588 Value::Bytes(b) => Cow::Owned(format!("X'{}'", hex_encode(b))),
589 Value::Uuid(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
590 Value::Date(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
591 Value::DateTime(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
592 Value::Time(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
593 Value::Json(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
594 Value::Array(arr) => {
595 let params: Vec<String> = arr
596 .iter()
597 .map(|v| v.to_param_with_dialect(dialect).into_owned())
598 .collect();
599 Cow::Owned(format!("({})", params.join(", ")))
600 }
601 Value::Object(_) => Cow::Borrowed("NULL"),
602 }
603 }
604
605 pub fn from<T: Into<Value>>(v: T) -> Self {
607 v.into()
608 }
609}
610
611impl fmt::Display for Value {
612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 match self {
614 Value::Null => write!(f, "NULL"),
615 Value::Bool(b) => write!(f, "{}", b),
616 Value::I8(v) => write!(f, "{}", v),
617 Value::I16(v) => write!(f, "{}", v),
618 Value::I32(v) => write!(f, "{}", v),
619 Value::I64(v) => write!(f, "{}", v),
620 Value::U8(v) => write!(f, "{}", v),
621 Value::U16(v) => write!(f, "{}", v),
622 Value::U32(v) => write!(f, "{}", v),
623 Value::U64(v) => write!(f, "{}", v),
624 Value::F32(v) => write!(f, "{}", v),
625 Value::F64(v) => write!(f, "{}", v),
626 Value::Decimal(v) => write!(f, "{}", v),
627 Value::String(v) => write!(f, "'{}'", v),
628 Value::Bytes(v) => write!(f, "X'{}'", hex_encode(v)),
629 Value::Uuid(v) => write!(f, "'{}'", v),
630 Value::Date(v) => write!(f, "'{}'", v),
631 Value::DateTime(v) => write!(f, "'{}'", v),
632 Value::Time(v) => write!(f, "'{}'", v),
633 Value::Json(v) => write!(f, "'{}'", v),
634 Value::Array(v) => {
635 let items: Vec<String> = v.iter().map(|i| format!("{}", i)).collect();
636 write!(f, "({})", items.join(", "))
637 }
638 Value::Object(map) => {
639 let items: Vec<String> = map.iter().map(|(k, v)| format!("{}: {}", k, v)).collect();
640 write!(f, "{{{}}}", items.join(", "))
641 }
642 }
643 }
644}
645
646impl From<()> for Value {
647 fn from(_: ()) -> Self {
648 Value::Null
649 }
650}
651
652impl From<bool> for Value {
653 fn from(v: bool) -> Self {
654 Value::Bool(v)
655 }
656}
657
658impl From<i8> for Value {
659 fn from(v: i8) -> Self {
660 Value::I8(v)
661 }
662}
663
664impl From<i16> for Value {
665 fn from(v: i16) -> Self {
666 Value::I16(v)
667 }
668}
669
670impl From<i32> for Value {
671 fn from(v: i32) -> Self {
672 Value::I32(v)
673 }
674}
675
676impl From<i64> for Value {
677 fn from(v: i64) -> Self {
678 Value::I64(v)
679 }
680}
681
682impl From<u8> for Value {
683 fn from(v: u8) -> Self {
684 Value::U8(v)
685 }
686}
687
688impl From<u16> for Value {
689 fn from(v: u16) -> Self {
690 Value::U16(v)
691 }
692}
693
694impl From<u32> for Value {
695 fn from(v: u32) -> Self {
696 Value::U32(v)
697 }
698}
699
700impl From<u64> for Value {
701 fn from(v: u64) -> Self {
702 Value::U64(v)
703 }
704}
705
706impl From<f32> for Value {
707 fn from(v: f32) -> Self {
708 Value::F32(v)
709 }
710}
711
712impl From<f64> for Value {
713 fn from(v: f64) -> Self {
714 Value::F64(v)
715 }
716}
717
718impl From<String> for Value {
719 fn from(v: String) -> Self {
720 Value::String(v)
721 }
722}
723
724impl From<&str> for Value {
725 fn from(v: &str) -> Self {
726 Value::String(v.to_string())
727 }
728}
729
730impl From<Vec<u8>> for Value {
731 fn from(v: Vec<u8>) -> Self {
732 Value::Bytes(v)
733 }
734}
735
736impl From<&[u8]> for Value {
737 fn from(v: &[u8]) -> Self {
738 Value::Bytes(v.to_vec())
739 }
740}
741
742impl From<Vec<Value>> for Value {
743 fn from(v: Vec<Value>) -> Self {
744 Value::Array(v)
745 }
746}
747
748fn escape_string(s: &str) -> String {
770 let mut escaped = String::with_capacity(s.len() + s.chars().filter(|&c| c == '\'').count());
771 for c in s.chars() {
772 if c == '\'' {
773 escaped.push_str("''");
774 } else {
775 escaped.push(c);
776 }
777 }
778 escaped
779}
780
781fn hex_encode(bytes: &[u8]) -> String {
782 bytes.iter().map(|b| format!("{:02x}", b)).collect()
783}
784
785#[derive(Debug, Clone, Copy, PartialEq, Eq)]
796#[non_exhaustive]
797pub enum ColType {
798 Bool,
800 I8,
802 I16,
804 I32,
806 I64,
808 U8,
810 U16,
812 U32,
814 U64,
816 F32,
818 F64,
820 Decimal,
822 String,
824 Bytes,
826 Date,
828 DateTime,
830 Time,
832 Json,
834 Uuid,
836 Unknown,
838}
839
840impl ColType {
841 pub fn from_type_name(type_name: &str) -> Self {
853 match type_name {
854 "BOOLEAN" | "BOOL" => Self::Bool,
855 "TINYINT" => Self::I8,
856 "SMALLINT" | "INT2" => Self::I16,
857 "INT" | "INT4" | "OID" | "MEDIUMINT" | "INTEGER" => Self::I32,
858 "BIGINT" | "INT8" => Self::I64,
859 "TINYINT UNSIGNED" => Self::U8,
860 "SMALLINT UNSIGNED" => Self::U16,
861 "INT UNSIGNED" | "MEDIUMINT UNSIGNED" => Self::U32,
862 "BIGINT UNSIGNED" => Self::U64,
863 "FLOAT" | "FLOAT4" | "REAL" => Self::F32,
864 "DOUBLE" | "FLOAT8" => Self::F64,
865 "DECIMAL" | "NUMERIC" | "NEWDECIMAL" | "MONEY" => Self::Decimal,
866 "TEXT" | "VARCHAR" | "CHAR" | "NAME" => Self::String,
867 "BLOB" | "BYTEA" => Self::Bytes,
868 "DATE" => Self::Date,
869 "DATETIME" | "TIMESTAMP" => Self::DateTime,
870 "TIME" => Self::Time,
871 "JSON" => Self::Json,
872 "UUID" => Self::Uuid,
873 _ => Self::Unknown,
874 }
875 }
876
877 pub fn parse_sqlite(type_name: &str) -> Self {
893 if type_name.is_empty() {
895 return Self::Unknown;
896 }
897 match type_name.to_uppercase().as_str() {
898 "INTEGER" | "INT" | "BIGINT" | "INT8" | "INT4" | "INT2" | "TINYINT" | "SMALLINT"
900 | "MEDIUMINT" => Self::I64,
901 "BOOLEAN" | "BOOL" => Self::Bool,
902 "REAL" | "FLOAT" | "DOUBLE" | "FLOAT8" | "DOUBLE PRECISION" => Self::F64,
903 "DECIMAL" | "NUMERIC" => Self::Decimal,
904 "TEXT" | "CLOB" | "VARCHAR" | "CHAR" | "NAME" => Self::String,
905 "BLOB" => Self::Bytes,
906 "DATE" => Self::Date,
907 "DATETIME" | "TIMESTAMP" => Self::DateTime,
908 "TIME" => Self::Time,
909 "JSON" => Self::Json,
910 _ => Self::Unknown,
911 }
912 }
913
914 pub fn parse_mysql(type_name: &str) -> Self {
918 match type_name.to_uppercase().as_str() {
919 "TINYINT" => Self::I8,
920 "SMALLINT" => Self::I16,
921 "INT" | "INTEGER" | "MEDIUMINT" => Self::I32,
922 "BIGINT" => Self::I64,
923 "TINYINT UNSIGNED" => Self::U8,
924 "SMALLINT UNSIGNED" => Self::U16,
925 "INT UNSIGNED" | "MEDIUMINT UNSIGNED" => Self::U32,
926 "BIGINT UNSIGNED" => Self::U64,
927 "FLOAT" => Self::F32,
928 "DOUBLE" => Self::F64,
929 "DECIMAL" | "NUMERIC" | "NEWDECIMAL" => Self::Decimal,
930 "VARCHAR" | "CHAR" | "TEXT" | "TINYTEXT" | "MEDIUMTEXT" | "LONGTEXT" | "ENUM"
931 | "SET" => Self::String,
932 "BLOB" | "TINYBLOB" | "MEDIUMBLOB" | "LONGBLOB" | "BINARY" | "VARBINARY" => Self::Bytes,
933 "DATE" => Self::Date,
934 "DATETIME" | "TIMESTAMP" => Self::DateTime,
935 "TIME" => Self::Time,
936 "YEAR" => Self::I16,
937 "JSON" => Self::Json,
938 "BOOLEAN" | "BOOL" => Self::Bool,
939 _ => Self::from_type_name(type_name),
940 }
941 }
942
943 pub fn parse_postgres(type_name: &str) -> Self {
947 match type_name.to_uppercase().as_str() {
948 "BOOL" => Self::Bool,
949 "INT2" | "SMALLINT" => Self::I16,
950 "INT4" | "INTEGER" | "INT" => Self::I32,
951 "INT8" | "BIGINT" => Self::I64,
952 "FLOAT4" | "REAL" => Self::F32,
953 "FLOAT8" | "DOUBLE PRECISION" => Self::F64,
954 "NUMERIC" | "DECIMAL" | "MONEY" => Self::Decimal,
955 "TEXT" | "VARCHAR" | "CHAR" | "BPCHAR" | "NAME" | "CITEXT" => Self::String,
956 "BYTEA" => Self::Bytes,
957 "DATE" => Self::Date,
958 "TIMESTAMP" | "TIMESTAMPTZ" => Self::DateTime,
959 "TIME" | "TIMETZ" => Self::Time,
960 "JSON" | "JSONB" => Self::Json,
961 "UUID" => Self::Uuid,
962 "OID" => Self::I32,
963 _ => Self::from_type_name(type_name),
964 }
965 }
966}
967
968pub type QueryValues = (Vec<String>, Vec<Vec<Value>>);
988
989#[cfg(test)]
990mod tests {
991 use super::*;
992
993 #[test]
994 fn test_value_is_null() {
995 assert!(Value::Null.is_null());
996 assert!(!Value::I64(0).is_null());
997 }
998
999 #[test]
1002 fn test_const_str_eq() {
1003 assert!(__sz_orm_const_str_eq("id", "id"));
1004 assert!(__sz_orm_const_str_eq("user_id", "user_id"));
1005 assert!(!__sz_orm_const_str_eq("id", "ID"));
1006 assert!(!__sz_orm_const_str_eq("id", "idd"));
1007 assert!(!__sz_orm_const_str_eq("", "id"));
1008 assert!(__sz_orm_const_str_eq("", ""));
1009 }
1010
1011 #[test]
1012 fn test_const_types_compatible_same_category() {
1013 assert!(__sz_orm_const_types_compatible("BIGINT", "BIGINT"));
1015 assert!(__sz_orm_const_types_compatible("bigint", "BIGINT"));
1016 assert!(__sz_orm_const_types_compatible("INT8", "BIGINT")); assert!(__sz_orm_const_types_compatible("varchar", "TEXT"));
1018 assert!(__sz_orm_const_types_compatible("VARCHAR", "VARCHAR"));
1019 assert!(__sz_orm_const_types_compatible("timestamp", "DATETIME"));
1020 assert!(__sz_orm_const_types_compatible("int4", "INT"));
1021 assert!(__sz_orm_const_types_compatible("jsonb", "JSON"));
1022 assert!(__sz_orm_const_types_compatible("numeric", "DECIMAL"));
1023 }
1024
1025 #[test]
1026 fn test_const_types_compatible_different_category() {
1027 assert!(!__sz_orm_const_types_compatible("BIGINT", "TEXT"));
1029 assert!(!__sz_orm_const_types_compatible("VARCHAR", "INT"));
1030 assert!(!__sz_orm_const_types_compatible("JSON", "BIGINT"));
1031 assert!(!__sz_orm_const_types_compatible("BLOB", "DATE"));
1032 assert!(!__sz_orm_const_types_compatible("DOUBLE", "INT"));
1033 }
1034
1035 #[test]
1036 fn test_const_types_compatible_unknown_tolerant() {
1037 assert!(__sz_orm_const_types_compatible("CUSTOM_TYPE", "BIGINT"));
1039 assert!(__sz_orm_const_types_compatible("BIGINT", "CUSTOM_TYPE"));
1040 assert!(__sz_orm_const_types_compatible("UNKNOWN1", "UNKNOWN2"));
1041 }
1042
1043 #[test]
1044 fn test_col_type_from_type_name() {
1045 assert_eq!(ColType::from_type_name("BOOLEAN"), ColType::Bool);
1047 assert_eq!(ColType::from_type_name("TINYINT"), ColType::I8);
1048 assert_eq!(ColType::from_type_name("SMALLINT"), ColType::I16);
1049 assert_eq!(ColType::from_type_name("INT"), ColType::I32);
1050 assert_eq!(ColType::from_type_name("BIGINT"), ColType::I64);
1051 assert_eq!(ColType::from_type_name("INT UNSIGNED"), ColType::U32);
1052 assert_eq!(ColType::from_type_name("FLOAT"), ColType::F32);
1053 assert_eq!(ColType::from_type_name("DOUBLE"), ColType::F64);
1054 assert_eq!(ColType::from_type_name("TEXT"), ColType::String);
1055 assert_eq!(ColType::from_type_name("BLOB"), ColType::Bytes);
1056 assert_eq!(ColType::from_type_name("DATE"), ColType::Date);
1057 assert_eq!(ColType::from_type_name("TIMESTAMP"), ColType::DateTime);
1058 assert_eq!(ColType::from_type_name("JSON"), ColType::Json);
1059 assert_eq!(ColType::from_type_name("INT2"), ColType::I16);
1061 assert_eq!(ColType::from_type_name("INT4"), ColType::I32);
1062 assert_eq!(ColType::from_type_name("INT8"), ColType::I64);
1063 assert_eq!(ColType::from_type_name("FLOAT4"), ColType::F32);
1064 assert_eq!(ColType::from_type_name("FLOAT8"), ColType::F64);
1065 assert_eq!(ColType::from_type_name("BYTEA"), ColType::Bytes);
1066 assert_eq!(ColType::from_type_name("UNKNOWN_TYPE"), ColType::Unknown);
1068 assert_eq!(ColType::from_type_name(""), ColType::Unknown);
1069 }
1070
1071 #[test]
1072 fn test_value_as_i64() {
1073 assert_eq!(Value::I64(42).as_i64(), Some(42));
1074 assert_eq!(Value::I32(42).as_i64(), Some(42));
1075 assert_eq!(Value::Bool(true).as_i64(), Some(1));
1076 assert!(Value::String("test".to_string()).as_i64().is_none());
1077 }
1078
1079 #[test]
1080 fn test_value_as_f64() {
1081 assert_eq!(Value::F64(2.5).as_f64(), Some(2.5));
1082 assert_eq!(Value::I64(42).as_f64(), Some(42.0));
1083 }
1084
1085 #[test]
1086 fn test_value_as_str() {
1087 assert_eq!(Value::String("hello".to_string()).as_str(), Some("hello"));
1088 }
1089
1090 #[test]
1091 fn test_value_to_param() {
1092 assert_eq!(Value::Null.to_param(), "NULL");
1093 assert_eq!(Value::Bool(true).to_param(), "TRUE");
1094 assert_eq!(Value::I64(42).to_param(), "42");
1095 assert_eq!(Value::String("test".to_string()).to_param(), "'test'");
1096 assert_eq!(Value::String("it's".to_string()).to_param(), "'it''s'");
1097 }
1098
1099 #[test]
1100 fn test_value_into() {
1101 let v: Value = 42i64.into();
1102 assert_eq!(v, Value::I64(42));
1103
1104 let v: Value = "hello".into();
1105 assert_eq!(v, Value::String("hello".to_string()));
1106
1107 let arr: Vec<Value> = vec![Value::I64(1), Value::I64(2)];
1108 let v: Value = arr.into();
1109 assert_eq!(v, Value::Array(vec![Value::I64(1), Value::I64(2)]));
1110 }
1111
1112 #[test]
1113 fn test_value_display() {
1114 assert_eq!(format!("{}", Value::Null), "NULL");
1115 assert_eq!(format!("{}", Value::Bool(true)), "true");
1116 assert_eq!(format!("{}", Value::I64(42)), "42");
1117 assert_eq!(format!("{}", Value::String("test".to_string())), "'test'");
1118 }
1119}