summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Batischev <eual.jp@gmail.com>2021-04-25 21:15:04 +0300
committerAlexander Batischev <eual.jp@gmail.com>2021-04-26 16:01:14 +0300
commitf21e6e0280b094efb72736f53931ecf0e7c2c0a2 (patch)
treeb52a29687841b40f3ecdf5b89d930fd9ccf2a277
parent36c89315fad651b3b8ce1f8e25310db3ea668fae (diff)
downloadobnam2-f21e6e0280b094efb72736f53931ecf0e7c2c0a2.tar.gz
Use an iterator internally for LocalGeneration
This adds the machinery. We have to keep the compiled SQL query while the iterator is in use, so we wrap it in an `SqlResults` struct which the iterator borrows.
-rw-r--r--src/generation.rs51
1 files changed, 32 insertions, 19 deletions
diff --git a/src/generation.rs b/src/generation.rs
index a780203..e5ca14c 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -197,7 +197,7 @@ impl LocalGeneration {
}
pub fn files(&self) -> LocalGenerationResult<Vec<LocalGenerationResult<BackedUpFile>>> {
- sql::files(&self.conn)
+ Ok(sql::files(&self.conn)?.iter()?.collect())
}
pub fn chunkids(&self, fileno: FileId) -> LocalGenerationResult<Vec<ChunkId>> {
@@ -221,7 +221,7 @@ mod sql {
use crate::backup_reason::Reason;
use crate::chunkid::ChunkId;
use crate::fsentry::FilesystemEntry;
- use rusqlite::{params, Connection, OpenFlags, Row, Transaction};
+ use rusqlite::{params, Connection, OpenFlags, Row, Statement, Transaction};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
@@ -289,24 +289,37 @@ mod sql {
Ok(count)
}
- pub fn files(
- conn: &Connection,
- ) -> LocalGenerationResult<Vec<LocalGenerationResult<BackedUpFile>>> {
- let mut stmt = conn.prepare("SELECT * FROM files")?;
- let iter = stmt.query_map(params![], |row| row_to_entry(row))?;
- let mut files: Vec<LocalGenerationResult<BackedUpFile>> = vec![];
- for x in iter {
- 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())),
- }
+ // A pointer to an iterator over values of type `LocalGenerationResult<T>`. The iterator is
+ // only valid for the lifetime 'stmt.
+ //
+ // The fact that it's a pointer (`Box<dyn ...>`) means we don't care what the actual type of
+ // the iterator is, and who produces it.
+ type SqlResultsIterator<'stmt, T> = Box<dyn Iterator<Item = LocalGenerationResult<T>> + 'stmt>;
+
+ pub struct SqlResults<'conn> {
+ stmt: Statement<'conn>,
+ }
+
+ impl<'conn> SqlResults<'conn> {
+ fn new(conn: &'conn Connection, statement: &str) -> LocalGenerationResult<Self> {
+ let stmt = conn.prepare(statement)?;
+ Ok(Self { stmt })
+ }
+
+ pub fn iter(&'_ mut self) -> LocalGenerationResult<SqlResultsIterator<'_, BackedUpFile>> {
+ let iter = self.stmt.query_map(params![], |row| row_to_entry(row))?;
+ let iter = iter.map(|x| match x {
+ Ok((fileno, json, reason)) => serde_json::from_str(&json)
+ .map(|entry| BackedUpFile::new(fileno, entry, &reason))
+ .map_err(|e| e.into()),
+ Err(e) => Err(e.into()),
+ });
+ Ok(iter)
}
- Ok(files)
+ }
+
+ pub fn files(conn: &Connection) -> LocalGenerationResult<SqlResults<'_>> {
+ SqlResults::new(conn, "SELECT * FROM files")
}
pub fn chunkids(conn: &Connection, fileno: FileId) -> LocalGenerationResult<Vec<ChunkId>> {