use serde_json::Value;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IdKind {
Uuid,
I64,
F64,
String,
Bool,
}
impl IdKind {
pub fn detect(value: &Value) -> Self {
match value {
Value::Number(n) => {
if let Some(_i) = n.as_i64() {
IdKind::I64
} else if let Some(_f) = n.as_f64() {
IdKind::F64
} else {
IdKind::String
}
}
Value::String(s) => {
if is_uuid_format(s) {
IdKind::Uuid
} else {
IdKind::String
}
}
Value::Bool(_) => IdKind::Bool,
_ => IdKind::String,
}
}
pub fn is_uuid(&self) -> bool { matches!(self, IdKind::Uuid) }
pub fn is_i64(&self) -> bool { matches!(self, IdKind::I64) }
pub fn is_string(&self) -> bool { matches!(self, IdKind::String) }
pub fn id_cast_sql(&self) -> &'static str {
match self {
IdKind::Uuid => "::uuid",
IdKind::I64 => "::bigint",
_ => "",
}
}
pub fn value_cast_sql(&self) -> &'static str {
match self {
IdKind::Uuid => "::uuid",
IdKind::I64 => "::bigint",
IdKind::F64 => "::double precision",
IdKind::Bool => "::boolean",
_ => "",
}
}
}
impl std::fmt::Display for IdKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IdKind::Uuid => write!(f, "uuid"),
IdKind::I64 => write!(f, "i64"),
IdKind::F64 => write!(f, "f64"),
IdKind::String => write!(f, "string"),
IdKind::Bool => write!(f, "bool"),
}
}
}
fn is_uuid_format(s: &str) -> bool {
if s.len() != 36 { return false; }
let bytes = s.as_bytes();
for (i, &b) in bytes.iter().enumerate() {
match i {
8 | 13 | 18 | 23 => { if b != b'-' { return false; } }
_ => { if !b.is_ascii_hexdigit() { return false; } }
}
}
true
}