From d9678f004029d7f4ce5d68c5e8f9c1a08afd0423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 20 Nov 2019 15:16:52 +0100 Subject: [PATCH 1/2] Fix the ordering functions of the Number type --- meilidb-core/src/number.rs | 47 +++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/meilidb-core/src/number.rs b/meilidb-core/src/number.rs index ff3419008..7817be3e5 100644 --- a/meilidb-core/src/number.rs +++ b/meilidb-core/src/number.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::fmt; use std::num::{ParseFloatError, ParseIntError}; use std::str::FromStr; @@ -5,7 +6,7 @@ use std::str::FromStr; use ordered_float::OrderedFloat; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, Hash)] pub enum Number { Unsigned(u64), Signed(i64), @@ -39,6 +40,50 @@ impl FromStr for Number { } } +impl PartialEq for Number { + fn eq(&self, other: &Number) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl Eq for Number {} + +impl PartialOrd for Number { + fn partial_cmp(&self, other: &Number) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Number { + fn cmp(&self, other: &Self) -> Ordering { + use Number::{Float, Signed, Unsigned}; + + match (*self, *other) { + (Unsigned(a), Unsigned(b)) => a.cmp(&b), + (Unsigned(a), Signed(b)) => { + if b < 0 { + Ordering::Greater + } else { + a.cmp(&(b as u64)) + } + } + (Unsigned(a), Float(b)) => (OrderedFloat(a as f64)).cmp(&b), + (Signed(a), Unsigned(b)) => { + if a < 0 { + Ordering::Less + } else { + (a as u64).cmp(&b) + } + } + (Signed(a), Signed(b)) => a.cmp(&b), + (Signed(a), Float(b)) => OrderedFloat(a as f64).cmp(&b), + (Float(a), Unsigned(b)) => a.cmp(&OrderedFloat(b as f64)), + (Float(a), Signed(b)) => a.cmp(&OrderedFloat(b as f64)), + (Float(a), Float(b)) => a.cmp(&b), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct ParseNumberError { uint_error: ParseIntError, From fd185a5e6b3ce36b7dad7da37404c1a53b03fc18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Fri, 22 Nov 2019 14:43:00 +0100 Subject: [PATCH 2/2] Add a test for the SorByAttr criterion --- meilidb-core/src/database.rs | 98 +++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/meilidb-core/src/database.rs b/meilidb-core/src/database.rs index 894193fa2..d63c79a71 100644 --- a/meilidb-core/src/database.rs +++ b/meilidb-core/src/database.rs @@ -277,8 +277,9 @@ impl Database { mod tests { use super::*; + use crate::criterion::{self, CriteriaBuilder}; use crate::update::{ProcessedUpdateResult, UpdateStatus}; - use crate::DocumentId; + use crate::{Document, DocumentId}; use serde::de::IgnoredAny; use std::sync::mpsc; @@ -912,4 +913,99 @@ mod tests { let result = database.open_index("test"); assert!(result.is_none()); } + + #[test] + fn check_number_ordering() { + let dir = tempfile::tempdir().unwrap(); + + let database = Database::open_or_create(dir.path()).unwrap(); + let env = &database.env; + + let (sender, receiver) = mpsc::sync_channel(100); + let update_fn = move |_name: &str, update: ProcessedUpdateResult| { + sender.send(update.update_id).unwrap() + }; + let index = database.create_index("test").unwrap(); + + database.set_update_callback(Box::new(update_fn)); + + let schema = { + let data = r#" + identifier = "id" + + [attributes."name"] + displayed = true + indexed = true + + [attributes."release_date"] + displayed = true + ranked = true + "#; + toml::from_str(data).unwrap() + }; + + let mut writer = env.write_txn().unwrap(); + let _update_id = index.schema_update(&mut writer, schema).unwrap(); + writer.commit().unwrap(); + + let mut additions = index.documents_addition(); + + // DocumentId(7900334843754999545) + let doc1 = serde_json::json!({ + "id": 123, + "name": "Kevin the first", + "release_date": -10000, + }); + + // DocumentId(8367468610878465872) + let doc2 = serde_json::json!({ + "id": 234, + "name": "Kevin the second", + "release_date": 10000, + }); + + additions.update_document(doc1); + additions.update_document(doc2); + + let mut writer = env.write_txn().unwrap(); + let update_id = additions.finalize(&mut writer).unwrap(); + writer.commit().unwrap(); + + // block until the transaction is processed + let _ = receiver.into_iter().find(|id| *id == update_id); + + let reader = env.read_txn().unwrap(); + + let schema = index.main.schema(&reader).unwrap().unwrap(); + let ranked_map = index.main.ranked_map(&reader).unwrap().unwrap(); + + let criteria = CriteriaBuilder::new() + .add( + criterion::SortByAttr::lower_is_better(&ranked_map, &schema, "release_date") + .unwrap(), + ) + .add(criterion::DocumentId) + .build(); + + let builder = index.query_builder_with_criteria(criteria); + + let results = builder.query(&reader, "Kevin", 0..20).unwrap(); + let mut iter = results.into_iter(); + + assert_matches!( + iter.next(), + Some(Document { + id: DocumentId(7900334843754999545), + .. + }) + ); + assert_matches!( + iter.next(), + Some(Document { + id: DocumentId(8367468610878465872), + .. + }) + ); + assert_matches!(iter.next(), None); + } }