fts wip: trigger, Quote::get_by_search_query, expose to API
This commit is contained in:
@@ -50,4 +50,5 @@ pub fn api_router() -> Router<MnemoState> {
|
||||
// quotes
|
||||
.route("/api/quotes", post(quotes::create))
|
||||
.route("/api/quotes/{id}", get(quotes::get_by_id))
|
||||
.route("/api/quotes/search", get(quotes::get_by_query))
|
||||
}
|
||||
|
||||
@@ -30,6 +30,16 @@ pub async fn get_by_id(
|
||||
Ok(Json(Quote::get_by_id(&mut conn, id).await?).into_response())
|
||||
}
|
||||
|
||||
pub async fn get_by_query(
|
||||
State(state): State<MnemoState>,
|
||||
headers: HeaderMap,
|
||||
Json(q): Json<String>,
|
||||
) -> Result<Response, CompositeError> {
|
||||
let mut conn = state.pool.acquire().await?;
|
||||
User::authenticate(&mut conn, &headers).await?.required()?;
|
||||
Ok(Json(Quote::get_by_search_query(&mut conn, &q).await?).into_response())
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct QuoteLineForm {
|
||||
pub content: String,
|
||||
|
||||
@@ -96,3 +96,36 @@ CREATE TABLE logs (
|
||||
);
|
||||
CREATE INDEX logs_by_actor ON logs(actor);
|
||||
CREATE INDEX logs_by_target ON logs(target);
|
||||
|
||||
CREATE OR REPLACE FUNCTION update_quote_fts_from_lines()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
affected_quote_id UUID;
|
||||
quote_lines_content TEXT;
|
||||
BEGIN
|
||||
IF TG_OP = 'DELETE' THEN
|
||||
affected_quote_id := OLD.quote_id;
|
||||
ELSE
|
||||
affected_quote_id := NEW.quote_id;
|
||||
END IF;
|
||||
|
||||
SELECT string_agg(content, ' ' ORDER BY ordering)
|
||||
INTO quote_lines_content
|
||||
FROM lines
|
||||
WHERE quote_id = affected_quote_id;
|
||||
|
||||
UPDATE quotes
|
||||
SET fts =
|
||||
setweight(to_tsvector(COALESCE(quote_lines_content, '')), 'A') ||
|
||||
setweight(to_tsvector(COALESCE(context, '')), 'B') ||
|
||||
setweight(to_tsvector(COALESCE(location, '')), 'C')
|
||||
WHERE id = affected_quote_id;
|
||||
|
||||
RETURN COALESCE(NEW, OLD);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trigger_lines_update_quote_fts
|
||||
AFTER INSERT OR UPDATE OR DELETE ON lines
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_quote_fts_from_lines();
|
||||
|
||||
@@ -174,6 +174,27 @@ impl Quote {
|
||||
Ok(quotes)
|
||||
}
|
||||
|
||||
pub async fn get_by_search_query(
|
||||
conn: &mut PgConnection,
|
||||
query: &str,
|
||||
) -> Result<Vec<Quote>, QuoteError> {
|
||||
let ids: Vec<Uuid> = sqlx::query_scalar(
|
||||
"SELECT id FROM quotes WHERE fts @@ phraseto_tsquery($1) LIMIT $2 OFFSET $3",
|
||||
)
|
||||
.bind(query)
|
||||
.bind(20)
|
||||
.bind(0)
|
||||
.fetch_all(&mut *conn)
|
||||
.await?;
|
||||
|
||||
let mut quotes = Vec::with_capacity(ids.len());
|
||||
for id in ids {
|
||||
quotes.push(Self::get_by_id(&mut *conn, id).await?);
|
||||
}
|
||||
|
||||
Ok(quotes)
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
conn: &mut PgConnection,
|
||||
lines: Vec<(String, Vec<Name>)>,
|
||||
|
||||
Reference in New Issue
Block a user