Expand search api

This commit is contained in:
Magnus Hoff 2017-10-24 22:15:42 +02:00
parent 59c11897b2
commit 9336fbf3cd
2 changed files with 33 additions and 15 deletions

View file

@ -11,21 +11,23 @@ use site::Layout;
use state::State;
use web::{Resource, ResponseFuture};
const DEFAULT_LIMIT: i32 = 30;
const DEFAULT_LIMIT: i32 = 10;
const DEFAULT_SNIPPET_SIZE: i32 = 8;
type BoxResource = Box<Resource + Sync + Send>;
#[derive(Serialize, Deserialize, Default)]
pub struct QueryParameters {
q: Option<String>,
skip: Option<i32>,
offset: Option<i32>,
limit: Option<i32>,
snippet_size: Option<i32>,
}
impl QueryParameters {
pub fn skip(self, skip: i32) -> Self {
pub fn offset(self, offset: i32) -> Self {
Self {
skip: if skip != 0 { Some(skip) } else { None },
offset: if offset != 0 { Some(offset) } else { None },
..self
}
}
@ -60,18 +62,30 @@ impl SearchLookup {
pub fn lookup(&self, query: Option<&str>) -> Result<Option<BoxResource>, ::web::Error> {
let args: QueryParameters = serde_urlencoded::from_str(query.unwrap_or(""))?;
Ok(Some(Box::new(SearchResource::new(self.state.clone(), args))))
Ok(Some(Box::new(
SearchResource::new(
self.state.clone(),
args.q,
args.limit.unwrap_or(DEFAULT_LIMIT),
args.offset.unwrap_or(0),
args.snippet_size.unwrap_or(DEFAULT_SNIPPET_SIZE),
)
)))
}
}
pub struct SearchResource {
state: State,
query_args: QueryParameters,
query: Option<String>,
limit: i32,
offset: i32,
snippet_size: i32,
}
impl SearchResource {
pub fn new(state: State, query_args: QueryParameters) -> Self {
Self { state, query_args }
pub fn new(state: State, query: Option<String>, limit: i32, offset: i32, snippet_size: i32) -> Self {
Self { state, query, limit, offset, snippet_size }
}
}
@ -107,9 +121,9 @@ impl Resource for SearchResource {
}
// TODO: Show a search "front page" when no query is given:
let query = self.query_args.q.as_ref().map(|x| x.clone()).unwrap_or("".to_owned());
let query = self.query.as_ref().map(|x| x.clone()).unwrap_or("".to_owned());
let data = self.state.search_query(query);
let data = self.state.search_query(query, self.limit, self.offset, self.snippet_size);
let head = self.head();
Box::new(data.join(head)
@ -119,7 +133,7 @@ impl Resource for SearchResource {
base: None, // Hmm, should perhaps accept `base` as argument
title: "Search",
body: &Template {
query: self.query_args.q.as_ref().map(|x| &**x).unwrap_or(""),
query: self.query.as_ref().map(|x| &**x).unwrap_or(""),
hits: data,
},
style_css_checksum: StyleCss::checksum(),

View file

@ -305,12 +305,12 @@ impl State {
})
}
pub fn search_query(&self, query_string: String) -> CpuFuture<Vec<models::SearchResult>, Error> {
pub fn search_query(&self, query_string: String, limit: i32, offset: i32, snippet_size: i32) -> CpuFuture<Vec<models::SearchResult>, Error> {
let connection_pool = self.connection_pool.clone();
self.cpu_pool.spawn_fn(move || {
use diesel::expression::sql_literal::sql;
use diesel::types::Text;
use diesel::types::{Integer, Text};
fn fts_quote(src: &str) -> String {
format!("\"{}\"", src.replace('\"', "\"\""))
@ -331,12 +331,16 @@ impl State {
Ok(
sql::<(Text, Text, Text)>(
"SELECT title, snippet(article_search, 1, '', '', '\u{2026}', 8), slug \
"SELECT title, snippet(article_search, 1, '', '', '\u{2026}', ?), slug \
FROM article_search \
WHERE article_search MATCH ? \
ORDER BY rank"
ORDER BY rank \
LIMIT ? OFFSET ?"
)
.bind::<Integer, _>(snippet_size)
.bind::<Text, _>(query)
.bind::<Integer, _>(limit)
.bind::<Integer, _>(offset)
.load(&*connection_pool.get()?)?)
})
}