use std::collections::btree_map::Iter;
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use crate::operation::{OperationError, OperationFieldsError, OperationValue};
use crate::Validate;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Default)]
pub struct OperationFields(BTreeMap<String, OperationValue>);
impl OperationFields {
pub fn new() -> Self {
Self(BTreeMap::new())
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn add(&mut self, name: &str, value: OperationValue) -> Result<(), OperationFieldsError> {
if self.0.contains_key(name) {
return Err(OperationFieldsError::FieldDuplicate);
}
self.0.insert(name.to_owned(), value);
Ok(())
}
pub fn update(
&mut self,
name: &str,
value: OperationValue,
) -> Result<(), OperationFieldsError> {
if !self.0.contains_key(name) {
return Err(OperationFieldsError::UnknownField);
}
self.0.insert(name.to_owned(), value);
Ok(())
}
pub fn remove(&mut self, name: &str) -> Result<(), OperationFieldsError> {
if !self.0.contains_key(name) {
return Err(OperationFieldsError::UnknownField);
}
self.0.remove(name);
Ok(())
}
pub fn get(&self, name: &str) -> Option<&OperationValue> {
if !self.0.contains_key(name) {
return None;
}
self.0.get(name)
}
pub fn keys(&self) -> Vec<String> {
self.0.keys().cloned().collect()
}
pub fn iter(&self) -> Iter<String, OperationValue> {
self.0.iter()
}
}
impl Validate for OperationFields {
type Error = OperationError;
fn validate(&self) -> Result<(), Self::Error> {
for (_, value) in self.iter() {
value.validate()?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use crate::document::DocumentViewId;
use crate::operation::{OperationId, PinnedRelationList};
use crate::test_utils::fixtures::random_operation_id;
use super::{OperationFields, OperationValue};
#[test]
fn operation_fields() {
let mut fields = OperationFields::new();
fields
.add("message", OperationValue::Text("Hello, Panda!".to_owned()))
.unwrap();
assert!(fields
.add("message", OperationValue::Text("Huhu".to_owned()))
.is_err());
assert!(fields
.update("message", OperationValue::Text("Huhu".to_owned()))
.is_ok());
assert!(fields
.update("imagine", OperationValue::Text("Pandaparty".to_owned()))
.is_err());
assert_eq!(fields.keys(), vec!["message"]);
assert!(fields.remove("message").is_ok());
assert_eq!(fields.len(), 0);
}
#[rstest]
fn pinned_relation_lists(
#[from(random_operation_id)] operation_id_1: OperationId,
#[from(random_operation_id)] operation_id_2: OperationId,
#[from(random_operation_id)] operation_id_3: OperationId,
#[from(random_operation_id)] operation_id_4: OperationId,
#[from(random_operation_id)] operation_id_5: OperationId,
#[from(random_operation_id)] operation_id_6: OperationId,
) {
let document_view_id_1 = DocumentViewId::new(&[operation_id_1, operation_id_2]).unwrap();
let document_view_id_2 = DocumentViewId::new(&[operation_id_3]).unwrap();
let document_view_id_3 =
DocumentViewId::new(&[operation_id_4, operation_id_5, operation_id_6]).unwrap();
let relations = PinnedRelationList::new(vec![
document_view_id_1,
document_view_id_2,
document_view_id_3,
]);
let value = OperationValue::PinnedRelationList(relations);
let mut fields = OperationFields::new();
assert!(fields.add("locations", value).is_ok());
}
}