diff options
author | Mauro D <mauro@stalw.art> | 2023-05-03 15:55:32 +0000 |
---|---|---|
committer | Mauro D <mauro@stalw.art> | 2023-05-03 15:55:32 +0000 |
commit | 60fa410aa55f02d7956d9c5fcae8b8cc69f91627 (patch) | |
tree | 07bc4f742398683c944893be5ff50b6d692e85e2 /crates/jmap-proto | |
parent | a3a0396772cfbfe8573ad15851acd19cacdc6499 (diff) |
Mailbox tests passing.
Diffstat (limited to 'crates/jmap-proto')
-rw-r--r-- | crates/jmap-proto/src/object/index.rs | 304 | ||||
-rw-r--r-- | crates/jmap-proto/src/response/references.rs | 83 |
2 files changed, 192 insertions, 195 deletions
diff --git a/crates/jmap-proto/src/object/index.rs b/crates/jmap-proto/src/object/index.rs index f74fe7d1..21701983 100644 --- a/crates/jmap-proto/src/object/index.rs +++ b/crates/jmap-proto/src/object/index.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, collections::HashSet}; use store::{ fts::builder::ToTokens, - write::{BatchBuilder, IntoOperations, Operation}, + write::{BatchBuilder, BitmapFamily, IntoOperations, Operation}, Serialize, BM_TAG, HASH_EXACT, }; @@ -124,7 +124,7 @@ impl IntoOperations for ObjectIndexBuilder { } (Some(current), None) => { // Deletion - build_batch(batch, self.index, ¤t, true); + build_batch(batch, self.index, ¤t, false); batch.ops.push(Operation::Value { field: Property::Value.into(), family: 0, @@ -149,190 +149,186 @@ fn merge_batch( if current_value == &value { continue; } - match index - .iter() - .find_map(|i| { - if i.property == property { - Some(i.index_as) - } else { - None - } - }) - .unwrap_or_default() - { - IndexAs::Text { tokenize, index } => { - // Remove current text from index - let mut add_tokens = HashSet::new(); - let mut remove_tokens = HashSet::new(); - if let Some(text) = current_value.as_string() { - if index { - batch.ops.push(Operation::Index { - field: property.clone().into(), - key: text.serialize(), - set: false, - }); - } - if tokenize { - remove_tokens = text.to_tokens(); - } - } - // Add new text to index - if let Some(text) = value.as_string() { - if index { - batch.ops.push(Operation::Index { - field: property.clone().into(), - key: text.serialize(), - set: true, - }); + for index_property in index { + if index_property.property != property { + continue; + } + match index_property.index_as { + IndexAs::Text { tokenize, index } => { + // Remove current text from index + let mut add_tokens = HashSet::new(); + let mut remove_tokens = HashSet::new(); + if let Some(text) = current_value.as_string() { + if index { + batch.ops.push(Operation::Index { + field: property.clone().into(), + key: text.serialize(), + set: false, + }); + } + if tokenize { + remove_tokens = text.to_tokens(); + } } - if tokenize { - for token in text.to_tokens() { - if !remove_tokens.remove(&token) { - add_tokens.insert(token); + + // Add new text to index + if let Some(text) = value.as_string() { + if index { + batch.ops.push(Operation::Index { + field: property.clone().into(), + key: text.serialize(), + set: true, + }); + } + if tokenize { + for token in text.to_tokens() { + if !remove_tokens.remove(&token) { + add_tokens.insert(token); + } } } } - } - // Update tokens - for (token, set) in [(add_tokens, true), (remove_tokens, false)] { - for token in token { - batch.ops.push(Operation::hash( - &token, - HASH_EXACT, - property.clone().into(), - set, - )); + // Update tokens + for (token, set) in [(add_tokens, true), (remove_tokens, false)] { + for token in token { + batch.ops.push(Operation::hash( + &token, + HASH_EXACT, + property.clone().into(), + set, + )); + } } } - } - IndexAs::TextList { tokenize, index } => { - let mut add_tokens = HashSet::new(); - let mut remove_tokens = HashSet::new(); - let mut add_values = HashSet::new(); - let mut remove_values = HashSet::new(); - - // Remove current text from index - if let Some(current_values) = current_value.as_list() { - for current_value in current_values { - if let Some(text) = current_value.as_string() { - if index { - remove_values.insert(text); - } - if tokenize { - remove_tokens.extend(text.to_tokens()); + IndexAs::TextList { tokenize, index } => { + let mut add_tokens = HashSet::new(); + let mut remove_tokens = HashSet::new(); + let mut add_values = HashSet::new(); + let mut remove_values = HashSet::new(); + + // Remove current text from index + if let Some(current_values) = current_value.as_list() { + for current_value in current_values { + if let Some(text) = current_value.as_string() { + if index { + remove_values.insert(text); + } + if tokenize { + remove_tokens.extend(text.to_tokens()); + } } } } - } - // Add new text to index - if let Some(values) = value.as_list() { - for value in values { - if let Some(text) = value.as_string() { - if index && !remove_values.remove(text) { - add_values.insert(text); - } - if tokenize { - for token in text.to_tokens() { - if !remove_tokens.remove(&token) { - add_tokens.insert(token); + // Add new text to index + if let Some(values) = value.as_list() { + for value in values { + if let Some(text) = value.as_string() { + if index && !remove_values.remove(text) { + add_values.insert(text); + } + if tokenize { + for token in text.to_tokens() { + if !remove_tokens.remove(&token) { + add_tokens.insert(token); + } } } } } } - } - // Update index - for (values, set) in [(add_values, true), (remove_values, false)] { - for value in values { + // Update index + for (values, set) in [(add_values, true), (remove_values, false)] { + for value in values { + batch.ops.push(Operation::Index { + field: property.clone().into(), + key: value.serialize(), + set, + }); + } + } + + // Update tokens + for (token, set) in [(add_tokens, true), (remove_tokens, false)] { + for token in token { + batch.ops.push(Operation::hash( + &token, + HASH_EXACT, + property.clone().into(), + set, + )); + } + } + } + index_as @ (IndexAs::Integer | IndexAs::LongInteger) => { + if let Some(current_value) = current_value.try_cast_uint() { batch.ops.push(Operation::Index { field: property.clone().into(), - key: value.serialize(), - set, + key: current_value.into_index(index_as), + set: false, }); } - } - - // Update tokens - for (token, set) in [(add_tokens, true), (remove_tokens, false)] { - for token in token { - batch.ops.push(Operation::hash( - &token, - HASH_EXACT, - property.clone().into(), - set, - )); + if let Some(value) = value.try_cast_uint() { + batch.ops.push(Operation::Index { + field: property.clone().into(), + key: value.into_index(index_as), + set: true, + }); } } - } - index_as @ (IndexAs::Integer | IndexAs::LongInteger) => { - if let Some(current_value) = current_value.try_cast_uint() { - batch.ops.push(Operation::Index { - field: property.clone().into(), - key: current_value.into_index(index_as), - set: false, - }); - } - if let Some(value) = value.try_cast_uint() { - batch.ops.push(Operation::Index { - field: property.clone().into(), - key: value.into_index(index_as), - set: false, - }); - } - } - IndexAs::IntegerList => { - let mut add_values = HashSet::new(); - let mut remove_values = HashSet::new(); - - if let Some(current_values) = current_value.as_list() { - for current_value in current_values { - if let Some(current_value) = current_value.try_cast_uint() { - remove_values.insert(current_value); + IndexAs::IntegerList => { + let mut add_values = HashSet::new(); + let mut remove_values = HashSet::new(); + + if let Some(current_values) = current_value.as_list() { + for current_value in current_values { + if let Some(current_value) = current_value.try_cast_uint() { + remove_values.insert(current_value); + } } } - } - if let Some(values) = value.as_list() { - for value in values { - if let Some(value) = value.try_cast_uint() { - if !remove_values.remove(&value) { - add_values.insert(value); + if let Some(values) = value.as_list() { + for value in values { + if let Some(value) = value.try_cast_uint() { + if !remove_values.remove(&value) { + add_values.insert(value); + } } } } - } - for (values, set) in [(add_values, true), (remove_values, false)] { - for value in values { - batch.ops.push(Operation::Index { + for (values, set) in [(add_values, true), (remove_values, false)] { + for value in values { + batch.ops.push(Operation::Index { + field: property.clone().into(), + key: (value as u32).serialize(), + set, + }); + } + } + } + IndexAs::HasProperty => { + if current_value == &Value::Null { + batch.ops.push(Operation::Bitmap { + family: ().family(), field: property.clone().into(), - key: (value as u32).serialize(), - set, + key: vec![], + set: true, + }); + } else if value == Value::Null { + batch.ops.push(Operation::Bitmap { + family: ().family(), + field: property.clone().into(), + key: vec![], + set: false, }); } } + IndexAs::None => (), } - IndexAs::HasProperty => { - if current_value == &Value::Null { - batch.ops.push(Operation::Bitmap { - family: BM_TAG, - field: property.clone().into(), - key: vec![], - set: true, - }); - } else if value == Value::Null { - batch.ops.push(Operation::Bitmap { - family: BM_TAG, - field: property.clone().into(), - key: vec![], - set: false, - }); - } - } - IndexAs::None => (), } if value != Value::Null { current.set(property, value); @@ -373,7 +369,7 @@ fn build_batch( &token, HASH_EXACT, (&item.property).into(), - true, + set, )); } } @@ -403,7 +399,7 @@ fn build_batch( &token, HASH_EXACT, (&item.property).into(), - true, + set, )); } } @@ -440,7 +436,7 @@ fn build_batch( } (value, IndexAs::HasProperty) if value != &Value::Null => { batch.ops.push(Operation::Bitmap { - family: BM_TAG, + family: ().family(), field: (&item.property).into(), key: vec![], set, diff --git a/crates/jmap-proto/src/response/references.rs b/crates/jmap-proto/src/response/references.rs index 2e67e2a9..590c973d 100644 --- a/crates/jmap-proto/src/response/references.rs +++ b/crates/jmap-proto/src/response/references.rs @@ -4,6 +4,7 @@ use utils::map::vec_map::VecMap; use crate::{ error::{method::MethodError, set::SetError}, + method::set::SetResponse, object::Object, request::{ reference::{MaybeReference, ResultReference}, @@ -305,52 +306,52 @@ impl Response { } } -impl Object<SetValue> { - pub fn iterate_and_eval_references( - self, - response: &Response, - ) -> impl Iterator<Item = Result<(Property, MaybePatchValue), SetError>> + '_ { - // Resolve id references, which were previously validated. - // If the ID is not found it means that set failed for that id, so we return a setError - // instead of failing the entire request with a MethodError::InvalidResultReference. - self.properties - .into_iter() - .map(|(property, set_value)| match set_value { - SetValue::Value(value) => Ok((property, MaybePatchValue::Value(value))), - SetValue::Patch(patch) => Ok((property, MaybePatchValue::Patch(patch))), - SetValue::IdReference(MaybeReference::Reference(id_ref)) => { - if let Some(id) = response.created_ids.get(&id_ref) { - Ok((property, MaybePatchValue::Value(Value::Id(*id)))) - } else { - Err(SetError::not_found() - .with_description(format!("Id reference {id_ref:?} not found."))) - } +impl SetResponse { + pub fn eval_object_references(&self, set_value: SetValue) -> Result<MaybePatchValue, SetError> { + match set_value { + SetValue::Value(value) => Ok(MaybePatchValue::Value(value)), + SetValue::Patch(patch) => Ok(MaybePatchValue::Patch(patch)), + SetValue::IdReference(MaybeReference::Reference(id_ref)) => { + if let Some(Value::Id(id)) = self + .created + .get(&id_ref) + .and_then(|obj| obj.properties.get(&Property::Id)) + { + Ok(MaybePatchValue::Value(Value::Id(*id))) + } else { + Err(SetError::not_found() + .with_description(format!("Id reference {id_ref:?} not found."))) } - SetValue::IdReference(MaybeReference::Value(id)) => { - Ok((property, MaybePatchValue::Value(Value::Id(id)))) - } - SetValue::IdReferences(id_refs) => { - let mut ids = Vec::with_capacity(id_refs.len()); - for id_ref in id_refs { - match id_ref { - MaybeReference::Value(id) => { - ids.push(Value::Id(id)); - } - MaybeReference::Reference(id_ref) => { - if let Some(id) = response.created_ids.get(&id_ref) { - ids.push(Value::Id(*id)); - } else { - return Err(SetError::not_found().with_description(format!( - "Id reference {id_ref:?} not found." - ))); - } + } + SetValue::IdReference(MaybeReference::Value(id)) => { + Ok(MaybePatchValue::Value(Value::Id(id))) + } + SetValue::IdReferences(id_refs) => { + let mut ids = Vec::with_capacity(id_refs.len()); + for id_ref in id_refs { + match id_ref { + MaybeReference::Value(id) => { + ids.push(Value::Id(id)); + } + MaybeReference::Reference(id_ref) => { + if let Some(Value::Id(id)) = self + .created + .get(&id_ref) + .and_then(|obj| obj.properties.get(&Property::Id)) + { + ids.push(Value::Id(*id)); + } else { + return Err(SetError::not_found().with_description(format!( + "Id reference {id_ref:?} not found." + ))); } } } - Ok((property, MaybePatchValue::Value(Value::List(ids)))) } - _ => unreachable!(), - }) + Ok(MaybePatchValue::Value(Value::List(ids))) + } + _ => unreachable!(), + } } } |