mant_query/scope_query/
search.rs1use super::{QueryScopeView, ScopeExecutionError};
3use mant_protocol::{ScopeSearch, ScopedSearchDocument, SearchQuery};
4
5pub fn search_scope(
11 input: QueryScopeView<'_>,
12 query: &SearchQuery,
13) -> Result<ScopeSearch, ScopeExecutionError> {
14 let plan = crate::search::SearchPlan::new(query).map_err(ScopeExecutionError::Search)?;
15 let mut total = 0_u32;
16 let mut remaining_skip = query.offset;
17 let mut remaining_take = query.limit;
18 let mut groups = Vec::new();
19 for (scoped, bundle) in input.iter() {
20 let document_ordinal_base = total;
21 let local = plan
22 .execute(bundle, remaining_skip, remaining_take.max(1))
23 .map_err(ScopeExecutionError::Search)?;
24 total = total.saturating_add(local.total);
25 remaining_skip = remaining_skip.saturating_sub(local.total);
26 if remaining_take == 0 || local.matches.is_empty() {
27 continue;
28 }
29 let mut local = local;
30 let mut hits = std::mem::take(&mut local.matches);
31 if u32::try_from(hits.len()).unwrap_or(u32::MAX) > remaining_take {
32 hits.truncate(usize::try_from(remaining_take).unwrap_or(usize::MAX));
33 }
34 for hit in &mut hits {
35 hit.ordinal = document_ordinal_base.saturating_add(hit.ordinal);
36 }
37 remaining_take =
38 remaining_take.saturating_sub(u32::try_from(hits.len()).unwrap_or(u32::MAX));
39 groups.push(ScopedSearchDocument {
40 address: scoped.address.clone(),
41 depth: scoped.depth,
42 render: local.render,
43 matches: hits,
44 });
45 }
46 let returned = query.limit.saturating_sub(remaining_take);
47 let end = query.offset.saturating_add(returned);
48 Ok(ScopeSearch {
49 query: query.clone(),
50 total,
51 returned,
52 offset: query.offset,
53 truncated: end < total,
54 next_offset: (end < total).then_some(end),
55 documents: groups,
56 })
57}