Skip to content

Commit

Permalink
indicate move operations properly in history
Browse files Browse the repository at this point in the history
  • Loading branch information
lmcmicu committed Oct 19, 2024
1 parent 69f721c commit 7ad2a15
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 30 deletions.
15 changes: 8 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ enum Commands {
/// Show recent changes to the database
History {
#[arg(long, value_name = "CONTEXT", action = ArgAction::Set,
help = "Number of lines of redo / undo context",
help = "Number of lines of redo / undo context (0 = infinite)",
default_value_t = 5)]
context: usize,
},
Expand Down Expand Up @@ -426,8 +426,8 @@ async fn main() -> Result<()> {
}

// Given a Valve instance, a table name, a row number, a column name, and an input value,
// fetch the row from the given table with the given row number, such that the value of the
// given column has been replaced with the given input_value.
// fetches the row from the given table with the given row number, such that the value of the
// given column is replaced with the given input_value.
async fn fetch_row_with_input_value(
valve: &Valve,
table: &str,
Expand Down Expand Up @@ -833,12 +833,13 @@ async fn main() -> Result<()> {
_ => undo_history[0].history_id,
};
undo_history.reverse();
let id_width = next_undo.to_string().len();
for undo in &undo_history {
if undo.history_id == next_undo {
let line = format!("▲ {} {}", undo.history_id, undo.message);
let line = format!("▲ {:>id_width$} {}", undo.history_id, undo.message);
println!("{}", Style::new().bold().paint(line));
} else {
println!(" {} {}", undo.history_id, undo.message);
println!(" {:>id_width$} {}", undo.history_id, undo.message);
}
}

Expand All @@ -857,9 +858,9 @@ async fn main() -> Result<()> {
// which indicates that nothing can be redone even though there are entries in the
// redo stack.
if redo.history_id == next_redo && redo.history_id > next_undo {
println!("▼ {} {}", redo.history_id, redo.message);
println!("▼ {:>id_width$} {}", redo.history_id, redo.message);
} else {
let line = format!(" {} {}", redo.history_id, redo.message);
let line = format!(" {:>id_width$} {}", redo.history_id, redo.message);
// If the history_id under consideration is lower than the next undo, or if
// there is a redo operation appearing before this one in the returned results
// that has a greater history_id, then this is an orphaned operation that cannot
Expand Down
15 changes: 8 additions & 7 deletions src/toolkit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2772,10 +2772,10 @@ pub async fn get_text_row_from_db_tx(
valve_row.contents_to_rich_json()
}

/// Given a configuration struct, the database kind, a table name, and a [SerdeMap] representing
/// a row in the table, such that all of the column values are represented as strings, use the
/// configuration to find the actual SQL types of each column in the row, and then convert the
/// values of each column from TEXT to the appropriate type, before returning the modified map.
/// Given a Valve configuration, the database kind, a table name, and a [SerdeMap] representing
/// a row in the table, such that all of the column values are represented as strings, uses the
/// configuration to find the actual SQL types of each column in the row, and then converts the
/// value of each column from a string to the appropriate type, before returning the modified map.
pub fn correct_row_datatypes(
config: &ValveConfig,
db_kind: &DbKind,
Expand Down Expand Up @@ -3884,9 +3884,10 @@ pub async fn get_next_undo_id(pool: &AnyPool) -> Result<u16> {
}
}

/// Given a table name, an [AnyRow] representing the last change to the database, a history id,
/// a row number, a database transaction, and a flag indicating whether the given move should be
/// undone (true) or redone (false), undo or redo the move.
/// Given a table name, an [AnyRow] representing the last change to the database (which is
/// expected to be a move operation), a history id, a row number, a database transaction, and a
/// flag indicating whether the given move should be undone (true) or redone (false), undoes or
/// redoes the move.
pub async fn undo_or_redo_move_tx(
table: &str,
last_change: &AnyRow,
Expand Down
70 changes: 54 additions & 16 deletions src/valve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,20 +414,20 @@ pub struct ValveRowChange {
}

impl ValveRowChange {
/// Given a database record representing either an undo or a redo from the history table,
/// return a [ValveRowChange] struct.
pub fn from_undo_or_redo_record(record: &AnyRow) -> Result<Self> {
let table: &str = record.get("table");
let row_number: i64 = record.get("row");
/// Given a database row representing either an undo or a redo record from the history table,
/// returns a [ValveRowChange] struct containing the same information.
pub fn from_undo_or_redo_record(db_rec: &AnyRow) -> Result<Self> {
let table: &str = db_rec.try_get("table")?;
let row_number: i64 = db_rec.try_get("row")?;
let row_number = row_number as u32;
let history_id: i32 = record.get("history_id");
let history_id: i32 = db_rec.try_get("history_id")?;
let history_id = history_id as u16;
let from = get_json_object_from_column(&record, "from");
let to = get_json_object_from_column(&record, "to");
let from = get_json_object_from_column(&db_rec, "from");
let to = get_json_object_from_column(&db_rec, "to");
let summary = {
let summary = record.try_get_raw("summary")?;
let summary = db_rec.try_get_raw("summary")?;
if !summary.is_null() {
let summary: &str = record.get("summary");
let summary: &str = db_rec.try_get("summary")?;
match serde_json::from_str::<SerdeValue>(summary) {
Ok(SerdeValue::Array(v)) => Some(v),
_ => {
Expand All @@ -448,37 +448,75 @@ impl ValveRowChange {
for entry in summary {
let column = entry
.get("column")
.and_then(|s| s.as_str())
.and_then(|s| Some(s.to_string()))
.ok_or(ValveError::InputError("No 'column' found".to_string()))?;
let level = entry
.get("level")
.and_then(|s| s.as_str())
.and_then(|s| Some(s.to_string()))
.ok_or(ValveError::InputError("No 'level' found".to_string()))?;
let old_value = entry
.get("old_value")
.and_then(|s| s.as_str())
.and_then(|s| Some(s.to_string()))
.ok_or(ValveError::InputError("No 'old_value' found".to_string()))?;
let value = entry
.get("value")
.and_then(|s| s.as_str())
.and_then(|s| Some(s.to_string()))
.ok_or(ValveError::InputError("No 'value' found".to_string()))?;
let message = entry
.get("message")
.and_then(|s| s.as_str())
.and_then(|s| Some(s.to_string()))
.ok_or(ValveError::InputError("No 'message' found".to_string()))?;
column_changes.push(ValveChange {
column: column.to_string(),
level: level.to_string(),
old_value: old_value.to_string(),
value: value.to_string(),
message: message.to_string(),
column: column,
level: level,
old_value: old_value,
value: value,
message: message,
});
}
let message = {
let moves = column_changes
.iter()
.filter(|cc| cc.level.to_lowercase() == "move")
.collect::<Vec<_>>();
if moves.len() == 0 {
format!("Update row {row_number} of '{table}'")
} else if moves.len() == 1 {
format!(
"Move row {row_number} of '{table}' from {before} to {after}",
before = {
if moves[0].old_value == "0" {
"first".to_string()
} else {
format!("after row {}", moves[0].old_value)
}
},
after = {
if moves[0].value == "0" {
"first".to_string()
} else {
format!("after row {}", moves[0].value)
}
},
)
} else {
return Err(ValveError::InputError(
"Summary for move (history ID: {history_id}) contains too many records"
.to_string(),
)
.into());
}
};
return Ok(ValveRowChange {
history_id: history_id,
table: table.to_string(),
row: row_number,
message: format!("Update row {row_number} of '{table}'"),
message: message,
changes: column_changes,
});
}
Expand Down

0 comments on commit 7ad2a15

Please sign in to comment.