use serde_json::Value as Json;
use crate::templates::{each_placeholder_pub, json_to_template_string};
fn lookup<'a>(item: &'a [(String, Json)], name: &str) -> Option<&'a Json> {
item.iter().find(|(k, _)| k == name).map(|(_, v)| v)
}
fn fill(template: &str, item: &[(String, Json)]) -> String {
let mut out = String::new();
let bytes = template.as_bytes();
let mut i = 0;
while i < bytes.len() {
if bytes[i] == b'{' {
if let Some(close) = template[i + 1..].find('}') {
let name = &template[i + 1..i + 1 + close];
if !name.is_empty() && !name.contains('{') {
let v = lookup(item, name)
.map(json_to_template_string)
.unwrap_or_default();
out.push_str(&v);
i += 1 + close + 1;
continue;
}
}
}
out.push(bytes[i] as char);
i += 1;
}
out
}
fn fillable(template: &str, item: &[(String, Json)]) -> bool {
each_placeholder_pub(template)
.iter()
.all(|name| lookup(item, name).is_some())
}
pub fn add_key_attributes(manifest: &Json, entity_name: &str, item: &mut Vec<(String, Json)>) {
let entity = manifest
.get("entities")
.and_then(Json::as_object)
.and_then(|e| e.get(entity_name));
let entity = match entity {
Some(e) => e,
None => return,
};
if let Some(key) = entity.get("key").filter(|k| !k.is_null()) {
let pk_tmpl = key.get("pkTemplate").and_then(Json::as_str).unwrap_or("");
let pk = fill(pk_tmpl, item);
set(item, "PK", Json::String(pk));
if let Some(sk_tmpl) = key.get("skTemplate").and_then(Json::as_str) {
let sk = fill(sk_tmpl, item);
set(item, "SK", Json::String(sk));
}
}
if let Some(gsis) = entity.get("gsis").and_then(Json::as_array) {
for gsi in gsis {
let index = gsi.get("indexName").and_then(Json::as_str).unwrap_or("");
if let Some(pk_tmpl) = gsi.get("pkTemplate").and_then(Json::as_str) {
if fillable(pk_tmpl, item) {
set(
item,
&format!("{index}PK"),
Json::String(fill(pk_tmpl, item)),
);
}
}
if let Some(sk_tmpl) = gsi.get("skTemplate").and_then(Json::as_str) {
if fillable(sk_tmpl, item) {
set(
item,
&format!("{index}SK"),
Json::String(fill(sk_tmpl, item)),
);
}
}
}
}
}
fn set(item: &mut Vec<(String, Json)>, key: &str, value: Json) {
if let Some(slot) = item.iter_mut().find(|(k, _)| k == key) {
slot.1 = value;
} else {
item.push((key.to_string(), value));
}
}