use crate::error::Error;
use crate::row::Row;
pub trait FromRow: Sized {
fn from_row(row: &Row) -> Result<Self, Error>;
}
pub trait RowIteratorExt: Iterator<Item = Result<Row, Error>> + Sized {
fn map_rows<T: FromRow>(self) -> MapRows<Self, T>;
}
impl<I: Iterator<Item = Result<Row, Error>>> RowIteratorExt for I {
fn map_rows<T: FromRow>(self) -> MapRows<Self, T> {
MapRows {
inner: self,
_marker: std::marker::PhantomData,
}
}
}
pub struct MapRows<I, T> {
inner: I,
_marker: std::marker::PhantomData<T>,
}
impl<I, T> Iterator for MapRows<I, T>
where
I: Iterator<Item = Result<Row, Error>>,
T: FromRow,
{
type Item = Result<T, Error>;
fn next(&mut self) -> Option<Self::Item> {
self.inner
.next()
.map(|result| result.and_then(|row| T::from_row(&row)))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use crate::row::Column;
use mssql_types::SqlValue;
struct TestUser {
id: i32,
name: String,
}
impl FromRow for TestUser {
fn from_row(row: &Row) -> Result<Self, Error> {
Ok(Self {
id: row.get_by_name("id").map_err(Error::from)?,
name: row.get_by_name("name").map_err(Error::from)?,
})
}
}
#[test]
fn test_from_row_manual_impl() {
let columns = vec![
Column::new("id", 0, "INT".to_string()),
Column::new("name", 1, "NVARCHAR".to_string()),
];
let row = Row::from_values(
columns,
vec![SqlValue::Int(42), SqlValue::String("Alice".to_string())],
);
let user = TestUser::from_row(&row).unwrap();
assert_eq!(user.id, 42);
assert_eq!(user.name, "Alice");
}
#[test]
fn test_map_rows_iterator() {
let columns = vec![
Column::new("id", 0, "INT".to_string()),
Column::new("name", 1, "NVARCHAR".to_string()),
];
let rows = vec![
Ok(Row::from_values(
columns.clone(),
vec![SqlValue::Int(1), SqlValue::String("Alice".to_string())],
)),
Ok(Row::from_values(
columns.clone(),
vec![SqlValue::Int(2), SqlValue::String("Bob".to_string())],
)),
];
let users: Vec<TestUser> = rows
.into_iter()
.map_rows::<TestUser>()
.collect::<Result<Vec<_>, _>>()
.unwrap();
assert_eq!(users.len(), 2);
assert_eq!(users[0].id, 1);
assert_eq!(users[0].name, "Alice");
assert_eq!(users[1].id, 2);
assert_eq!(users[1].name, "Bob");
}
}