fts wip: trigger, Quote::get_by_search_query, expose to API

This commit is contained in:
2026-04-25 01:00:18 +02:00
parent 983e1ae88f
commit 84e2ad3918
4 changed files with 65 additions and 0 deletions

View File

@@ -50,4 +50,5 @@ pub fn api_router() -> Router<MnemoState> {
// quotes // quotes
.route("/api/quotes", post(quotes::create)) .route("/api/quotes", post(quotes::create))
.route("/api/quotes/{id}", get(quotes::get_by_id)) .route("/api/quotes/{id}", get(quotes::get_by_id))
.route("/api/quotes/search", get(quotes::get_by_query))
} }

View File

@@ -30,6 +30,16 @@ pub async fn get_by_id(
Ok(Json(Quote::get_by_id(&mut conn, id).await?).into_response()) 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)] #[derive(Deserialize)]
pub struct QuoteLineForm { pub struct QuoteLineForm {
pub content: String, pub content: String,

View File

@@ -96,3 +96,36 @@ CREATE TABLE logs (
); );
CREATE INDEX logs_by_actor ON logs(actor); CREATE INDEX logs_by_actor ON logs(actor);
CREATE INDEX logs_by_target ON logs(target); 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();

View File

@@ -174,6 +174,27 @@ impl Quote {
Ok(quotes) 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( pub async fn create(
conn: &mut PgConnection, conn: &mut PgConnection,
lines: Vec<(String, Vec<Name>)>, lines: Vec<(String, Vec<Name>)>,