aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-04-15 15:52:09 +0200
committermetamuffin <metamuffin@disroot.org>2024-04-15 15:52:09 +0200
commite38c599bcfe0c052881b78bc141e9f54c75290ea (patch)
treedad96fda6de95c591bceb69c672d9b2cbde61757 /server/src/routes
parentc988e7db759966d9586471e8cfcfd0d91e855dc0 (diff)
downloadjellything-e38c599bcfe0c052881b78bc141e9f54c75290ea.tar
jellything-e38c599bcfe0c052881b78bc141e9f54c75290ea.tar.bz2
jellything-e38c599bcfe0c052881b78bc141e9f54c75290ea.tar.zst
search almost works
Diffstat (limited to 'server/src/routes')
-rw-r--r--server/src/routes/ui/error.rs5
-rw-r--r--server/src/routes/ui/layout.rs2
-rw-r--r--server/src/routes/ui/search.rs100
3 files changed, 61 insertions, 46 deletions
diff --git a/server/src/routes/ui/error.rs b/server/src/routes/ui/error.rs
index 41a2de9..02011fc 100644
--- a/server/src/routes/ui/error.rs
+++ b/server/src/routes/ui/error.rs
@@ -139,3 +139,8 @@ impl From<jellybase::database::TransactionError> for MyError {
MyError(anyhow::anyhow!("database oopsie during transaction: {err}"))
}
}
+impl From<jellybase::database::tantivy::TantivyError> for MyError {
+ fn from(err: jellybase::database::tantivy::TantivyError) -> Self {
+ MyError(anyhow::anyhow!("database during search: {err}"))
+ }
+}
diff --git a/server/src/routes/ui/layout.rs b/server/src/routes/ui/layout.rs
index 07fc70c..1696ac4 100644
--- a/server/src/routes/ui/layout.rs
+++ b/server/src/routes/ui/layout.rs
@@ -46,7 +46,7 @@ markup::define! {
@if let Some(_) = session {
a.library[href=uri!(r_library_node("library"))] { "My Library" } " "
a.library[href=uri!(r_all_items())] { "All Items" } " "
- a.library[href=uri!(r_search(None::<&'static str>))] { "Search" } " "
+ a.library[href=uri!(r_search(None::<&'static str>, None::<usize>))] { "Search" } " "
}
div.account {
@if let Some(session) = session {
diff --git a/server/src/routes/ui/search.rs b/server/src/routes/ui/search.rs
index cafa755..f87a13b 100644
--- a/server/src/routes/ui/search.rs
+++ b/server/src/routes/ui/search.rs
@@ -4,60 +4,68 @@ use super::{
layout::{DynLayoutPage, LayoutPage},
node::NodeCard,
};
-use edit_distance::edit_distance;
-use jellybase::database::{
- tantivy::query::QueryParser, DataAcid, ReadableTable, T_NODE, T_USER_NODE,
+use anyhow::{anyhow, Context};
+use jellybase::{
+ database::{
+ tantivy::{
+ collector::{Count, TopDocs},
+ query::QueryParser,
+ schema::Value,
+ TantivyDocument,
+ },
+ DataAcid, TableExt, T_NODE, T_USER_NODE,
+ },
+ permission::NodePermissionExt,
};
use rocket::{get, State};
+use std::time::Instant;
-#[get("/search?<query>")]
+#[get("/search?<query>&<page>")]
pub async fn r_search<'a>(
session: Session,
db: &State<DataAcid>,
query: Option<&str>,
+ page: Option<usize>,
) -> MyResult<DynLayoutPage<'a>> {
- // 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::<Vec<_>>();
- // 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::<Vec<_>>())
- // } else {
- // None
- // };
+ let timing = Instant::now();
+ let results = if let Some(query) = query {
+ let query = QueryParser::for_index(
+ &db.node_index.index,
+ vec![db.node_index.title, db.node_index.description],
+ )
+ .parse_query(query)
+ .context("parsing query")?;
+
+ let searcher = db.node_index.reader.searcher();
+ let sres = searcher.search(
+ &query,
+ &TopDocs::with_limit(32).and_offset(page.unwrap_or_default() * 32),
+ )?;
+ let scount = searcher.search(&query, &Count)?;
+
+ let mut results = Vec::new();
+ for (_, daddr) in sres {
+ let doc: TantivyDocument = searcher.doc(daddr)?;
+ let id = doc.get_first(db.node_index.id).unwrap().as_str().unwrap();
+
+ let node = T_NODE
+ .get(&db, id)?
+ .only_if_permitted(&session.user.permissions)
+ .ok_or(anyhow!("node does not exist"))?
+ .public;
+ let udata = T_USER_NODE
+ .get(&db, &(session.user.name.as_str(), id))?
+ .unwrap_or_default();
- let query = QueryParser::for_index(index, vec![]);
+ results.push((id.to_owned(), node, udata));
+ }
+ Some((scount, results))
+ } else {
+ None
+ };
+ let search_dur = timing.elapsed();
- let searcher = db.node_index.reader.searcher();
- searcher.Ok(LayoutPage {
+ Ok(LayoutPage {
title: "Search".to_string(),
class: Some("search"),
content: markup::new! {
@@ -66,11 +74,13 @@ pub async fn r_search<'a>(
input[type="text", name="query", placeholder="Search Term"];
input[type="submit", value="Search"];
}
- @if let Some(results) = &results {
+ @if let Some((count, results)) = &results {
h2 { "Results" }
+ p.stats { @format!("Found {count} nodes in {search_dur:?}.") }
ul.children {@for (id, node, udata) in results.iter() {
li { @NodeCard { id, node, udata } }
}}
+ // TODO pagination
}
},
})