2018-10-10 16:57:21 +02:00
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 ;
2018-12-07 17:59:03 +01:00
use std ::ops ::Deref ;
2018-12-10 12:10:59 +01:00
use std ::marker ;
2018-12-07 17:59:03 +01:00
2018-12-10 12:10:59 +01:00
use serde ::de ::DeserializeOwned ;
2018-12-07 17:59:03 +01:00
use rocksdb ::DB ;
2018-12-07 14:41:06 +01:00
use crate ::database ::DatabaseView ;
2018-10-10 16:57:21 +02:00
use crate ::rank ::Document ;
pub use self ::{
2018-10-11 14:04:41 +02:00
sum_of_typos ::SumOfTypos ,
number_of_words ::NumberOfWords ,
words_proximity ::WordsProximity ,
sum_of_words_attribute ::SumOfWordsAttribute ,
sum_of_words_position ::SumOfWordsPosition ,
exact ::Exact ,
2018-10-10 16:57:21 +02:00
} ;
2018-12-07 17:59:03 +01:00
pub trait Criterion < D >
where D : Deref < Target = DB >
{
2018-10-11 14:04:41 +02:00
#[ inline ]
2018-12-07 17:59:03 +01:00
fn evaluate ( & self , lhs : & Document , rhs : & Document , view : & DatabaseView < D > ) -> Ordering ;
2018-10-10 16:57:21 +02:00
2018-10-11 14:04:41 +02:00
#[ inline ]
2018-12-07 17:59:03 +01:00
fn eq ( & self , lhs : & Document , rhs : & Document , view : & DatabaseView < D > ) -> bool {
2018-12-07 14:41:06 +01:00
self . evaluate ( lhs , rhs , view ) = = Ordering ::Equal
2018-10-11 14:04:41 +02:00
}
}
2018-10-10 16:57:21 +02:00
2018-12-07 17:59:03 +01:00
impl < ' a , D , T : Criterion < D > + ? Sized > Criterion < D > for & ' a T
where D : Deref < Target = DB >
{
fn evaluate ( & self , lhs : & Document , rhs : & Document , view : & DatabaseView < D > ) -> Ordering {
2018-12-07 14:41:06 +01:00
( * * self ) . evaluate ( lhs , rhs , view )
2018-10-10 16:57:21 +02:00
}
2018-12-07 17:59:03 +01:00
fn eq ( & self , lhs : & Document , rhs : & Document , view : & DatabaseView < D > ) -> bool {
2018-12-07 14:41:06 +01:00
( * * self ) . eq ( lhs , rhs , view )
2018-10-10 16:57:21 +02:00
}
2018-10-11 14:04:41 +02:00
}
2018-10-10 16:57:21 +02:00
2018-12-07 17:59:03 +01:00
impl < D , T : Criterion < D > + ? Sized > Criterion < D > for Box < T >
where D : Deref < Target = DB >
{
fn evaluate ( & self , lhs : & Document , rhs : & Document , view : & DatabaseView < D > ) -> Ordering {
2018-12-07 14:41:06 +01:00
( * * self ) . evaluate ( lhs , rhs , view )
2018-10-10 16:57:21 +02:00
}
2018-12-07 17:59:03 +01:00
fn eq ( & self , lhs : & Document , rhs : & Document , view : & DatabaseView < D > ) -> bool {
2018-12-07 14:41:06 +01:00
( * * self ) . eq ( lhs , rhs , view )
2018-10-10 16:57:21 +02:00
}
}
2018-10-11 14:04:41 +02:00
#[ derive(Debug, Clone, Copy) ]
pub struct DocumentId ;
2018-10-10 16:57:21 +02:00
2018-12-07 17:59:03 +01:00
impl < D > Criterion < D > for DocumentId
where D : Deref < Target = DB >
{
fn evaluate ( & self , lhs : & Document , rhs : & Document , _ : & DatabaseView < D > ) -> Ordering {
2018-10-11 14:04:41 +02:00
lhs . id . cmp ( & rhs . id )
2018-10-10 16:57:21 +02:00
}
}
2018-12-10 12:10:59 +01:00
/// 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::<TimeOnly>::new())
/// .add(DocumentId);
///
/// let criterion = builder.build();
///
/// ```
#[ derive(Default) ]
pub struct SortBy < T > {
_phantom : marker ::PhantomData < T > ,
}
impl < T > SortBy < T > {
pub fn new ( ) -> Self {
SortBy { _phantom : marker ::PhantomData }
}
}
impl < T , D > Criterion < D > for SortBy < T >
where D : Deref < Target = DB > ,
T : DeserializeOwned + Ord ,
{
fn evaluate ( & self , lhs : & Document , rhs : & Document , view : & DatabaseView < D > ) -> Ordering {
let lhs = match view . retrieve_document ::< T > ( lhs . id ) {
Ok ( doc ) = > Some ( doc ) ,
Err ( e ) = > { eprintln! ( " {} " , e ) ; None } ,
} ;
let rhs = match view . retrieve_document ::< T > ( rhs . id ) {
Ok ( doc ) = > Some ( doc ) ,
Err ( e ) = > { eprintln! ( " {} " , e ) ; None } ,
} ;
lhs . cmp ( & rhs )
}
}
2018-12-10 11:36:09 +01:00
pub struct CriteriaBuilder < D >
where D : Deref < Target = DB >
{
inner : Vec < Box < dyn Criterion < D > > >
}
impl < D > CriteriaBuilder < D >
where D : Deref < Target = DB >
{
pub fn new ( ) -> CriteriaBuilder < D > {
CriteriaBuilder { inner : Vec ::new ( ) }
}
pub fn with_capacity ( capacity : usize ) -> CriteriaBuilder < D > {
CriteriaBuilder { inner : Vec ::with_capacity ( capacity ) }
}
pub fn reserve ( & mut self , additional : usize ) {
self . inner . reserve ( additional )
}
pub fn add < C > ( mut self , criterion : C ) -> CriteriaBuilder < D >
where C : 'static + Criterion < D > ,
{
self . push ( criterion ) ;
self
}
pub fn push < C > ( & mut self , criterion : C )
where C : 'static + Criterion < D > ,
{
self . inner . push ( Box ::new ( criterion ) ) ;
}
pub fn build ( self ) -> Vec < Box < dyn Criterion < D > > > {
self . inner
}
}
2018-12-07 17:59:03 +01:00
pub fn default < D > ( ) -> Vec < Box < dyn Criterion < D > > >
where D : Deref < Target = DB >
{
2018-12-10 11:36:09 +01:00
CriteriaBuilder ::with_capacity ( 7 )
. add ( SumOfTypos )
. add ( NumberOfWords )
. add ( WordsProximity )
. add ( SumOfWordsAttribute )
. add ( SumOfWordsPosition )
. add ( Exact )
. add ( DocumentId )
. build ( )
2018-10-10 16:57:21 +02:00
}