use crate::document::error::DocumentBuilderError;
use crate::document::{DocumentViewFields, DocumentViewValue, IsDeleted, IsEdited};
use crate::graph::Graph;
use crate::operation::traits::{AsOperation, AsVerifiedOperation};
use crate::operation::{OperationId, VerifiedOperation};
pub(crate) fn build_graph(
operations: &[VerifiedOperation],
) -> Result<Graph<OperationId, VerifiedOperation>, DocumentBuilderError> {
let mut graph = Graph::new();
for operation in operations {
graph.add_node(operation.id(), operation.clone());
}
for operation in operations {
if let Some(previous_operations) = operation.previous_operations() {
for previous in previous_operations.iter() {
let success = graph.add_link(previous, operation.id());
if !success {
return Err(DocumentBuilderError::InvalidOperationLink(
operation.id().to_owned(),
));
}
}
}
}
Ok(graph)
}
pub(crate) fn reduce(
ordered_operations: &[VerifiedOperation],
) -> (Option<DocumentViewFields>, IsEdited, IsDeleted) {
let mut is_edited = false;
let mut document_view_fields = DocumentViewFields::new();
for operation in ordered_operations {
if operation.is_delete() {
return (None, true, true);
}
if operation.is_update() {
is_edited = true
}
if let Some(fields) = operation.fields() {
for (key, value) in fields.iter() {
let document_view_value = DocumentViewValue::new(operation.id(), value);
document_view_fields.insert(key, document_view_value);
}
}
}
(Some(document_view_fields), is_edited, false)
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use crate::operation::{OperationValue, VerifiedOperation};
use crate::test_utils::fixtures::{
operation_fields, random_previous_operations, verified_operation_with_schema,
};
use super::reduce;
#[rstest]
fn reduces_operations(
#[from(verified_operation_with_schema)] create_operation: VerifiedOperation,
#[from(verified_operation_with_schema)]
#[with(
Some(operation_fields(vec![("username", OperationValue::String("Yahooo!".into()))])),
Some(random_previous_operations(1))
)]
update_operation: VerifiedOperation,
#[from(verified_operation_with_schema)]
#[with(None, Some(random_previous_operations(1)))]
delete_operation: VerifiedOperation,
) {
let (reduced_create, is_edited, is_deleted) = reduce(&[create_operation.clone()]);
assert_eq!(
*reduced_create.unwrap().get("username").unwrap().value(),
OperationValue::String("bubu".to_string())
);
assert!(!is_edited);
assert!(!is_deleted);
let (reduced_update, is_edited, is_deleted) =
reduce(&[create_operation.clone(), update_operation.clone()]);
assert_eq!(
*reduced_update.unwrap().get("username").unwrap().value(),
OperationValue::String("Yahooo!".to_string())
);
assert!(is_edited);
assert!(!is_deleted);
let (reduced_delete, is_edited, is_deleted) =
reduce(&[create_operation, update_operation, delete_operation]);
assert!(reduced_delete.is_none());
assert!(is_edited);
assert!(is_deleted);
}
}