use crate::backend::Backend;
use crate::deserialize;
use deserialize::FromSql;
use std::default::Default;
use std::ops::Range;
#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
#[doc(inline)]
pub use self::private::{PartialRow, RowSealed};
#[cfg(not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))]
#[allow(unused_imports)]
pub(crate) use self::private::{PartialRow, RowSealed};
pub trait RowIndex<I> {
fn idx(&self, idx: I) -> Option<usize>;
}
#[doc(hidden)]
#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
#[deprecated(note = "Use `Row::Field` directly instead")]
pub type FieldRet<'a, R, DB> = <R as self::private::RowLifetimeHelper<DB>>::Field<'a>;
pub trait Row<'a, DB: Backend>:
RowIndex<usize> + for<'b> RowIndex<&'b str> + self::private::RowSealed + Sized
{
type Field<'f>: Field<'f, DB>
where
'a: 'f,
Self: 'f;
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
doc(hidden)
)]
type InnerPartialRow: Row<'a, DB>;
fn field_count(&self) -> usize;
fn get<'b, I>(&'b self, idx: I) -> Option<Self::Field<'b>>
where
'a: 'b,
Self: RowIndex<I>;
fn get_value<ST, T, I>(&self, idx: I) -> crate::deserialize::Result<T>
where
Self: RowIndex<I>,
T: FromSql<ST, DB>,
{
let field = self.get(idx).ok_or(crate::result::UnexpectedEndOfRow)?;
<T as FromSql<ST, DB>>::from_nullable_sql(field.value())
}
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
doc(hidden)
)]
fn partial_row(&self, range: Range<usize>) -> PartialRow<'_, Self::InnerPartialRow>;
}
pub trait Field<'a, DB: Backend> {
fn field_name(&self) -> Option<&str>;
fn value(&self) -> Option<DB::RawValue<'_>>;
fn is_null(&self) -> bool {
self.value().is_none()
}
}
pub trait NamedRow<'a, DB: Backend>: Row<'a, DB> {
fn get<ST, T>(&self, column_name: &str) -> deserialize::Result<T>
where
T: FromSql<ST, DB>;
}
impl<'a, R, DB> NamedRow<'a, DB> for R
where
R: Row<'a, DB>,
DB: Backend,
{
fn get<ST, T>(&self, column_name: &str) -> deserialize::Result<T>
where
T: FromSql<ST, DB>,
{
let field = Row::get(self, column_name)
.ok_or_else(|| format!("Column `{column_name}` was not present in query"))?;
T::from_nullable_sql(field.value())
}
}
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
pub trait IntoOwnedRow<'a, DB: Backend>: Row<'a, DB> {
type OwnedRow: Row<'a, DB> + Send + 'static;
type Cache: Default + 'static;
fn into_owned(self, cache: &mut Self::Cache) -> Self::OwnedRow;
}
pub(crate) mod private {
use super::*;
#[cfg_attr(
diesel_docsrs,
doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
)]
pub trait RowSealed {}
#[derive(Debug)]
#[cfg_attr(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")
)]
pub struct PartialRow<'a, R> {
inner: &'a R,
range: Range<usize>,
}
impl<'a, R> PartialRow<'a, R> {
pub fn new<'b, DB>(inner: &'a R, range: Range<usize>) -> Self
where
R: Row<'b, DB>,
DB: Backend,
{
let range_lower = std::cmp::min(range.start, inner.field_count());
let range_upper = std::cmp::min(range.end, inner.field_count());
Self {
inner,
range: range_lower..range_upper,
}
}
}
impl<R> RowSealed for PartialRow<'_, R> {}
impl<'a, DB, R> Row<'a, DB> for PartialRow<'_, R>
where
DB: Backend,
R: Row<'a, DB>,
{
type Field<'f>
= R::Field<'f>
where
'a: 'f,
R: 'f,
Self: 'f;
type InnerPartialRow = R;
fn field_count(&self) -> usize {
self.range.len()
}
fn get<'c, I>(&'c self, idx: I) -> Option<Self::Field<'c>>
where
'a: 'c,
Self: RowIndex<I>,
{
let idx = self.idx(idx)?;
self.inner.get(idx)
}
fn partial_row(&self, range: Range<usize>) -> PartialRow<'_, R> {
let range_upper_bound = std::cmp::min(self.range.end, self.range.start + range.end);
let range = (self.range.start + range.start)..range_upper_bound;
PartialRow {
inner: self.inner,
range,
}
}
}
impl<'a, R> RowIndex<&'a str> for PartialRow<'_, R>
where
R: RowIndex<&'a str>,
{
fn idx(&self, idx: &'a str) -> Option<usize> {
let idx = self.inner.idx(idx)?;
if self.range.contains(&idx) {
Some(idx)
} else {
None
}
}
}
impl<R> RowIndex<usize> for PartialRow<'_, R>
where
R: RowIndex<usize>,
{
fn idx(&self, idx: usize) -> Option<usize> {
let idx = self.inner.idx(idx + self.range.start)?;
if self.range.contains(&idx) {
Some(idx)
} else {
None
}
}
}
#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
#[allow(unreachable_pub)]
pub trait RowLifetimeHelper<DB>: for<'a> super::Row<'a, DB>
where
DB: Backend,
{
type Field<'f>
where
Self: 'f;
}
#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
impl<R, DB> RowLifetimeHelper<DB> for R
where
DB: Backend,
for<'a> R: super::Row<'a, DB>,
{
type Field<'f>
= <R as super::Row<'f, DB>>::Field<'f>
where
R: 'f;
}
}