use std::path::Path;
use serde_json::{json, Value};
use crate::data;
use crate::output::{emit, exit, print_brief, CliError, Ctx};
use super::people;
pub fn run(dir: &Path, ctx: Ctx, query: &str) -> Result<(), CliError> {
let needle = query.to_lowercase();
let people_data = data::load(dir, "people")?;
let people_iter = people::all_people(&people_data);
let mut people_hits: Vec<Value> = Vec::new();
for (dept, p) in &people_iter {
let s = serde_json::to_string(&Value::Object(p.clone())).unwrap_or_default();
if s.to_lowercase().contains(&needle) {
let mut obj = p.clone();
obj.insert("department".into(), Value::String(dept.clone()));
people_hits.push(Value::Object(obj));
}
}
let products_data = data::load(dir, "products")?;
let products: Vec<Value> = products_data
.get("products")
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_default()
.into_iter()
.filter(|p| {
serde_json::to_string(p)
.map(|s| s.to_lowercase().contains(&needle))
.unwrap_or(false)
})
.collect();
let customers_data = data::load(dir, "customers")?;
let customers: Vec<Value> = customers_data
.get("customers")
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_default()
.into_iter()
.filter(|c| {
serde_json::to_string(c)
.map(|s| s.to_lowercase().contains(&needle))
.unwrap_or(false)
})
.collect();
let repos_data = data::load(dir, "repos")?;
let repos: Vec<Value> = repos_data
.get("repos")
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_default()
.into_iter()
.filter(|r| {
serde_json::to_string(r)
.map(|s| s.to_lowercase().contains(&needle))
.unwrap_or(false)
})
.collect();
let chats_data = data::load(dir, "chats")?;
let mut chats_hits: Vec<Value> = Vec::new();
if let Some(map) = chats_data.get("group_chats").and_then(|v| v.as_object()) {
for (name, val) in map {
let id = match val {
Value::String(s) => Value::String(s.clone()),
Value::Object(o) => o.get("id").cloned().unwrap_or(Value::Null),
other => other.clone(),
};
if name.to_lowercase().contains(&needle)
|| id
.as_str()
.map(|s| s.to_lowercase().contains(&needle))
.unwrap_or(false)
{
chats_hits.push(json!({ "name": name, "id": id }));
}
}
}
let total = people_hits.len()
+ products.len()
+ customers.len()
+ chats_hits.len()
+ repos.len();
if total == 0 {
return Err(CliError {
code: exit::NOT_FOUND,
message: format!("no matches for: {query}"),
hint: Some("widen the query or `liber <noun> list` to browse".into()),
retryable: false,
});
}
let results = json!({
"people": people_hits,
"products": products,
"customers": customers,
"chats": chats_hits,
"repos": repos,
});
if ctx.json {
emit(ctx, &results);
return Ok(());
}
for kind in ["people", "products", "customers", "chats", "repos"] {
let arr = results
.get(kind)
.and_then(|v| v.as_array())
.cloned()
.unwrap_or_default();
if arr.is_empty() {
continue;
}
println!("== {kind} ({}) ==", arr.len());
for item in arr {
print_brief(&item, false);
}
}
Ok(())
}