234 lines
6.4 KiB
Rust
234 lines
6.4 KiB
Rust
use crate::errors::Error;
|
|
use crate::storage::{Operation, StorageTxn};
|
|
|
|
pub(super) fn apply_op(txn: &mut dyn StorageTxn, op: &Operation) -> anyhow::Result<()> {
|
|
match op {
|
|
Operation::Create { uuid } => {
|
|
// insert if the task does not already exist
|
|
if !txn.create_task(*uuid)? {
|
|
return Err(Error::Database(format!("Task {} already exists", uuid)).into());
|
|
}
|
|
}
|
|
Operation::Delete { ref uuid } => {
|
|
if !txn.delete_task(*uuid)? {
|
|
return Err(Error::Database(format!("Task {} does not exist", uuid)).into());
|
|
}
|
|
}
|
|
Operation::Update {
|
|
ref uuid,
|
|
ref property,
|
|
ref value,
|
|
timestamp: _,
|
|
} => {
|
|
// update if this task exists, otherwise ignore
|
|
if let Some(mut task) = txn.get_task(*uuid)? {
|
|
match value {
|
|
Some(ref val) => task.insert(property.to_string(), val.clone()),
|
|
None => task.remove(property),
|
|
};
|
|
txn.set_task(*uuid, task)?;
|
|
} else {
|
|
return Err(Error::Database(format!("Task {} does not exist", uuid)).into());
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::taskdb::TaskDb;
|
|
use chrono::Utc;
|
|
use pretty_assertions::assert_eq;
|
|
use std::collections::HashMap;
|
|
use uuid::Uuid;
|
|
|
|
#[test]
|
|
fn test_apply_create() -> anyhow::Result<()> {
|
|
let mut db = TaskDb::new_inmemory();
|
|
let uuid = Uuid::new_v4();
|
|
let op = Operation::Create { uuid };
|
|
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
apply_op(txn.as_mut(), &op)?;
|
|
txn.commit()?;
|
|
}
|
|
|
|
assert_eq!(db.sorted_tasks(), vec![(uuid, vec![]),]);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_apply_create_exists() -> anyhow::Result<()> {
|
|
let mut db = TaskDb::new_inmemory();
|
|
let uuid = Uuid::new_v4();
|
|
let op = Operation::Create { uuid };
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
apply_op(txn.as_mut(), &op)?;
|
|
assert_eq!(
|
|
apply_op(txn.as_mut(), &op).err().unwrap().to_string(),
|
|
format!("Task Database Error: Task {} already exists", uuid)
|
|
);
|
|
txn.commit()?;
|
|
}
|
|
|
|
// first op was applied
|
|
assert_eq!(db.sorted_tasks(), vec![(uuid, vec![])]);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_apply_create_update() -> anyhow::Result<()> {
|
|
let mut db = TaskDb::new_inmemory();
|
|
let uuid = Uuid::new_v4();
|
|
let op1 = Operation::Create { uuid };
|
|
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
apply_op(txn.as_mut(), &op1)?;
|
|
txn.commit()?;
|
|
}
|
|
|
|
let op2 = Operation::Update {
|
|
uuid,
|
|
property: String::from("title"),
|
|
value: Some("my task".into()),
|
|
timestamp: Utc::now(),
|
|
};
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
apply_op(txn.as_mut(), &op2)?;
|
|
txn.commit()?;
|
|
}
|
|
|
|
assert_eq!(
|
|
db.sorted_tasks(),
|
|
vec![(uuid, vec![("title".into(), "my task".into())])]
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_apply_create_update_delete_prop() -> anyhow::Result<()> {
|
|
let mut db = TaskDb::new_inmemory();
|
|
let uuid = Uuid::new_v4();
|
|
let op1 = Operation::Create { uuid };
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
apply_op(txn.as_mut(), &op1)?;
|
|
txn.commit()?;
|
|
}
|
|
|
|
let op2 = Operation::Update {
|
|
uuid,
|
|
property: String::from("title"),
|
|
value: Some("my task".into()),
|
|
timestamp: Utc::now(),
|
|
};
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
apply_op(txn.as_mut(), &op2)?;
|
|
txn.commit()?;
|
|
}
|
|
|
|
let op3 = Operation::Update {
|
|
uuid,
|
|
property: String::from("priority"),
|
|
value: Some("H".into()),
|
|
timestamp: Utc::now(),
|
|
};
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
apply_op(txn.as_mut(), &op3)?;
|
|
txn.commit()?;
|
|
}
|
|
|
|
let op4 = Operation::Update {
|
|
uuid,
|
|
property: String::from("title"),
|
|
value: None,
|
|
timestamp: Utc::now(),
|
|
};
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
apply_op(txn.as_mut(), &op4)?;
|
|
txn.commit()?;
|
|
}
|
|
|
|
let mut exp = HashMap::new();
|
|
let mut task = HashMap::new();
|
|
task.insert(String::from("priority"), String::from("H"));
|
|
exp.insert(uuid, task);
|
|
assert_eq!(
|
|
db.sorted_tasks(),
|
|
vec![(uuid, vec![("priority".into(), "H".into())])]
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_apply_update_does_not_exist() -> anyhow::Result<()> {
|
|
let mut db = TaskDb::new_inmemory();
|
|
let uuid = Uuid::new_v4();
|
|
let op = Operation::Update {
|
|
uuid,
|
|
property: String::from("title"),
|
|
value: Some("my task".into()),
|
|
timestamp: Utc::now(),
|
|
};
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
assert_eq!(
|
|
apply_op(txn.as_mut(), &op).err().unwrap().to_string(),
|
|
format!("Task Database Error: Task {} does not exist", uuid)
|
|
);
|
|
txn.commit()?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_apply_create_delete() -> anyhow::Result<()> {
|
|
let mut db = TaskDb::new_inmemory();
|
|
let uuid = Uuid::new_v4();
|
|
let op1 = Operation::Create { uuid };
|
|
let op2 = Operation::Delete { uuid };
|
|
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
apply_op(txn.as_mut(), &op1)?;
|
|
apply_op(txn.as_mut(), &op2)?;
|
|
txn.commit()?;
|
|
}
|
|
|
|
assert_eq!(db.sorted_tasks(), vec![]);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_apply_delete_not_present() -> anyhow::Result<()> {
|
|
let mut db = TaskDb::new_inmemory();
|
|
let uuid = Uuid::new_v4();
|
|
let op = Operation::Delete { uuid };
|
|
{
|
|
let mut txn = db.storage.txn()?;
|
|
assert_eq!(
|
|
apply_op(txn.as_mut(), &op).err().unwrap().to_string(),
|
|
format!("Task Database Error: Task {} does not exist", uuid)
|
|
);
|
|
txn.commit()?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|