use serde_json::Value as Json;
use crate::errors::GraphDDBError;
use crate::iso_datetime::{normalize_date, normalize_datetime};
use crate::value::indexmap_shim::IndexMap;
use crate::value::Value;
pub fn is_internal_key(name: &str) -> bool {
if name == "PK" || name == "SK" {
return true;
}
name.starts_with("GSI") && (name.ends_with("PK") || name.ends_with("SK"))
}
pub fn hydrate_item(
raw: &IndexMap<Value>,
select: &[String],
entity_meta: &Json,
) -> Result<IndexMap<Value>, GraphDDBError> {
let fields = entity_meta.get("fields").and_then(Json::as_object);
let mut result = IndexMap::new();
for field_name in select {
if is_internal_key(field_name) {
continue;
}
if let Some(v) = raw.get(field_name) {
let field_meta = fields.and_then(|f| f.get(field_name));
result.insert(field_name.clone(), deserialize_value(v, field_meta)?);
}
}
Ok(result)
}
fn deserialize_value(value: &Value, field_meta: Option<&Json>) -> Result<Value, GraphDDBError> {
let fmt = field_meta
.and_then(|m| m.get("format"))
.and_then(Json::as_str);
match (fmt, value) {
(Some("datetime"), Value::S(s)) => Ok(Value::S(normalize_datetime(s)?)),
(Some("date"), Value::S(s)) => Ok(Value::S(normalize_date(s)?)),
_ => Ok(value.clone()),
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn selects_only_named_and_drops_internal() {
let mut raw = IndexMap::new();
raw.insert("PK".to_string(), Value::S("x".to_string()));
raw.insert("name".to_string(), Value::S("Alice".to_string()));
raw.insert("secret".to_string(), Value::S("hidden".to_string()));
let select = vec!["name".to_string(), "PK".to_string()];
let out = hydrate_item(&raw, &select, &json!({"fields": {}})).unwrap();
assert_eq!(out.len(), 1);
assert_eq!(out.get("name").unwrap(), &Value::S("Alice".to_string()));
}
#[test]
fn datetime_format_normalized() {
let mut raw = IndexMap::new();
raw.insert(
"createdAt".to_string(),
Value::S("2020-01-01T00:00:00Z".to_string()),
);
let meta = json!({"fields": {"createdAt": {"format": "datetime"}}});
let out = hydrate_item(&raw, &["createdAt".to_string()], &meta).unwrap();
assert_eq!(
out.get("createdAt").unwrap(),
&Value::S("2020-01-01T00:00:00.000Z".to_string())
);
}
}