mod sum_of_typos; mod number_of_words; mod words_proximity; mod sum_of_words_attribute; mod sum_of_words_position; mod exact; use std::cmp::Ordering; use std::ops::Deref; use std::marker; use serde::de::DeserializeOwned; use rocksdb::DB; use crate::database::DatabaseView; use crate::rank::Document; pub use self::{ sum_of_typos::SumOfTypos, number_of_words::NumberOfWords, words_proximity::WordsProximity, sum_of_words_attribute::SumOfWordsAttribute, sum_of_words_position::SumOfWordsPosition, exact::Exact, }; pub trait Criterion where D: Deref { #[inline] fn evaluate(&self, lhs: &Document, rhs: &Document, view: &DatabaseView) -> Ordering; #[inline] fn eq(&self, lhs: &Document, rhs: &Document, view: &DatabaseView) -> bool { self.evaluate(lhs, rhs, view) == Ordering::Equal } } impl<'a, D, T: Criterion + ?Sized> Criterion for &'a T where D: Deref { fn evaluate(&self, lhs: &Document, rhs: &Document, view: &DatabaseView) -> Ordering { (**self).evaluate(lhs, rhs, view) } fn eq(&self, lhs: &Document, rhs: &Document, view: &DatabaseView) -> bool { (**self).eq(lhs, rhs, view) } } impl + ?Sized> Criterion for Box where D: Deref { fn evaluate(&self, lhs: &Document, rhs: &Document, view: &DatabaseView) -> Ordering { (**self).evaluate(lhs, rhs, view) } fn eq(&self, lhs: &Document, rhs: &Document, view: &DatabaseView) -> bool { (**self).eq(lhs, rhs, view) } } #[derive(Debug, Clone, Copy)] pub struct DocumentId; impl Criterion for DocumentId where D: Deref { fn evaluate(&self, lhs: &Document, rhs: &Document, _: &DatabaseView) -> Ordering { lhs.id.cmp(&rhs.id) } } /// An helper struct that permit to sort documents by /// some of their stored attributes. /// /// # Note /// /// If a document cannot be deserialized it will be considered [`None`][]. /// /// Deserialized documents are compared like `Some(doc0).cmp(&Some(doc1))`, /// so you must check the [`Ord`] of `Option` implementation. /// /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None /// [`Ord`]: https://doc.rust-lang.org/std/option/enum.Option.html#impl-Ord /// /// # Example /// /// ``` /// use serde_derive::Deserialize; /// use meilidb::rank::criterion::*; /// /// #[derive(Deserialize, PartialOrd, Ord, PartialEq, Eq)] /// struct TimeOnly { /// time: String, /// } /// /// let builder = CriteriaBuilder::with_capacity(7) /// .add(SumOfTypos) /// .add(NumberOfWords) /// .add(WordsProximity) /// .add(SumOfWordsAttribute) /// .add(SumOfWordsPosition) /// .add(Exact) /// .add(SortBy::::new()) /// .add(DocumentId); /// /// let criterion = builder.build(); /// /// ``` #[derive(Default)] pub struct SortBy { _phantom: marker::PhantomData, } impl SortBy { pub fn new() -> Self { SortBy { _phantom: marker::PhantomData } } } impl Criterion for SortBy where D: Deref, T: DeserializeOwned + Ord, { fn evaluate(&self, lhs: &Document, rhs: &Document, view: &DatabaseView) -> Ordering { let lhs = match view.retrieve_document::(lhs.id) { Ok(doc) => Some(doc), Err(e) => { eprintln!("{}", e); None }, }; let rhs = match view.retrieve_document::(rhs.id) { Ok(doc) => Some(doc), Err(e) => { eprintln!("{}", e); None }, }; lhs.cmp(&rhs) } } pub struct CriteriaBuilder where D: Deref { inner: Vec>> } impl CriteriaBuilder where D: Deref { pub fn new() -> CriteriaBuilder { CriteriaBuilder { inner: Vec::new() } } pub fn with_capacity(capacity: usize) -> CriteriaBuilder { CriteriaBuilder { inner: Vec::with_capacity(capacity) } } pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) } pub fn add(mut self, criterion: C) -> CriteriaBuilder where C: 'static + Criterion, { self.push(criterion); self } pub fn push(&mut self, criterion: C) where C: 'static + Criterion, { self.inner.push(Box::new(criterion)); } pub fn build(self) -> Vec>> { self.inner } } pub fn default() -> Vec>> where D: Deref { CriteriaBuilder::with_capacity(7) .add(SumOfTypos) .add(NumberOfWords) .add(WordsProximity) .add(SumOfWordsAttribute) .add(SumOfWordsPosition) .add(Exact) .add(DocumentId) .build() }