accounting tantivy search

This commit is contained in:
Priec
2026-07-21 10:34:16 +02:00
parent a96d95f1b2
commit f8a0437f77
4 changed files with 98 additions and 10 deletions

View File

@@ -9,7 +9,9 @@ pub use common::proto::komp_ac::search::searcher_server::SearcherServer;
use common::proto::komp_ac::search::{
SearchOrderDirection, SearchRequest, SearchResponse, search_response::Hit,
};
use common::search::{SchemaFields, register_tokenizers, search_index_path};
use common::search::{
JOURNAL_SEARCH_TABLE_NAME, SchemaFields, register_tokenizers, search_index_path,
};
use query_builder::{
ConstraintMode, SearchConstraint, SearchConstraintTarget, build_master_query,
};
@@ -271,6 +273,10 @@ async fn profile_exists(pool: &PgPool, profile_name: &str) -> Result<bool, Statu
}
async fn table_exists(pool: &PgPool, profile_name: &str, table_name: &str) -> Result<bool, Status> {
if table_name == JOURNAL_SEARCH_TABLE_NAME {
return profile_exists(pool, profile_name).await;
}
let exists = sqlx::query_scalar::<_, bool>(
r#"
SELECT EXISTS(
@@ -475,6 +481,10 @@ async fn table_physical_to_display_map(
profile_name: &str,
table_name: &str,
) -> Result<HashMap<String, String>, Status> {
if table_name == JOURNAL_SEARCH_TABLE_NAME {
return Ok(HashMap::new());
}
let rows = sqlx::query(
r#"
SELECT tdc.physical_name, tdc.display_name
@@ -509,6 +519,10 @@ async fn table_row_display_column(
profile_name: &str,
table_name: &str,
) -> Result<String, Status> {
if table_name == JOURNAL_SEARCH_TABLE_NAME {
return Ok("journal_name".to_string());
}
sqlx::query_scalar(
r#"
SELECT td.row_display_column
@@ -660,6 +674,15 @@ async fn fetch_ordered_rows(
limit: usize,
offset: usize,
) -> Result<Vec<Hit>, Status> {
if table_name == JOURNAL_SEARCH_TABLE_NAME {
if order.is_some() {
return Err(Status::invalid_argument(
"Explicit ordering is not supported for journal search",
));
}
return fetch_journal_rows(pool, profile_name, limit, offset).await;
}
let physical_to_display = table_physical_to_display_map(pool, profile_name, table_name).await?;
let display_column = table_row_display_column(pool, profile_name, table_name).await?;
let (resolved_order, direction) = match order {
@@ -708,6 +731,53 @@ async fn fetch_ordered_rows(
.collect())
}
async fn fetch_journal_rows(
pool: &PgPool,
profile_name: &str,
limit: usize,
offset: usize,
) -> Result<Vec<Hit>, Status> {
let rows = sqlx::query(
r#"WITH positioned AS (
SELECT journal.*,
ROW_NUMBER() OVER (ORDER BY journal.id) AS picker_position
FROM journal_entries journal
JOIN schemas schema_meta ON schema_meta.id = journal.schema_id
WHERE schema_meta.name = $1
)
SELECT id,
to_jsonb(positioned) - 'schema_id' - 'picker_position' AS data,
picker_position
FROM positioned
ORDER BY picker_position DESC
LIMIT $2 OFFSET $3"#,
)
.bind(profile_name)
.bind(limit as i64)
.bind(offset as i64)
.fetch_all(pool)
.await
.map_err(|error| Status::internal(format!("Journal list query failed: {}", error)))?;
Ok(rows
.into_iter()
.map(|row| {
let id: i64 = row.try_get("id").unwrap_or_default();
let json_data: serde_json::Value = row.try_get("data").unwrap_or_default();
let position: i64 = row.try_get("picker_position").unwrap_or_default();
Hit {
id,
score: 0.0,
row_display_value: row_display_value(&json_data, "journal_name"),
content_json: json_data.to_string(),
table_name: JOURNAL_SEARCH_TABLE_NAME.to_string(),
row_display_column: "journal_name".to_string(),
position: u64::try_from(position).ok(),
}
})
.collect())
}
async fn run_search(
pool: &PgPool,
profile: &ProfileIndex,
@@ -790,6 +860,11 @@ async fn run_search(
if let Some(order) = order {
let table_name = table_filter.expect("ordered searches require a normalized table filter");
if table_name == JOURNAL_SEARCH_TABLE_NAME {
return Err(Status::invalid_argument(
"Explicit ordering is not supported for journal search",
));
}
return fetch_ordered_candidate_rows(
pool,
profile_name,
@@ -816,16 +891,28 @@ async fn run_search(
let physical_to_display =
table_physical_to_display_map(pool, profile_name, &table_name).await?;
let display_column = table_row_display_column(pool, profile_name, &table_name).await?;
let sql = format!(
"SELECT id, to_jsonb(t) AS data FROM {} t WHERE deleted = FALSE AND id = ANY($1)",
qualify_profile_table(profile_name, &table_name)
);
let rows = sqlx::query(AssertSqlSafe(sql))
let rows = if table_name == JOURNAL_SEARCH_TABLE_NAME {
sqlx::query(
r#"SELECT journal.id, to_jsonb(journal) - 'schema_id' AS data
FROM journal_entries journal
JOIN schemas schema_meta ON schema_meta.id = journal.schema_id
WHERE schema_meta.name = $1 AND journal.id = ANY($2)"#,
)
.bind(profile_name)
.bind(&pg_ids)
.fetch_all(pool)
.await
.map_err(|e| Status::internal(format!("Database query failed: {}", e)))?;
} else {
let sql = format!(
"SELECT id, to_jsonb(t) AS data FROM {} t WHERE deleted = FALSE AND id = ANY($1)",
qualify_profile_table(profile_name, &table_name)
);
sqlx::query(AssertSqlSafe(sql))
.bind(&pg_ids)
.fetch_all(pool)
.await
}
.map_err(|e| Status::internal(format!("Database query failed: {}", e)))?;
for row in rows {
let id: i64 = row.try_get("id").unwrap_or_default();