rename Operation to ReplicaOp for clarity
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#![allow(clippy::new_without_default)]
|
||||
|
||||
use crate::storage::{Operation, Storage, StorageTxn, TaskMap, VersionId, DEFAULT_BASE_VERSION};
|
||||
use crate::storage::{ReplicaOp, Storage, StorageTxn, TaskMap, VersionId, DEFAULT_BASE_VERSION};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
@@ -9,7 +9,7 @@ use uuid::Uuid;
|
||||
struct Data {
|
||||
tasks: HashMap<Uuid, TaskMap>,
|
||||
base_version: VersionId,
|
||||
operations: Vec<Operation>,
|
||||
operations: Vec<ReplicaOp>,
|
||||
working_set: Vec<Option<Uuid>>,
|
||||
}
|
||||
|
||||
@@ -87,16 +87,16 @@ impl<'t> StorageTxn for Txn<'t> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn operations(&mut self) -> anyhow::Result<Vec<Operation>> {
|
||||
fn operations(&mut self) -> anyhow::Result<Vec<ReplicaOp>> {
|
||||
Ok(self.data_ref().operations.clone())
|
||||
}
|
||||
|
||||
fn add_operation(&mut self, op: Operation) -> anyhow::Result<()> {
|
||||
fn add_operation(&mut self, op: ReplicaOp) -> anyhow::Result<()> {
|
||||
self.mut_data_ref().operations.push(op);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_operations(&mut self, ops: Vec<Operation>) -> anyhow::Result<()> {
|
||||
fn set_operations(&mut self, ops: Vec<ReplicaOp>) -> anyhow::Result<()> {
|
||||
self.mut_data_ref().operations = ops;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@ use uuid::Uuid;
|
||||
|
||||
mod config;
|
||||
mod inmemory;
|
||||
mod operation;
|
||||
mod op;
|
||||
pub(crate) mod sqlite;
|
||||
|
||||
pub use config::StorageConfig;
|
||||
pub use inmemory::InMemoryStorage;
|
||||
pub use sqlite::SqliteStorage;
|
||||
|
||||
pub use operation::Operation;
|
||||
pub use op::ReplicaOp;
|
||||
|
||||
/// An in-memory representation of a task as a simple hashmap
|
||||
pub type TaskMap = HashMap<String, String>;
|
||||
@@ -80,14 +80,14 @@ pub trait StorageTxn {
|
||||
|
||||
/// Get the current set of outstanding operations (operations that have not been sync'd to the
|
||||
/// server yet)
|
||||
fn operations(&mut self) -> Result<Vec<Operation>>;
|
||||
fn operations(&mut self) -> Result<Vec<ReplicaOp>>;
|
||||
|
||||
/// Add an operation to the end of the list of operations in the storage. Note that this
|
||||
/// merely *stores* the operation; it is up to the TaskDb to apply it.
|
||||
fn add_operation(&mut self, op: Operation) -> Result<()>;
|
||||
fn add_operation(&mut self, op: ReplicaOp) -> Result<()>;
|
||||
|
||||
/// Replace the current list of operations with a new list.
|
||||
fn set_operations(&mut self, ops: Vec<Operation>) -> Result<()>;
|
||||
fn set_operations(&mut self, ops: Vec<ReplicaOp>) -> Result<()>;
|
||||
|
||||
/// Get the entire working set, with each task UUID at its appropriate (1-based) index.
|
||||
/// Element 0 is always None.
|
||||
|
||||
@@ -2,9 +2,10 @@ use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// An Operation defines a single change to the task database
|
||||
/// A ReplicaOp defines a single change to the task database, as stored locally in the replica.
|
||||
/// This contains additional information not included in SyncOp.
|
||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum Operation {
|
||||
pub enum ReplicaOp {
|
||||
/// Create a new task.
|
||||
///
|
||||
/// On application, if the task already exists, the operation does nothing.
|
||||
@@ -27,9 +28,9 @@ pub enum Operation {
|
||||
},
|
||||
}
|
||||
|
||||
use Operation::*;
|
||||
use ReplicaOp::*;
|
||||
|
||||
impl Operation {
|
||||
impl ReplicaOp {
|
||||
// Transform takes two operations A and B that happened concurrently and produces two
|
||||
// operations A' and B' such that `apply(apply(S, A), B') = apply(apply(S, B), A')`. This
|
||||
// function is used to serialize operations in a process similar to a Git "rebase".
|
||||
@@ -53,9 +54,9 @@ impl Operation {
|
||||
// reached different states, to return to the same state by applying op2' and op1',
|
||||
// respectively.
|
||||
pub fn transform(
|
||||
operation1: Operation,
|
||||
operation2: Operation,
|
||||
) -> (Option<Operation>, Option<Operation>) {
|
||||
operation1: ReplicaOp,
|
||||
operation2: ReplicaOp,
|
||||
) -> (Option<ReplicaOp>, Option<ReplicaOp>) {
|
||||
match (&operation1, &operation2) {
|
||||
// Two creations or deletions of the same uuid reach the same state, so there's no need
|
||||
// for any further operations to bring the state together.
|
||||
@@ -135,13 +136,13 @@ mod test {
|
||||
// thoroughly, so this testing is light.
|
||||
|
||||
fn test_transform(
|
||||
setup: Option<Operation>,
|
||||
o1: Operation,
|
||||
o2: Operation,
|
||||
exp1p: Option<Operation>,
|
||||
exp2p: Option<Operation>,
|
||||
setup: Option<ReplicaOp>,
|
||||
o1: ReplicaOp,
|
||||
o2: ReplicaOp,
|
||||
exp1p: Option<ReplicaOp>,
|
||||
exp2p: Option<ReplicaOp>,
|
||||
) {
|
||||
let (o1p, o2p) = Operation::transform(o1.clone(), o2.clone());
|
||||
let (o1p, o2p) = ReplicaOp::transform(o1.clone(), o2.clone());
|
||||
assert_eq!((&o1p, &o2p), (&exp1p, &exp2p));
|
||||
|
||||
// check that the two operation sequences have the same effect, enforcing the invariant of
|
||||
@@ -349,12 +350,12 @@ mod test {
|
||||
]
|
||||
}
|
||||
|
||||
fn operation_strategy() -> impl Strategy<Value = Operation> {
|
||||
fn operation_strategy() -> impl Strategy<Value = ReplicaOp> {
|
||||
prop_oneof![
|
||||
uuid_strategy().prop_map(|uuid| Operation::Create { uuid }),
|
||||
uuid_strategy().prop_map(|uuid| Operation::Delete { uuid }),
|
||||
uuid_strategy().prop_map(|uuid| ReplicaOp::Create { uuid }),
|
||||
uuid_strategy().prop_map(|uuid| ReplicaOp::Delete { uuid }),
|
||||
(uuid_strategy(), "(title|project|status)").prop_map(|(uuid, property)| {
|
||||
Operation::Update {
|
||||
ReplicaOp::Update {
|
||||
uuid,
|
||||
property,
|
||||
value: Some("true".into()),
|
||||
@@ -372,30 +373,30 @@ mod test {
|
||||
// check that the two operation sequences have the same effect, enforcing the invariant of
|
||||
// the transform function.
|
||||
fn transform_invariant_holds(o1 in operation_strategy(), o2 in operation_strategy()) {
|
||||
let (o1p, o2p) = Operation::transform(o1.clone(), o2.clone());
|
||||
let (o1p, o2p) = ReplicaOp::transform(o1.clone(), o2.clone());
|
||||
|
||||
let mut db1 = TaskDb::new(Box::new(InMemoryStorage::new()));
|
||||
let mut db2 = TaskDb::new(Box::new(InMemoryStorage::new()));
|
||||
|
||||
// Ensure that any expected tasks already exist
|
||||
if let Operation::Update{ ref uuid, .. } = o1 {
|
||||
let _ = db1.apply(Operation::Create{uuid: uuid.clone()});
|
||||
let _ = db2.apply(Operation::Create{uuid: uuid.clone()});
|
||||
if let ReplicaOp::Update{ ref uuid, .. } = o1 {
|
||||
let _ = db1.apply(ReplicaOp::Create{uuid: uuid.clone()});
|
||||
let _ = db2.apply(ReplicaOp::Create{uuid: uuid.clone()});
|
||||
}
|
||||
|
||||
if let Operation::Update{ ref uuid, .. } = o2 {
|
||||
let _ = db1.apply(Operation::Create{uuid: uuid.clone()});
|
||||
let _ = db2.apply(Operation::Create{uuid: uuid.clone()});
|
||||
if let ReplicaOp::Update{ ref uuid, .. } = o2 {
|
||||
let _ = db1.apply(ReplicaOp::Create{uuid: uuid.clone()});
|
||||
let _ = db2.apply(ReplicaOp::Create{uuid: uuid.clone()});
|
||||
}
|
||||
|
||||
if let Operation::Delete{ ref uuid } = o1 {
|
||||
let _ = db1.apply(Operation::Create{uuid: uuid.clone()});
|
||||
let _ = db2.apply(Operation::Create{uuid: uuid.clone()});
|
||||
if let ReplicaOp::Delete{ ref uuid } = o1 {
|
||||
let _ = db1.apply(ReplicaOp::Create{uuid: uuid.clone()});
|
||||
let _ = db2.apply(ReplicaOp::Create{uuid: uuid.clone()});
|
||||
}
|
||||
|
||||
if let Operation::Delete{ ref uuid } = o2 {
|
||||
let _ = db1.apply(Operation::Create{uuid: uuid.clone()});
|
||||
let _ = db2.apply(Operation::Create{uuid: uuid.clone()});
|
||||
if let ReplicaOp::Delete{ ref uuid } = o2 {
|
||||
let _ = db1.apply(ReplicaOp::Create{uuid: uuid.clone()});
|
||||
let _ = db2.apply(ReplicaOp::Create{uuid: uuid.clone()});
|
||||
}
|
||||
|
||||
// if applying the initial operations fail, that indicates the operation was invalid
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::storage::{Operation, Storage, StorageTxn, TaskMap, VersionId, DEFAULT_BASE_VERSION};
|
||||
use crate::storage::{ReplicaOp, Storage, StorageTxn, TaskMap, VersionId, DEFAULT_BASE_VERSION};
|
||||
use anyhow::Context;
|
||||
use rusqlite::types::{FromSql, ToSql};
|
||||
use rusqlite::{params, Connection, OptionalExtension};
|
||||
@@ -52,17 +52,17 @@ impl ToSql for StoredTaskMap {
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores [`Operation`] in SQLite
|
||||
impl FromSql for Operation {
|
||||
/// Stores [`ReplicaOp`] in SQLite
|
||||
impl FromSql for ReplicaOp {
|
||||
fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
|
||||
let o: Operation = serde_json::from_str(value.as_str()?)
|
||||
let o: ReplicaOp = serde_json::from_str(value.as_str()?)
|
||||
.map_err(|_| rusqlite::types::FromSqlError::InvalidType)?;
|
||||
Ok(o)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parsers Operation stored as JSON in string column
|
||||
impl ToSql for Operation {
|
||||
/// Parses ReplicaOp stored as JSON in string column
|
||||
impl ToSql for ReplicaOp {
|
||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
|
||||
let s = serde_json::to_string(&self)
|
||||
.map_err(|e| rusqlite::Error::ToSqlConversionFailure(Box::new(e)))?;
|
||||
@@ -241,12 +241,12 @@ impl<'t> StorageTxn for Txn<'t> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn operations(&mut self) -> anyhow::Result<Vec<Operation>> {
|
||||
fn operations(&mut self) -> anyhow::Result<Vec<ReplicaOp>> {
|
||||
let t = self.get_txn()?;
|
||||
|
||||
let mut q = t.prepare("SELECT data FROM operations ORDER BY id ASC")?;
|
||||
let rows = q.query_map([], |r| {
|
||||
let data: Operation = r.get("data")?;
|
||||
let data: ReplicaOp = r.get("data")?;
|
||||
Ok(data)
|
||||
})?;
|
||||
|
||||
@@ -257,7 +257,7 @@ impl<'t> StorageTxn for Txn<'t> {
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn add_operation(&mut self, op: Operation) -> anyhow::Result<()> {
|
||||
fn add_operation(&mut self, op: ReplicaOp) -> anyhow::Result<()> {
|
||||
let t = self.get_txn()?;
|
||||
|
||||
t.execute("INSERT INTO operations (data) VALUES (?)", params![&op])
|
||||
@@ -265,7 +265,7 @@ impl<'t> StorageTxn for Txn<'t> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_operations(&mut self, ops: Vec<Operation>) -> anyhow::Result<()> {
|
||||
fn set_operations(&mut self, ops: Vec<ReplicaOp>) -> anyhow::Result<()> {
|
||||
let t = self.get_txn()?;
|
||||
t.execute("DELETE FROM operations", [])
|
||||
.context("Clear all existing operations")?;
|
||||
@@ -611,8 +611,8 @@ mod test {
|
||||
// create some operations
|
||||
{
|
||||
let mut txn = storage.txn()?;
|
||||
txn.add_operation(Operation::Create { uuid: uuid1 })?;
|
||||
txn.add_operation(Operation::Create { uuid: uuid2 })?;
|
||||
txn.add_operation(ReplicaOp::Create { uuid: uuid1 })?;
|
||||
txn.add_operation(ReplicaOp::Create { uuid: uuid2 })?;
|
||||
txn.commit()?;
|
||||
}
|
||||
|
||||
@@ -623,8 +623,8 @@ mod test {
|
||||
assert_eq!(
|
||||
ops,
|
||||
vec![
|
||||
Operation::Create { uuid: uuid1 },
|
||||
Operation::Create { uuid: uuid2 },
|
||||
ReplicaOp::Create { uuid: uuid1 },
|
||||
ReplicaOp::Create { uuid: uuid2 },
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -633,8 +633,8 @@ mod test {
|
||||
{
|
||||
let mut txn = storage.txn()?;
|
||||
txn.set_operations(vec![
|
||||
Operation::Delete { uuid: uuid2 },
|
||||
Operation::Delete { uuid: uuid1 },
|
||||
ReplicaOp::Delete { uuid: uuid2 },
|
||||
ReplicaOp::Delete { uuid: uuid1 },
|
||||
])?;
|
||||
txn.commit()?;
|
||||
}
|
||||
@@ -642,8 +642,8 @@ mod test {
|
||||
// create some more operations (to test adding operations after clearing)
|
||||
{
|
||||
let mut txn = storage.txn()?;
|
||||
txn.add_operation(Operation::Create { uuid: uuid3 })?;
|
||||
txn.add_operation(Operation::Delete { uuid: uuid3 })?;
|
||||
txn.add_operation(ReplicaOp::Create { uuid: uuid3 })?;
|
||||
txn.add_operation(ReplicaOp::Delete { uuid: uuid3 })?;
|
||||
txn.commit()?;
|
||||
}
|
||||
|
||||
@@ -654,10 +654,10 @@ mod test {
|
||||
assert_eq!(
|
||||
ops,
|
||||
vec![
|
||||
Operation::Delete { uuid: uuid2 },
|
||||
Operation::Delete { uuid: uuid1 },
|
||||
Operation::Create { uuid: uuid3 },
|
||||
Operation::Delete { uuid: uuid3 },
|
||||
ReplicaOp::Delete { uuid: uuid2 },
|
||||
ReplicaOp::Delete { uuid: uuid1 },
|
||||
ReplicaOp::Create { uuid: uuid3 },
|
||||
ReplicaOp::Delete { uuid: uuid3 },
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user