//! Fallible row decoding shared by connection and transaction queries. use rusqlite::{Connection, OptionalExtension, Params, Row}; use crate::error::{Error, Result}; // Read explicitly indexed fields in declaration order; Rust infers their types. macro_rules! sql_row { ($row:ident => $kind:ident { $($field:ident: $index:literal),+ $(,)? }) => { $kind { $($field: $row.get($index)?),+ } }; } pub(crate) use sql_row; pub(crate) fn constraint_conflict(error: rusqlite::Error, message: &str) -> Error { if error.sqlite_error_code() == Some(rusqlite::ErrorCode::ConstraintViolation) { Error::Conflict(message.to_owned()) } else { Error::Database(error) } } pub(crate) fn query( connection: &Connection, sql: &str, params: impl Params, decode: impl FnMut(&Row<'_>) -> Result, ) -> Result> { connection .prepare(sql)? .query_and_then(params, decode)? .collect() } pub(crate) fn query_optional( connection: &Connection, sql: &str, params: impl Params, decode: impl FnOnce(&Row<'_>) -> Result, ) -> Result> { connection .query_row(sql, params, |row| Ok(decode(row))) .optional()? .transpose() } #[cfg(test)] mod tests;