summaryrefslogtreecommitdiff
path: root/crates/jmap-proto
diff options
context:
space:
mode:
authorMauro D <mauro@stalw.art>2023-05-03 15:55:32 +0000
committerMauro D <mauro@stalw.art>2023-05-03 15:55:32 +0000
commit60fa410aa55f02d7956d9c5fcae8b8cc69f91627 (patch)
tree07bc4f742398683c944893be5ff50b6d692e85e2 /crates/jmap-proto
parenta3a0396772cfbfe8573ad15851acd19cacdc6499 (diff)
Mailbox tests passing.
Diffstat (limited to 'crates/jmap-proto')
-rw-r--r--crates/jmap-proto/src/object/index.rs304
-rw-r--r--crates/jmap-proto/src/response/references.rs83
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, &current, true);
+ build_batch(batch, self.index, &current, 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!(),
+ }
}
}