use aspero_core::{FieldSet, ProviderId, SourceRecord, Usage, WorkId};
use crate::Engine;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Abstract {
pub text: String,
pub source: ProviderId,
}
#[derive(Debug, Clone, Default)]
pub struct AbstractsReport {
pub found: Vec<Option<Abstract>>,
pub usage: Vec<(ProviderId, Usage)>,
}
impl Engine {
pub async fn abstracts(&self, works: &[&SourceRecord]) -> AbstractsReport {
let mut found: Vec<Option<Abstract>> = works
.iter()
.map(|r| {
non_blank(r.work.abstract_text.clone()).map(|text| Abstract {
text,
source: r.source.clone(),
})
})
.collect();
let mut usage = Vec::new();
for entry in &self.entries {
let provider = entry.provider.id();
let kinds = &entry.provider.capabilities().lookup_kinds;
let wanted: Vec<(usize, WorkId)> = works
.iter()
.enumerate()
.filter(|(i, r)| found[*i].is_none() && r.source != provider)
.filter_map(|(i, r)| {
let id = r.ids.iter().find(|id| kinds.contains(&id.kind()))?;
Some((i, id.clone()))
})
.collect();
if wanted.is_empty() {
continue;
}
let ids: Vec<WorkId> = wanted.iter().map(|(_, id)| id.clone()).collect();
let answers = self.lookup_at(entry, &ids, FieldSet::ALL, &mut usage).await;
for ((i, _), (_, record)) in wanted.into_iter().zip(answers) {
if let Some(text) = record.and_then(|r| non_blank(r.work.abstract_text)) {
found[i] = Some(Abstract {
text,
source: provider.clone(),
});
}
}
}
AbstractsReport { found, usage }
}
}
fn non_blank(text: Option<String>) -> Option<String> {
text.filter(|t| !t.trim().is_empty())
}