1use std::fmt;
2
3use async_trait::async_trait;
4use downcast_rs::impl_downcast;
5
6use super::Weight;
7use crate::core::searcher::Searcher;
8use crate::query::Explanation;
9use crate::schema::Schema;
10use crate::{DocAddress, Term};
11
12#[derive(Copy, Clone)]
14pub enum EnableScoring<'a> {
15 Enabled(&'a Searcher),
17 Disabled {
20 schema: &'a Schema,
22 searcher_opt: Option<&'a Searcher>,
24 },
25}
26
27impl<'a> EnableScoring<'a> {
28 pub fn enabled_from_searcher(searcher: &'a Searcher) -> EnableScoring<'a> {
30 EnableScoring::Enabled(searcher)
31 }
32
33 pub fn disabled_from_searcher(searcher: &'a Searcher) -> EnableScoring<'a> {
35 EnableScoring::Disabled {
36 schema: searcher.schema(),
37 searcher_opt: Some(searcher),
38 }
39 }
40
41 pub fn disabled_from_schema(schema: &'a Schema) -> EnableScoring<'a> {
43 Self::Disabled {
44 schema,
45 searcher_opt: None,
46 }
47 }
48
49 pub fn searcher(&self) -> Option<&Searcher> {
51 match self {
52 EnableScoring::Enabled(searcher) => Some(searcher),
53 EnableScoring::Disabled { searcher_opt, .. } => searcher_opt.to_owned(),
54 }
55 }
56
57 pub fn schema(&self) -> &Schema {
59 match self {
60 EnableScoring::Enabled(searcher) => searcher.schema(),
61 EnableScoring::Disabled { schema, .. } => schema,
62 }
63 }
64
65 pub fn is_scoring_enabled(&self) -> bool {
67 matches!(self, EnableScoring::Enabled(..))
68 }
69}
70
71#[async_trait]
106pub trait Query: QueryClone + Send + Sync + downcast_rs::Downcast + fmt::Debug {
107 fn weight(&self, enable_scoring: EnableScoring<'_>) -> crate::Result<Box<dyn Weight>>;
114
115 #[cfg(feature = "quickwit")]
119 async fn weight_async(
120 &self,
121 enable_scoring: EnableScoring<'_>,
122 ) -> crate::Result<Box<dyn Weight>>;
123
124 fn explain(&self, searcher: &Searcher, doc_address: DocAddress) -> crate::Result<Explanation> {
126 let weight = self.weight(EnableScoring::enabled_from_searcher(searcher))?;
127 let reader = searcher.segment_reader(doc_address.segment_ord);
128 weight.explain(reader, doc_address.doc_id)
129 }
130
131 fn count(&self, searcher: &Searcher) -> crate::Result<usize> {
133 let weight = self.weight(EnableScoring::disabled_from_searcher(searcher))?;
134 let mut result = 0;
135 for reader in searcher.segment_readers() {
136 result += weight.count(reader)? as usize;
137 }
138 Ok(result)
139 }
140
141 #[cfg(feature = "quickwit")]
143 async fn count_async(&self, searcher: &Searcher) -> crate::Result<usize> {
144 let weight = self
145 .weight_async(EnableScoring::disabled_from_schema(searcher.schema()))
146 .await?;
147 let mut result = 0;
148 for reader in searcher.segment_readers() {
149 result += weight.count_async(reader).await? as usize;
150 }
151 Ok(result)
152 }
153
154 fn query_terms<'a>(&'a self, _visitor: &mut dyn FnMut(&'a Term, bool)) {}
163}
164
165pub trait QueryClone {
167 fn box_clone(&self) -> Box<dyn Query>;
169}
170
171impl<T> QueryClone for T
172where T: 'static + Query + Clone
173{
174 fn box_clone(&self) -> Box<dyn Query> {
175 Box::new(self.clone())
176 }
177}
178
179#[async_trait]
180impl Query for Box<dyn Query> {
181 fn weight(&self, enabled_scoring: EnableScoring) -> crate::Result<Box<dyn Weight>> {
182 self.as_ref().weight(enabled_scoring)
183 }
184
185 #[cfg(feature = "quickwit")]
186 async fn weight_async(
187 &self,
188 enable_scoring: EnableScoring<'_>,
189 ) -> crate::Result<Box<dyn Weight>> {
190 self.as_ref().weight_async(enable_scoring).await
191 }
192
193 fn count(&self, searcher: &Searcher) -> crate::Result<usize> {
194 self.as_ref().count(searcher)
195 }
196
197 fn query_terms<'a>(&'a self, visitor: &mut dyn FnMut(&'a Term, bool)) {
198 self.as_ref().query_terms(visitor);
199 }
200}
201
202impl QueryClone for Box<dyn Query> {
203 fn box_clone(&self) -> Box<dyn Query> {
204 self.as_ref().box_clone()
205 }
206}
207
208impl_downcast!(Query);