use crate::paginated_query_as::internal::DEFAULT_EMPTY_VALUE;
use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime};
use sqlx::types::Uuid;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
pub fn get_postgres_type_casting(value: &str) -> &'static str {
match value.trim().to_string().to_lowercase().as_str() {
value
if value.eq_ignore_ascii_case("null")
|| value.eq_ignore_ascii_case("nan")
|| value.eq_ignore_ascii_case("infinity")
|| value.eq_ignore_ascii_case("-infinity") =>
{
DEFAULT_EMPTY_VALUE
}
value if value.starts_with("\\x") && value[2..].chars().all(|c| c.is_ascii_hexdigit()) => {
"::bytea"
}
value if value.starts_with('{') || value.starts_with('[') => {
match serde_json::from_str::<serde_json::Value>(value) {
Ok(_) => "::jsonb", Err(_) => DEFAULT_EMPTY_VALUE,
}
}
value if value.starts_with("<?xml") || (value.starts_with('<') && value.ends_with('>')) => {
"::xml"
}
value if value.parse::<IpAddr>().is_ok() => "::inet", value if value.parse::<Ipv4Addr>().is_ok() => "::inet", value if value.parse::<Ipv6Addr>().is_ok() => "::inet",
value if Uuid::parse_str(value).is_ok() => "::uuid",
value if NaiveDateTime::parse_from_str(value, "%Y-%m-%d %H:%M:%S").is_ok() => {
"::timestamp without time zone"
}
value if NaiveDate::parse_from_str(value, "%Y-%m-%d").is_ok() => "::date",
value if NaiveTime::parse_from_str(value, "%H:%M:%S").is_ok() => "::time",
value if DateTime::parse_from_rfc3339(value).is_ok() => "::timestamp with time zone",
value if value == "t" || value == "f" => "::boolean",
value if value == "true" || value == "false" => "::boolean",
value if value.parse::<i16>().is_ok() => "::smallint", value if value.parse::<i32>().is_ok() => "::integer", value if value.parse::<i64>().is_ok() => "::bigint", value if value.parse::<f32>().is_ok() => "::real", value if value.parse::<f64>().is_ok() => "::double precision",
_ => DEFAULT_EMPTY_VALUE,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_boolean_types() {
assert_eq!(get_postgres_type_casting("true"), "::boolean");
assert_eq!(get_postgres_type_casting("false"), "::boolean");
assert_eq!(get_postgres_type_casting("t"), "::boolean");
assert_eq!(get_postgres_type_casting("f"), "::boolean");
assert_eq!(get_postgres_type_casting("TRUE"), "::boolean");
assert_eq!(get_postgres_type_casting("FALSE"), "::boolean");
assert_eq!(get_postgres_type_casting("True"), "::boolean");
assert_eq!(get_postgres_type_casting("False"), "::boolean");
}
#[test]
fn test_numeric_types() {
assert_eq!(get_postgres_type_casting("32767"), "::smallint"); assert_eq!(get_postgres_type_casting("-32768"), "::smallint"); assert_eq!(get_postgres_type_casting("2147483647"), "::integer"); assert_eq!(get_postgres_type_casting("-2147483648"), "::integer"); assert_eq!(get_postgres_type_casting("9223372036854775807"), "::bigint"); assert_eq!(
get_postgres_type_casting("-9223372036854775808"),
"::bigint"
);
assert_eq!(get_postgres_type_casting("3.14"), "::real");
assert_eq!(get_postgres_type_casting("-3.14"), "::real");
assert_eq!(get_postgres_type_casting("1.23e-4"), "::real");
assert_eq!(get_postgres_type_casting("1.23E+4"), "::real");
assert_eq!(
get_postgres_type_casting("1.7976931348623157e+308"),
"::real"
);
}
#[test]
fn test_network_types() {
assert_eq!(get_postgres_type_casting("192.168.0.1"), "::inet");
assert_eq!(get_postgres_type_casting("0.0.0.0"), "::inet");
assert_eq!(get_postgres_type_casting("255.255.255.255"), "::inet");
assert_eq!(get_postgres_type_casting("2001:db8::1"), "::inet");
assert_eq!(get_postgres_type_casting("::1"), "::inet");
assert_eq!(get_postgres_type_casting("fe80::1"), "::inet");
}
#[test]
fn test_json_types() {
assert_eq!(get_postgres_type_casting("{}"), "::jsonb");
assert_eq!(get_postgres_type_casting("{\"key\":\"value\"}"), "::jsonb");
assert_eq!(
get_postgres_type_casting("{\"nested\":{\"key\":\"value\"}}"),
"::jsonb"
);
assert_eq!(get_postgres_type_casting("[]"), "::jsonb");
assert_eq!(get_postgres_type_casting("[1,2,3]"), "::jsonb");
assert_eq!(
get_postgres_type_casting("[{\"key\":\"value\"}]"),
"::jsonb"
);
assert_eq!(
get_postgres_type_casting("{\"array\":[1,2,3],\"object\":{\"key\":\"value\"}}"),
"::jsonb"
);
}
#[test]
fn test_binary_types() {
assert_eq!(get_postgres_type_casting("\\x0123456789ABCDEF"), "::bytea");
assert_eq!(get_postgres_type_casting("\\x"), "::bytea");
assert_eq!(get_postgres_type_casting("\\xGG"), "");
}
#[test]
fn test_date_time_types() {
assert_eq!(get_postgres_type_casting("2024-01-01"), "::date");
assert_eq!(get_postgres_type_casting("2024-12-31"), "::date");
assert_eq!(get_postgres_type_casting("12:34:56"), "::time");
assert_eq!(get_postgres_type_casting("23:59:59"), "::time");
assert_eq!(
get_postgres_type_casting("2024-01-01 12:34:56"),
"::timestamp without time zone"
);
assert_eq!(
get_postgres_type_casting("2024-01-01T12:34:56Z"),
"::timestamp with time zone"
);
assert_eq!(
get_postgres_type_casting("2024-01-01T12:34:56+00:00"),
"::timestamp with time zone"
);
}
#[test]
fn test_uuid_types() {
assert_eq!(
get_postgres_type_casting("550e8400-e29b-41d4-a716-446655440000"),
"::uuid"
);
assert_eq!(
get_postgres_type_casting("550E8400-E29B-41D4-A716-446655440000"),
"::uuid"
);
assert_eq!(get_postgres_type_casting("550e8400-e29b-41d4-a716"), "");
assert_eq!(
get_postgres_type_casting("550e8400-e29b-41d4-a716-44665544000G"),
""
);
}
#[test]
fn test_xml_types() {
assert_eq!(
get_postgres_type_casting("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"),
"::xml"
);
assert_eq!(
get_postgres_type_casting("<root><child>value</child></root>"),
"::xml"
);
assert_eq!(get_postgres_type_casting("<element/>"), "::xml");
}
#[test]
fn test_edge_cases() {
assert_eq!(get_postgres_type_casting(""), "");
assert_eq!(get_postgres_type_casting(" "), "");
assert_eq!(get_postgres_type_casting("123abc"), "");
assert_eq!(get_postgres_type_casting("true123"), "");
assert_eq!(get_postgres_type_casting("2024-13-01"), "");
assert_eq!(get_postgres_type_casting("trueish"), "");
assert_eq!(get_postgres_type_casting("192.168.1"), ""); assert_eq!(get_postgres_type_casting("{invalid json}"), "");
assert_eq!(get_postgres_type_casting("\\n\\t\\r"), "");
assert_eq!(get_postgres_type_casting("🦀"), "");
}
#[test]
fn test_type_precedence() {
assert_eq!(get_postgres_type_casting("123"), "::smallint"); assert_eq!(get_postgres_type_casting("t"), "::boolean"); }
#[test]
fn test_special_values() {
assert_eq!(get_postgres_type_casting("NULL"), "");
assert_eq!(get_postgres_type_casting("null"), "");
assert_eq!(get_postgres_type_casting("Infinity"), "");
assert_eq!(get_postgres_type_casting("-Infinity"), "");
}
}