diff --git a/meilidb-core/src/database.rs b/meilidb-core/src/database.rs index 5210db72f..3a614f708 100644 --- a/meilidb-core/src/database.rs +++ b/meilidb-core/src/database.rs @@ -226,7 +226,10 @@ impl Database { #[cfg(test)] mod tests { use super::*; + use crate::update::{ProcessedUpdateResult, UpdateStatus}; + use crate::DocumentId; + use serde::de::IgnoredAny; use std::sync::mpsc; #[test] @@ -529,4 +532,85 @@ mod tests { let result = index.update_status(&reader, update_id).unwrap(); assert_matches!(result, UpdateStatus::Processed(status) if status.result.is_err()); } + + #[test] + fn deserialize_documents() { + 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 |update: ProcessedUpdateResult| sender.send(update.update_id).unwrap(); + let index = database.create_index("test").unwrap(); + + let done = database.set_update_callback("test", Box::new(update_fn)); + assert!(done, "could not set the index update function"); + + let schema = { + let data = r#" + identifier = "id" + + [attributes."name"] + displayed = true + indexed = true + + [attributes."description"] + displayed = true + indexed = true + "#; + toml::from_str(data).unwrap() + }; + + let mut writer = env.write_txn().unwrap(); + let _update_id = index.schema_update(&mut writer, schema).unwrap(); + + // don't forget to commit... + writer.commit().unwrap(); + + let mut additions = index.documents_addition(); + + // DocumentId(7900334843754999545) + let doc1 = serde_json::json!({ + "id": 123, + "name": "Marvin", + "description": "My name is Marvin", + }); + + // DocumentId(8367468610878465872) + let doc2 = serde_json::json!({ + "id": 234, + "name": "Kevin", + "description": "My name is Kevin", + }); + + additions.update_document(doc1); + additions.update_document(doc2); + + let mut writer = env.write_txn().unwrap(); + let update_id = additions.finalize(&mut writer).unwrap(); + + // don't forget to commit... + 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 result = index.update_status(&reader, update_id).unwrap(); + assert_matches!(result, UpdateStatus::Processed(status) if status.result.is_ok()); + + let document: Option = index.document(&reader, None, DocumentId(25)).unwrap(); + assert!(document.is_none()); + + let document: Option = index + .document(&reader, None, DocumentId(7900334843754999545)) + .unwrap(); + assert!(document.is_some()); + + let document: Option = index + .document(&reader, None, DocumentId(8367468610878465872)) + .unwrap(); + assert!(document.is_some()); + } } diff --git a/meilidb-core/src/serde/deserializer.rs b/meilidb-core/src/serde/deserializer.rs index 3c6955cdf..61a805d58 100644 --- a/meilidb-core/src/serde/deserializer.rs +++ b/meilidb-core/src/serde/deserializer.rs @@ -63,13 +63,14 @@ impl<'de, 'a, 'b> de::Deserializer<'de> for &'b mut Deserializer<'a> { where V: de::Visitor<'de>, { - self.deserialize_map(visitor) + self.deserialize_option(visitor) } - forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string - bytes byte_buf option unit unit_struct newtype_struct seq tuple - tuple_struct struct enum identifier ignored_any + fn deserialize_option(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.deserialize_map(visitor) } fn deserialize_map(self, visitor: V) -> Result @@ -104,16 +105,29 @@ impl<'de, 'a, 'b> de::Deserializer<'de> for &'b mut Deserializer<'a> { } }); - let map_deserializer = de::value::MapDeserializer::new(iter); - let result = visitor - .visit_map(map_deserializer) - .map_err(DeserializerError::from); + let mut iter = iter.peekable(); + + let result = match iter.peek() { + Some(_) => { + let map_deserializer = de::value::MapDeserializer::new(iter); + visitor + .visit_some(map_deserializer) + .map_err(DeserializerError::from) + } + None => visitor.visit_none(), + }; match error.take() { Some(error) => Err(error.into()), None => result, } } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf unit unit_struct newtype_struct seq tuple + tuple_struct struct enum identifier ignored_any + } } struct Value(SerdeJsonDeserializer>>>); diff --git a/meilidb-core/src/store/mod.rs b/meilidb-core/src/store/mod.rs index 72317e202..ed2a5e328 100644 --- a/meilidb-core/src/store/mod.rs +++ b/meilidb-core/src/store/mod.rs @@ -22,7 +22,7 @@ use std::collections::HashSet; use heed::Result as ZResult; use meilidb_schema::{Schema, SchemaAttr}; -use serde::de; +use serde::de::{self, Deserialize}; use zerocopy::{AsBytes, FromBytes}; use crate::criterion::Criteria; @@ -120,9 +120,7 @@ impl Index { attributes: attributes.as_ref(), }; - // TODO: currently we return an error if all document fields are missing, - // returning None would have been better - Ok(T::deserialize(&mut deserializer).map(Some)?) + Ok(Option::::deserialize(&mut deserializer)?) } pub fn document_attribute(