diff options
author | Lars Wirzenius <liw@liw.fi> | 2021-02-03 09:11:49 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2021-02-04 09:14:01 +0200 |
commit | a2adcb5a90c15b473a2fcf114555443fba8a20ce (patch) | |
tree | 7ec36f244daa105b0da774d6705ef736f9135f64 /src/index.rs | |
parent | bf08ea67ca035fc0e78364450599cefff7cd9bc6 (diff) | |
download | obnam2-a2adcb5a90c15b473a2fcf114555443fba8a20ce.tar.gz |
refactor: have per-module error enums
This means that a function that parses step bindings can't return an
error that the document is missing a title. Such an error return would
be nonsensical, and we use the Rust type system to prevent it, at a
small cost of being a bit verbose.
Additional benefit is that the library portion of Obnam doesn't return
anyhow::Result values anymore.
Diffstat (limited to 'src/index.rs')
-rw-r--r-- | src/index.rs | 55 |
1 files changed, 37 insertions, 18 deletions
diff --git a/src/index.rs b/src/index.rs index d527839..f7300da 100644 --- a/src/index.rs +++ b/src/index.rs @@ -17,8 +17,27 @@ pub struct Index { metas: HashMap<ChunkId, ChunkMeta>, } +/// All the errors that may be returned for `Index`. +#[derive(Debug, thiserror::Error)] +pub enum IndexError { + /// Index does not have a chunk. + #[error("The repository index does not have chunk {0}")] + MissingChunk(ChunkId), + + /// Index has chunk more than once. + #[error("The repository index duplicates chunk {0}")] + DuplicateChunk(ChunkId), + + /// An error from SQLite. + #[error(transparent)] + SqlError(#[from] rusqlite::Error), +} + +/// A result from an `Index` operation. +pub type IndexResult<T> = Result<T, IndexError>; + impl Index { - pub fn new<P: AsRef<Path>>(dirname: P) -> anyhow::Result<Self> { + pub fn new<P: AsRef<Path>>(dirname: P) -> IndexResult<Self> { let filename = dirname.as_ref().join("meta.db"); let conn = if filename.exists() { sql::open_db(&filename)? @@ -34,26 +53,26 @@ impl Index { }) } - pub fn insert_meta(&mut self, id: ChunkId, meta: ChunkMeta) -> anyhow::Result<()> { + pub fn insert_meta(&mut self, id: ChunkId, meta: ChunkMeta) -> IndexResult<()> { let t = self.conn.transaction()?; sql::insert(&t, &id, &meta)?; t.commit()?; Ok(()) } - pub fn get_meta(&self, id: &ChunkId) -> anyhow::Result<ChunkMeta> { + pub fn get_meta(&self, id: &ChunkId) -> IndexResult<ChunkMeta> { sql::lookup(&self.conn, id) } - pub fn remove_meta(&mut self, id: &ChunkId) -> anyhow::Result<()> { + pub fn remove_meta(&mut self, id: &ChunkId) -> IndexResult<()> { sql::remove(&self.conn, id) } - pub fn find_by_sha256(&self, sha256: &str) -> anyhow::Result<Vec<ChunkId>> { + pub fn find_by_sha256(&self, sha256: &str) -> IndexResult<Vec<ChunkId>> { sql::find_by_256(&self.conn, sha256) } - pub fn find_generations(&self) -> anyhow::Result<Vec<ChunkId>> { + pub fn find_generations(&self) -> IndexResult<Vec<ChunkId>> { sql::find_generations(&self.conn) } } @@ -132,14 +151,14 @@ mod test { } mod sql { + use super::{IndexError, IndexResult}; use crate::chunkid::ChunkId; use crate::chunkmeta::ChunkMeta; - use crate::error::ObnamError; use log::error; use rusqlite::{params, Connection, OpenFlags, Row, Transaction}; use std::path::Path; - pub fn create_db(filename: &Path) -> anyhow::Result<Connection> { + pub fn create_db(filename: &Path) -> IndexResult<Connection> { let flags = OpenFlags::SQLITE_OPEN_CREATE | OpenFlags::SQLITE_OPEN_READ_WRITE; let conn = Connection::open_with_flags(filename, flags)?; conn.execute( @@ -155,14 +174,14 @@ mod sql { Ok(conn) } - pub fn open_db(filename: &Path) -> anyhow::Result<Connection> { + pub fn open_db(filename: &Path) -> IndexResult<Connection> { let flags = OpenFlags::SQLITE_OPEN_READ_WRITE; let conn = Connection::open_with_flags(filename, flags)?; conn.pragma_update(None, "journal_mode", &"WAL")?; Ok(conn) } - pub fn insert(t: &Transaction, chunkid: &ChunkId, meta: &ChunkMeta) -> anyhow::Result<()> { + pub fn insert(t: &Transaction, chunkid: &ChunkId, meta: &ChunkMeta) -> IndexResult<()> { let chunkid = format!("{}", chunkid); let sha256 = meta.sha256(); let generation = if meta.is_generation() { 1 } else { 0 }; @@ -174,12 +193,12 @@ mod sql { Ok(()) } - pub fn remove(conn: &Connection, chunkid: &ChunkId) -> anyhow::Result<()> { + pub fn remove(conn: &Connection, chunkid: &ChunkId) -> IndexResult<()> { conn.execute("DELETE FROM chunks WHERE id IS ?1", params![chunkid])?; Ok(()) } - pub fn lookup(conn: &Connection, id: &ChunkId) -> anyhow::Result<ChunkMeta> { + pub fn lookup(conn: &Connection, id: &ChunkId) -> IndexResult<ChunkMeta> { let mut stmt = conn.prepare("SELECT * FROM chunks WHERE id IS ?1")?; let iter = stmt.query_map(params![id], |row| row_to_meta(row))?; let mut metas: Vec<ChunkMeta> = vec![]; @@ -189,20 +208,20 @@ mod sql { eprintln!("lookup: meta={:?}", meta); metas.push(meta); } else { - let err = ObnamError::DuplicateChunk(id.clone()); + let err = IndexError::DuplicateChunk(id.clone()); error!("{}", err); return Err(err.into()); } } if metas.len() == 0 { eprintln!("lookup: no hits"); - return Err(ObnamError::MissingChunk(id.clone()).into()); + return Err(IndexError::MissingChunk(id.clone()).into()); } let r = metas[0].clone(); Ok(r) } - pub fn find_by_256(conn: &Connection, sha256: &str) -> anyhow::Result<Vec<ChunkId>> { + pub fn find_by_256(conn: &Connection, sha256: &str) -> IndexResult<Vec<ChunkId>> { let mut stmt = conn.prepare("SELECT id FROM chunks WHERE sha256 IS ?1")?; let iter = stmt.query_map(params![sha256], |row| row_to_id(row))?; let mut ids = vec![]; @@ -213,7 +232,7 @@ mod sql { Ok(ids) } - pub fn find_generations(conn: &Connection) -> anyhow::Result<Vec<ChunkId>> { + pub fn find_generations(conn: &Connection) -> IndexResult<Vec<ChunkId>> { let mut stmt = conn.prepare("SELECT id FROM chunks WHERE generation IS 1")?; let iter = stmt.query_map(params![], |row| row_to_id(row))?; let mut ids = vec![]; @@ -224,7 +243,7 @@ mod sql { Ok(ids) } - pub fn row_to_meta(row: &Row) -> rusqlite::Result<ChunkMeta> { + fn row_to_meta(row: &Row) -> rusqlite::Result<ChunkMeta> { let sha256: String = row.get(row.column_index("sha256")?)?; let generation: i32 = row.get(row.column_index("generation")?)?; let meta = if generation == 0 { @@ -236,7 +255,7 @@ mod sql { Ok(meta) } - pub fn row_to_id(row: &Row) -> rusqlite::Result<ChunkId> { + fn row_to_id(row: &Row) -> rusqlite::Result<ChunkId> { let id: String = row.get(row.column_index("id")?)?; Ok(ChunkId::from_str(&id)) } |