use std::collections::BTreeSet;
use qql::executor::SearchHit;
use super::cell::{Alignment, Cell};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum QueryColumnSource {
Metadata(&'static str),
Payload(String),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct QueryColumn {
pub label: String,
pub source: QueryColumnSource,
}
pub fn detect_query_columns(hits: &[SearchHit], scored: bool) -> Vec<QueryColumn> {
let mut cols = vec![QueryColumn {
label: "id".into(),
source: QueryColumnSource::Metadata("id"),
}];
if scored {
cols.push(QueryColumn {
label: "score".into(),
source: QueryColumnSource::Metadata("score"),
});
}
if hits.iter().any(|hit| hit.collection.is_some()) {
cols.push(QueryColumn {
label: "collection".into(),
source: QueryColumnSource::Metadata("collection"),
});
}
let mut payload_keys = BTreeSet::new();
for hit in hits {
if let Some(payload) = &hit.payload {
for key in payload.keys() {
payload_keys.insert(key.clone());
}
}
}
for key in payload_keys {
let mut label = if matches!(key.as_str(), "id" | "score" | "collection") {
format!("payload.{key}")
} else {
key.clone()
};
while cols.iter().any(|column| column.label == label) {
label = format!("payload.{label}");
}
cols.push(QueryColumn {
label,
source: QueryColumnSource::Payload(key),
});
}
cols
}
pub fn query_cell(hit: &SearchHit, column: &QueryColumn) -> Cell {
match &column.source {
QueryColumnSource::Metadata("id") => Cell::text(hit.id.to_string()),
QueryColumnSource::Metadata("score") => Cell {
value: hit.score.to_string(),
alignment: Alignment::Right,
},
QueryColumnSource::Metadata("collection") => {
Cell::text(hit.collection.as_deref().unwrap_or_default())
}
QueryColumnSource::Payload(key) => {
Cell::from_json(hit.payload.as_ref().and_then(|payload| payload.get(key)))
}
QueryColumnSource::Metadata(_) => Cell::text(""),
}
}