1use crate::Candidate;
7use crate::CandidateFilter;
8use crate::SearchOutput;
9use crate::SearchQuery;
10use crate::SearchSeparators;
11use crate::SearchStats;
12use crate::index::Indexes;
13use crate::query::QueryPlanner;
14use crate::search::SearchError;
15use crate::search::SearchOutcome;
16use crate::search::candidates::walk;
17use crate::search::request::SearchExecution;
18use rayon::prelude::*;
19
20pub struct GrepRequest<'a> {
22 pub indexes: &'a Indexes,
23 pub filter: &'a CandidateFilter,
24 pub output: SearchOutput,
25 pub separators: &'a SearchSeparators,
26 pub collect_stats: bool,
27}
28
29impl GrepRequest<'_> {
30 pub fn run(&self, query: &SearchQuery) -> crate::Result<SearchOutcome> {
36 if query.opts.max_results == Some(0) {
37 return Err(crate::Error::Search(SearchError::InvalidMaxCount));
38 }
39
40 let spec = query.spec();
41 let output = self.output;
42
43 let raw = QueryPlanner::new(spec).candidates(
44 self.indexes,
45 output.candidate_requirement(),
46 || walk::collect_candidates(self.filter),
47 )?;
48
49 let candidates: Vec<Candidate> = raw
50 .into_par_iter()
51 .filter(|c| c.matches(self.filter))
52 .collect();
53
54 if candidates.is_empty() {
55 return Ok(SearchOutcome {
56 matched: false,
57 stats: self.collect_stats.then_some(SearchStats::default()),
58 });
59 }
60
61 query.search(&SearchExecution {
62 candidates,
63 output,
64 separators: self.separators,
65 collect_stats: self.collect_stats,
66 })
67 }
68}