use std::collections::btree_map::Iter;
use std::collections::BTreeMap;
use crate::operation::error::FieldsError;
use crate::operation::OperationValue;
#[derive(Clone, Debug, PartialEq, 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 insert(&mut self, name: &str, value: OperationValue) -> Result<(), FieldsError> {
if self.0.contains_key(name) {
return Err(FieldsError::FieldDuplicate(name.to_owned()));
}
self.0.insert(name.to_owned(), value);
Ok(())
}
pub fn update(&mut self, name: &str, value: OperationValue) -> Result<(), FieldsError> {
if !self.0.contains_key(name) {
return Err(FieldsError::UnknownField);
}
self.0.insert(name.to_owned(), value);
Ok(())
}
pub fn remove(&mut self, name: &str) -> Result<(), FieldsError> {
if !self.0.contains_key(name) {
return Err(FieldsError::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 From<Vec<(&str, OperationValue)>> for OperationFields {
fn from(spec: Vec<(&str, OperationValue)>) -> Self {
let mut operation_fields = OperationFields::new();
for field in spec {
if operation_fields.insert(field.0, field.1).is_err() {
}
}
operation_fields
}
}
#[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
.insert(
"message",
OperationValue::String("Hello, Panda!".to_owned()),
)
.unwrap();
assert!(fields
.insert("message", OperationValue::String("Huhu".to_owned()))
.is_err());
assert!(fields
.update("message", OperationValue::String("Huhu".to_owned()))
.is_ok());
assert!(fields
.update("imagine", OperationValue::String("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]);
let document_view_id_2 = DocumentViewId::new(&[operation_id_3]);
let document_view_id_3 =
DocumentViewId::new(&[operation_id_4, operation_id_5, operation_id_6]);
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.insert("locations", value).is_ok());
}
#[test]
fn from_vec() {
let fields = OperationFields::from(vec![
("message", "Hello, Panda!".into()),
("message", "Duplicates are ignored".into()),
("is_cute", true.into()),
]);
assert_eq!(
fields.get("message").unwrap(),
&OperationValue::String("Hello, Panda!".into())
);
assert_eq!(
fields.get("is_cute").unwrap(),
&OperationValue::Boolean(true)
);
}
}