Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define Operations as a sequence of Operation-s #423

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 79 additions & 2 deletions taskchampion/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// A Operation defines a single change to the task database, as stored locally in the replica.
/// This contains additional information not included in SyncOp.
/// An Operation defines a single change to the task database, as stored locally in the replica.
///
/// Operations are the means by which changes are made to the database, typically batched together
/// into [`Operations`] and committed to the replica.
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
pub enum Operation {
/// Create a new task.
Expand Down Expand Up @@ -43,6 +45,61 @@ impl Operation {
}
}

/// Operations contains a sequence of [`Operation`] values, which can be committed in a single
/// transaction with [`Replica::commit`](crate::Replica::commit).
#[derive(PartialEq, Eq, Debug, Default)]
pub struct Operations(Vec<Operation>);

impl Operations {
/// Create a new, empty set of operations.
pub fn new() -> Self {
Self::default()
}

/// Create a new set of operations beginning with an undo point.
///
/// This is a convenience method to begin creating a batch of operations that can be
/// undone together.
pub fn new_with_undo_point() -> Self {
let mut ops = Self::default();
ops.add(Operation::UndoPoint);
ops
}

/// Add a new operation to the end of this sequence.
pub fn add(&mut self, op: Operation) {
self.0.push(op);
}

/// For tests, it's useful to set the timestamps of all updates to the same value.
#[cfg(test)]
pub fn set_all_timestamps(&mut self, set_to: DateTime<Utc>) {
for op in &mut self.0 {
if let Operation::Update { timestamp, .. } = op {
*timestamp = set_to;
}
}
}
}

impl IntoIterator for Operations {
type Item = Operation;
type IntoIter = std::vec::IntoIter<Operation>;

fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}

impl<'a> IntoIterator for &'a Operations {
type Item = &'a Operation;
type IntoIter = std::slice::Iter<'a, Operation>;

fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down Expand Up @@ -132,4 +189,24 @@ mod test {
assert_eq!(deser, op);
Ok(())
}

#[test]
fn operations_empty() {
let ops = Operations::new();
assert_eq!(ops.0, vec![]);
}

#[test]
fn operations_with_undo_point() {
let ops = Operations::new_with_undo_point();
assert_eq!(ops.0, vec![UndoPoint]);
}

#[test]
fn operations_add() {
let uuid = Uuid::new_v4();
let mut ops = Operations::new();
ops.add(Create { uuid });
assert_eq!(ops.0, vec![Create { uuid }]);
}
}
Loading