use serde_json::Value as Json;
use crate::store::Store;
use crate::store::hierarchy::Hierarchy;
use crate::store::{NodeKind, SYSTEM_TAG_WORLD};
pub fn chapter(store: &Store, chapter_head: &str) -> Option<Json> {
let h = Hierarchy::load(store).ok()?;
let book = h
.iter()
.find(|n| n.kind == NodeKind::Book && n.system_tag.as_deref() == Some(SYSTEM_TAG_WORLD))?;
let head = chapter_head.trim();
let chapter = h.children_of(Some(book.id)).into_iter().find(|n| {
n.kind == NodeKind::Chapter
&& (n.title.eq_ignore_ascii_case(head) || n.slug.eq_ignore_ascii_case(head))
})?;
let mut map = serde_json::Map::new();
for pid in h.collect_subtree(chapter.id) {
let Some(node) = h.get(pid) else { continue };
if node.kind != NodeKind::Paragraph {
continue;
}
let Ok(Some(bytes)) = store.get_content(pid) else { continue };
if let Ok(Json::Object(obj)) = serde_json::from_slice::<Json>(&bytes) {
for (k, v) in obj {
map.insert(k, v);
}
}
}
if map.is_empty() {
return None;
}
Some(Json::Object(map))
}
pub fn lookup(store: &Store, path: &str) -> Option<Json> {
let segs: Vec<&str> = path.split('/').map(str::trim).filter(|s| !s.is_empty()).collect();
let (head, rest) = segs.split_first()?;
let chapter = chapter(store, head)?;
index_json(&chapter, rest)
}
fn index_json<'a>(root: &'a Json, path: &[&str]) -> Option<Json> {
let mut cur = root;
for seg in path {
cur = match cur {
Json::Object(map) => map.get(*seg)?,
Json::Array(arr) => {
let i: usize = seg.parse().ok()?;
arr.get(i)?
}
_ => return None,
};
}
Some(cur.clone())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn index_object_then_array_then_field() {
let root = serde_json::json!({
"year_length_planet_days": 412.3,
"insolation_bands": [ { "annual_mean": 18.7 }, { "annual_mean": 9.1 } ],
});
assert_eq!(index_json(&root, &["year_length_planet_days"]).unwrap(), serde_json::json!(412.3));
assert_eq!(index_json(&root, &["insolation_bands", "1", "annual_mean"]).unwrap(), serde_json::json!(9.1));
assert!(index_json(&root, &["missing"]).is_none());
assert!(index_json(&root, &["insolation_bands", "9"]).is_none());
assert_eq!(index_json(&root, &[]).unwrap(), root);
}
}