use super::{ account::session::Session, error::MyResult, layout::{DynLayoutPage, LayoutPage}, node::NodeCard, }; use edit_distance::edit_distance; use jellybase::database::{DataAcid, ReadableTable, T_NODE, T_USER_NODE}; use rocket::{get, State}; #[get("/search?")] pub async fn r_search<'a>( session: Session, db: &State, query: Option<&str>, ) -> MyResult> { let results = if let Some(query) = query { let mut items = { let txn = db.begin_read()?; let nodes = txn.open_table(T_NODE)?; let node_users = txn.open_table(T_USER_NODE)?; let i = nodes .iter()? .map(|a| { let (x, y) = a.unwrap(); let (x, y) = (x.value().to_owned(), y.value().0); let z = node_users .get(&(session.user.name.as_str(), x.as_str())) .unwrap() .map(|z| z.value().0) .unwrap_or_default(); let y = y.public; (x, y, z) }) .collect::>(); drop(nodes); i }; let query = query.to_lowercase(); items.sort_by_cached_key(|(_, n, _)| { n.title .as_ref() .map(|x| x.to_lowercase()) .unwrap_or_default() .split(" ") .map(|tok| edit_distance(query.as_str(), tok)) .min() .unwrap_or(usize::MAX) }); Some(items.into_iter().take(64).collect::>()) } else { None }; Ok(LayoutPage { title: "Search".to_string(), class: Some("search"), content: markup::new! { h1 { "Search" } form[action="", method="GET"] { input[type="text", name="query", placeholder="Search Term"]; input[type="submit", value="Search"]; } @if let Some(results) = &results { h2 { "Results" } ul.children {@for (id, node, udata) in results.iter() { li { @NodeCard { id, node, udata } } }} } }, }) }