use std::fmt;
use async_trait::async_trait;
use downcast_rs::impl_downcast;
use super::Weight;
use crate::core::searcher::Searcher;
use crate::query::Explanation;
use crate::schema::Schema;
use crate::{DocAddress, Term};
#[derive(Copy, Clone)]
pub enum EnableScoring<'a> {
Enabled(&'a Searcher),
Disabled {
schema: &'a Schema,
searcher_opt: Option<&'a Searcher>,
},
}
impl<'a> EnableScoring<'a> {
pub fn enabled_from_searcher(searcher: &'a Searcher) -> EnableScoring<'a> {
EnableScoring::Enabled(searcher)
}
pub fn disabled_from_searcher(searcher: &'a Searcher) -> EnableScoring<'a> {
EnableScoring::Disabled {
schema: searcher.schema(),
searcher_opt: Some(searcher),
}
}
pub fn disabled_from_schema(schema: &'a Schema) -> EnableScoring<'a> {
Self::Disabled {
schema,
searcher_opt: None,
}
}
pub fn searcher(&self) -> Option<&Searcher> {
match self {
EnableScoring::Enabled(searcher) => Some(searcher),
EnableScoring::Disabled { searcher_opt, .. } => searcher_opt.to_owned(),
}
}
pub fn schema(&self) -> &Schema {
match self {
EnableScoring::Enabled(searcher) => searcher.schema(),
EnableScoring::Disabled { schema, .. } => schema,
}
}
pub fn is_scoring_enabled(&self) -> bool {
matches!(self, EnableScoring::Enabled(..))
}
}
#[async_trait]
pub trait Query: QueryClone + Send + Sync + downcast_rs::Downcast + fmt::Debug {
fn weight(&self, enable_scoring: EnableScoring<'_>) -> crate::Result<Box<dyn Weight>>;
#[cfg(feature = "quickwit")]
async fn weight_async(
&self,
enable_scoring: EnableScoring<'_>,
) -> crate::Result<Box<dyn Weight>>;
fn explain(&self, searcher: &Searcher, doc_address: DocAddress) -> crate::Result<Explanation> {
let weight = self.weight(EnableScoring::enabled_from_searcher(searcher))?;
let reader = searcher.segment_reader(doc_address.segment_ord);
weight.explain(reader, doc_address.doc_id)
}
fn count(&self, searcher: &Searcher) -> crate::Result<usize> {
let weight = self.weight(EnableScoring::disabled_from_searcher(searcher))?;
let mut result = 0;
for reader in searcher.segment_readers() {
result += weight.count(reader)? as usize;
}
Ok(result)
}
#[cfg(feature = "quickwit")]
async fn count_async(&self, searcher: &Searcher) -> crate::Result<usize> {
let weight = self
.weight_async(EnableScoring::disabled_from_schema(searcher.schema()))
.await?;
let mut result = 0;
for reader in searcher.segment_readers() {
result += weight.count_async(reader).await? as usize;
}
Ok(result)
}
fn query_terms<'a>(&'a self, _visitor: &mut dyn FnMut(&'a Term, bool)) {}
}
pub trait QueryClone {
fn box_clone(&self) -> Box<dyn Query>;
}
impl<T> QueryClone for T
where T: 'static + Query + Clone
{
fn box_clone(&self) -> Box<dyn Query> {
Box::new(self.clone())
}
}
#[async_trait]
impl Query for Box<dyn Query> {
fn weight(&self, enabled_scoring: EnableScoring) -> crate::Result<Box<dyn Weight>> {
self.as_ref().weight(enabled_scoring)
}
#[cfg(feature = "quickwit")]
async fn weight_async(
&self,
enable_scoring: EnableScoring<'_>,
) -> crate::Result<Box<dyn Weight>> {
self.as_ref().weight_async(enable_scoring).await
}
fn count(&self, searcher: &Searcher) -> crate::Result<usize> {
self.as_ref().count(searcher)
}
fn query_terms<'a>(&'a self, visitor: &mut dyn FnMut(&'a Term, bool)) {
self.as_ref().query_terms(visitor);
}
}
impl QueryClone for Box<dyn Query> {
fn box_clone(&self) -> Box<dyn Query> {
self.as_ref().box_clone()
}
}
impl_downcast!(Query);