use std::sync::LazyLock;
use regex::Regex;
use serde_json::Value;
#[allow(unused_imports)] use crate::error::FraiseQLError;
use crate::error::Result;
static UUID_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
.expect("UUID regex is valid")
});
#[derive(Debug, Clone)]
pub struct UUIDExtractor;
impl UUIDExtractor {
pub fn extract_entity_uuid(response: &Value, _entity_type: &str) -> Result<Option<String>> {
match response {
Value::Object(obj) => {
if let Some(id_value) = obj.get("id") {
return extract_uuid_from_value(id_value);
}
for (_key, value) in obj {
if let Value::Object(nested) = value {
if let Some(id_value) = nested.get("id") {
return extract_uuid_from_value(id_value);
}
}
}
Ok(None)
},
_ => Ok(None),
}
}
pub fn extract_batch_uuids(response: &Value, _entity_type: &str) -> Result<Vec<String>> {
match response {
Value::Array(arr) => {
let mut uuids = Vec::new();
for item in arr {
if let Ok(Some(uuid)) = extract_uuid_from_value(item) {
uuids.push(uuid);
}
}
Ok(uuids)
},
Value::Object(_) => {
match Self::extract_entity_uuid(response, "")? {
Some(uuid) => Ok(vec![uuid]),
None => Ok(vec![]),
}
},
_ => Ok(vec![]),
}
}
#[must_use]
pub fn is_valid_uuid(id: &str) -> bool {
UUID_REGEX.is_match(&id.to_lowercase())
}
}
fn extract_uuid_from_value(value: &Value) -> Result<Option<String>> {
match value {
Value::String(s) => {
if UUIDExtractor::is_valid_uuid(s) {
Ok(Some(s.to_lowercase()))
} else {
Ok(None)
}
},
Value::Object(obj) => {
if let Some(id_val) = obj.get("id") {
return extract_uuid_from_value(id_val);
}
Ok(None)
},
_ => Ok(None),
}
}