use crate::document::error::DocumentBuilderError;
use crate::document::{DocumentViewFields, DocumentViewValue};
use crate::graph::Graph;
use crate::identity::PublicKey;
use crate::operation::traits::AsOperation;
use crate::operation::{Operation, OperationId};
pub fn build_graph(
operations: &[(OperationId, Operation, PublicKey)],
) -> Result<Graph<OperationId, (OperationId, Operation, PublicKey)>, DocumentBuilderError> {
let mut graph = Graph::new();
for (id, operation, public_key) in operations {
graph.add_node(id, (id.to_owned(), operation.to_owned(), *public_key));
}
for (id, operation, _public_key) in operations {
if let Some(previous) = operation.previous() {
for previous in previous.iter() {
let success = graph.add_link(previous, id);
if !success {
return Err(DocumentBuilderError::InvalidOperationLink(id.to_owned()));
}
}
}
}
Ok(graph)
}
pub fn reduce(
ordered_operations: &[(OperationId, Operation, PublicKey)],
) -> Option<DocumentViewFields> {
let mut document_view_fields = DocumentViewFields::new();
for (id, operation, _public_key) in ordered_operations {
if operation.is_delete() {
return None;
}
if let Some(fields) = operation.fields() {
for (key, value) in fields.iter() {
let document_view_value = DocumentViewValue::new(id, value);
document_view_fields.insert(key, document_view_value);
}
}
}
Some(document_view_fields)
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use crate::identity::PublicKey;
use crate::operation::{Operation, OperationValue};
use crate::test_utils::fixtures::{
create_operation, delete_operation, public_key, random_operation_id, update_operation,
};
use super::reduce;
#[rstest]
fn reduces_operations(
#[with(vec![("username", OperationValue::String("bubu".into()))])]
create_operation: Operation,
#[with(vec![("username", OperationValue::String("Yahooo!".into()))])]
update_operation: Operation,
delete_operation: Operation,
public_key: PublicKey,
) {
let mut operations = Vec::new();
operations.push((random_operation_id(), create_operation, public_key));
let reduced_create = reduce(&operations);
assert_eq!(
*reduced_create.unwrap().get("username").unwrap().value(),
OperationValue::String("bubu".to_string())
);
operations.push((random_operation_id(), update_operation, public_key));
let reduced_update = reduce(&operations);
assert_eq!(
*reduced_update.unwrap().get("username").unwrap().value(),
OperationValue::String("Yahooo!".to_string())
);
operations.push((random_operation_id(), delete_operation, public_key));
let reduced_delete = reduce(&operations);
assert!(reduced_delete.is_none());
}
}