prax_postgres/deserialize.rs
1//! Row -> T: FromRow helpers for PgEngine.
2//!
3//! `tokio_postgres::Row` does not implement `prax_query::row::RowRef` (orphan
4//! rule); we wrap each row in `PgRow` first, which does.
5
6use prax_query::error::{QueryError, QueryResult};
7use prax_query::row::FromRow;
8use tokio_postgres::Row;
9
10use crate::row_ref::PgRow;
11
12/// Decode a batch of driver rows into typed models.
13///
14/// # Short-circuit on decode error
15///
16/// Uses `Result<Vec<T>, _>::collect`, which returns the first decode
17/// error and discards every successfully-decoded row before it. A
18/// row-level type mismatch therefore aborts the whole batch rather
19/// than returning partial results. Callers that want per-row
20/// recovery should manually iterate `rows` and handle each
21/// `T::from_row` result.
22pub fn rows_into<T: FromRow>(rows: Vec<Row>) -> QueryResult<Vec<T>> {
23 rows.into_iter()
24 .map(|r| {
25 let r = PgRow::from(r);
26 T::from_row(&r).map_err(|e| {
27 let msg = e.to_string();
28 QueryError::deserialization(msg).with_source(e)
29 })
30 })
31 .collect()
32}
33
34/// Decode a single driver row into a typed model.
35///
36/// Returns a deserialization error if any column fails to decode or
37/// if the FromRow impl returns an error. No partial-result fallback.
38pub fn row_into<T: FromRow>(row: Row) -> QueryResult<T> {
39 let row = PgRow::from(row);
40 T::from_row(&row).map_err(|e| {
41 let msg = e.to_string();
42 QueryError::deserialization(msg).with_source(e)
43 })
44}