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