diesel_async/pg/
row.rs

1use diesel::backend::Backend;
2use diesel::row::{Field, PartialRow, RowIndex, RowSealed};
3use std::{error::Error, num::NonZeroU32};
4use tokio_postgres::{types::Type, Row};
5
6pub struct PgRow {
7    row: Row,
8}
9
10impl PgRow {
11    pub(super) fn new(row: Row) -> Self {
12        Self { row }
13    }
14}
15impl RowSealed for PgRow {}
16
17impl<'a> diesel::row::Row<'a, diesel::pg::Pg> for PgRow {
18    type InnerPartialRow = Self;
19    type Field<'b>
20        = PgField<'b>
21    where
22        Self: 'b,
23        'a: 'b;
24
25    fn field_count(&self) -> usize {
26        self.row.len()
27    }
28
29    fn get<'b, I>(&'b self, idx: I) -> Option<Self::Field<'b>>
30    where
31        'a: 'b,
32        Self: diesel::row::RowIndex<I>,
33    {
34        let idx = self.idx(idx)?;
35        Some(PgField {
36            row: &self.row,
37            idx,
38        })
39    }
40
41    fn partial_row(
42        &self,
43        range: std::ops::Range<usize>,
44    ) -> diesel::row::PartialRow<'_, Self::InnerPartialRow> {
45        PartialRow::new(self, range)
46    }
47}
48
49impl RowIndex<usize> for PgRow {
50    fn idx(&self, idx: usize) -> Option<usize> {
51        if idx < self.row.len() {
52            Some(idx)
53        } else {
54            None
55        }
56    }
57}
58
59impl<'a> RowIndex<&'a str> for PgRow {
60    fn idx(&self, idx: &'a str) -> Option<usize> {
61        self.row.columns().iter().position(|c| c.name() == idx)
62    }
63}
64
65pub struct PgField<'a> {
66    row: &'a Row,
67    idx: usize,
68}
69
70impl<'a> Field<'a, diesel::pg::Pg> for PgField<'a> {
71    fn field_name(&self) -> Option<&str> {
72        Some(self.row.columns()[self.idx].name())
73    }
74
75    fn value(&self) -> Option<<diesel::pg::Pg as Backend>::RawValue<'_>> {
76        let DieselFromSqlWrapper(value) = self.row.get(self.idx);
77        value
78    }
79}
80
81#[repr(transparent)]
82struct TyWrapper(Type);
83
84impl diesel::pg::TypeOidLookup for TyWrapper {
85    fn lookup(&self) -> NonZeroU32 {
86        NonZeroU32::new(self.0.oid()).unwrap()
87    }
88}
89
90struct DieselFromSqlWrapper<'a>(Option<diesel::pg::PgValue<'a>>);
91
92impl<'a> tokio_postgres::types::FromSql<'a> for DieselFromSqlWrapper<'a> {
93    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + 'static + Send + Sync>> {
94        let ty = unsafe { &*(ty as *const Type as *const TyWrapper) };
95        Ok(DieselFromSqlWrapper(Some(diesel::pg::PgValue::new(
96            raw, ty,
97        ))))
98    }
99
100    fn accepts(ty: &Type) -> bool {
101        ty.oid() != 0
102    }
103
104    fn from_sql_null(_ty: &Type) -> Result<Self, Box<dyn Error + Sync + Send>> {
105        Ok(DieselFromSqlWrapper(None))
106    }
107}