Skip to main content

sift_core/query/
planner.rs

1use crate::Candidate;
2use crate::index::Indexes;
3use crate::query::QuerySpec;
4
5/// Whether search needs all candidate paths or only potential matches.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum CandidateRequirement {
8    Complete,
9    PotentialMatches,
10}
11
12/// Plans candidate selection by combining indexes and a lazy base provider.
13pub struct QueryPlanner<'a> {
14    spec: QuerySpec<'a>,
15}
16
17impl<'a> QueryPlanner<'a> {
18    #[must_use]
19    pub const fn new(spec: QuerySpec<'a>) -> Self {
20        Self { spec }
21    }
22
23    /// Resolve candidates using indexes or the lazy base provider.
24    ///
25    /// # Errors
26    ///
27    /// Delegates to `base` when fallback is triggered; returns `base` errors unchanged.
28    pub fn candidates(
29        &self,
30        indexes: &Indexes,
31        requirement: CandidateRequirement,
32        base: impl FnOnce() -> crate::Result<Vec<Candidate>>,
33    ) -> crate::Result<Vec<Candidate>> {
34        match requirement {
35            CandidateRequirement::Complete => {
36                if indexes.is_empty() {
37                    base()
38                } else {
39                    Ok(indexes.complete_candidates())
40                }
41            }
42            CandidateRequirement::PotentialMatches => {
43                if indexes.is_empty() {
44                    return base();
45                }
46                indexes.candidates(&self.spec).map_or_else(base, Ok)
47            }
48        }
49    }
50}