From 36c89315fad651b3b8ce1f8e25310db3ea668fae Mon Sep 17 00:00:00 2001 From: Alexander Batischev Date: Sun, 25 Apr 2021 18:29:19 +0300 Subject: Expose fallibility of individual SQL results `LocalGeneration::sql::files()` runs an SQL query, iterates over the results and collects the rows into a `Vec`. This can fail at any step: the query might fail to run, or one of the rows might fail to be fetched or processed. Right now, we lump all those failures into a `Result` that wraps the whole return value. This is only possible because we process each row before returning. Once `Vec` is replaced by an iterator, we won't have that luxury anymore, so we now wrap each individual element into its own `Result` (as well as wrapping the whole vector into a `Result` of its own). --- src/cmd/list_files.rs | 1 + src/cmd/restore.rs | 2 ++ src/cmd/show_gen.rs | 17 ++++++++++------- src/generation.rs | 20 ++++++++++++++------ 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/cmd/list_files.rs b/src/cmd/list_files.rs index 22b102e..7f0cfed 100644 --- a/src/cmd/list_files.rs +++ b/src/cmd/list_files.rs @@ -23,6 +23,7 @@ impl ListFiles { let gen = client.fetch_generation(&gen_id, temp.path())?; for file in gen.files()? { + let file = file?; println!("{}", format_entry(&file.entry(), file.reason())); } diff --git a/src/cmd/restore.rs b/src/cmd/restore.rs index a321e80..f8bbaf4 100644 --- a/src/cmd/restore.rs +++ b/src/cmd/restore.rs @@ -41,6 +41,7 @@ impl Restore { info!("restoring {} files", gen.file_count()?); let progress = create_progress_bar(gen.file_count()?, true); for file in gen.files()? { + let file = file?; match file.reason() { Reason::FileError => (), _ => restore_generation( @@ -54,6 +55,7 @@ impl Restore { } } for file in gen.files()? { + let file = file?; if file.entry().is_dir() { restore_directory_metadata(file.entry(), &self.to)?; } diff --git a/src/cmd/show_gen.rs b/src/cmd/show_gen.rs index ba39809..7dc52cf 100644 --- a/src/cmd/show_gen.rs +++ b/src/cmd/show_gen.rs @@ -23,14 +23,17 @@ impl ShowGeneration { let gen = client.fetch_generation(&gen_id, temp.path())?; let files = gen.files()?; - let total_bytes = files.iter().fold(0, |acc, file| { - let e = file.entry(); - if e.kind() == FilesystemKind::Regular { - acc + file.entry().len() - } else { - acc - } + let total_bytes = files.into_iter().try_fold(0, |acc, file| { + file.map(|file| { + let e = file.entry(); + if e.kind() == FilesystemKind::Regular { + acc + e.len() + } else { + acc + } + }) }); + let total_bytes = total_bytes?; println!("generation-id: {}", gen_id); println!("file-count: {}", gen.file_count()?); diff --git a/src/generation.rs b/src/generation.rs index 1d0ee52..a780203 100644 --- a/src/generation.rs +++ b/src/generation.rs @@ -196,7 +196,7 @@ impl LocalGeneration { sql::file_count(&self.conn) } - pub fn files(&self) -> LocalGenerationResult> { + pub fn files(&self) -> LocalGenerationResult>> { sql::files(&self.conn) } @@ -289,14 +289,22 @@ mod sql { Ok(count) } - pub fn files(conn: &Connection) -> LocalGenerationResult> { + pub fn files( + conn: &Connection, + ) -> LocalGenerationResult>> { let mut stmt = conn.prepare("SELECT * FROM files")?; let iter = stmt.query_map(params![], |row| row_to_entry(row))?; - let mut files = vec![]; + let mut files: Vec> = vec![]; for x in iter { - let (fileno, json, reason) = x?; - let entry = serde_json::from_str(&json)?; - files.push(BackedUpFile::new(fileno, entry, &reason)); + match x { + Ok((fileno, json, reason)) => { + let result = serde_json::from_str(&json) + .map(|entry| BackedUpFile::new(fileno, entry, &reason)) + .map_err(|e| e.into()); + files.push(result) + } + Err(e) => files.push(Err(e.into())), + } } Ok(files) } -- cgit v1.2.1