1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
use super::{
account::session::Session,
error::MyResult,
layout::{DynLayoutPage, LayoutPage},
node::NodeCard,
};
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>&<page>")]
pub async fn r_search<'a>(
session: Session,
db: &State<DataAcid>,
query: Option<&str>,
page: Option<usize>,
) -> MyResult<DynLayoutPage<'a>> {
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();
results.push((id.to_owned(), node, udata));
}
Some((scount, results))
} else {
None
};
let search_dur = timing.elapsed();
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((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
}
},
})
}
|