Skip to content

Commit

Permalink
Replace the HasBindCollector trait with a GAT on Backend
Browse files Browse the repository at this point in the history
  • Loading branch information
weiznich committed Dec 30, 2022
1 parent f0f7a92 commit 464ef34
Show file tree
Hide file tree
Showing 12 changed files with 55 additions and 134 deletions.
42 changes: 14 additions & 28 deletions diesel/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::sql_types::{self, HasSqlType, TypeMetadata};
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
pub(crate) use self::private::{DieselReserveSpecialization, HasBindCollector, TrustedBackend};
pub(crate) use self::private::{DieselReserveSpecialization, TrustedBackend};

/// A database backend
///
Expand Down Expand Up @@ -98,7 +98,7 @@ pub(crate) use self::private::{DieselReserveSpecialization, HasBindCollector, Tr
/// [`QueryFragment`]: crate::query_builder::QueryFragment
pub trait Backend
where
Self: Sized + SqlDialect,
Self: Sized + SqlDialect + TypeMetadata,
Self: HasSqlType<sql_types::SmallInt>,
Self: HasSqlType<sql_types::Integer>,
Self: HasSqlType<sql_types::BigInt>,
Expand All @@ -109,7 +109,6 @@ where
Self: HasSqlType<sql_types::Date>,
Self: HasSqlType<sql_types::Time>,
Self: HasSqlType<sql_types::Timestamp>,
Self: for<'a> HasBindCollector<'a>,
{
/// The concrete [`QueryBuilder`] implementation for this backend.
type QueryBuilder: QueryBuilder<Self>;
Expand All @@ -120,16 +119,25 @@ where
///
/// [`FromSql`]: crate::deserialize::FromSql
type RawValue<'a>;

/// The concrete [`BindCollector`](crate::query_builder::bind_collector::BindCollector)
/// implementation for this backend.
///
/// Most backends should use [`RawBytesBindCollector`].
///
/// [`RawBytesBindCollector`]: crate::query_builder::bind_collector::RawBytesBindCollector
type BindCollector<'a>: crate::query_builder::bind_collector::BindCollector<'a, Self> + 'a;
}

#[doc(hidden)]
#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
#[deprecated(note = "Use `Backend::RawValue` directly")]
pub type RawValue<'a, DB> = <DB as Backend>::RawValue<'a>;

/// A helper type to get the bind collector for a database backend.
/// Equivalent to `<DB as HasBindCollector<'a>>::BindCollector<'a>`j
pub type BindCollector<'a, DB> = <DB as HasBindCollector<'a>>::BindCollector;
#[doc(hidden)]
#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
#[deprecated(note = "Use `Backend::BindCollector` directly")]
pub type BindCollector<'a, DB> = <DB as Backend>::BindCollector<'a>;

/// This trait provides various options to configure the
/// generated SQL for a specific backend.
Expand Down Expand Up @@ -524,7 +532,6 @@ pub(crate) mod sql_dialect {
// because we want to replace them by with an associated type
// in the child trait later if GAT's are finally stable
mod private {
use super::TypeMetadata;

/// This is a marker trait which indicates that
/// diesel may specialize a certain [`QueryFragment`]
Expand All @@ -547,27 +554,6 @@ mod private {
)]
pub trait DieselReserveSpecialization {}

/// The bind collector type used to collect query binds for this backend
///
/// This trait is separate from [`Backend`](super::Backend) to imitate `type BindCollector<'a>`. It
/// should only be referenced directly by implementors. Users of this type
/// should instead use the [`BindCollector`] helper type instead.
///
/// [`BindCollector`]: super::BindCollector
#[cfg_attr(
doc_cfg,
doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
)]
pub trait HasBindCollector<'a>: TypeMetadata + Sized {
/// The concrete [`BindCollector`](crate::query_builder::bind_collector::BindCollector)
/// implementation for this backend.
///
/// Most backends should use [`RawBytesBindCollector`].
///
/// [`RawBytesBindCollector`]: crate::query_builder::bind_collector::RawBytesBindCollector
type BindCollector: crate::query_builder::bind_collector::BindCollector<'a, Self> + 'a;
}

/// This trait just indicates that noone implements
/// [`SqlDialect`](super::SqlDialect) without enabling the
/// `i-implement-a-third-party-backend-and-opt-into-breaking-changes`
Expand Down
5 changes: 1 addition & 4 deletions diesel/src/mysql/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ pub enum MysqlType {
impl Backend for Mysql {
type QueryBuilder = MysqlQueryBuilder;
type RawValue<'a> = MysqlValue<'a>;
}

impl<'a> HasBindCollector<'a> for Mysql {
type BindCollector = RawBytesBindCollector<Self>;
type BindCollector<'a> = RawBytesBindCollector<Self>;
}

impl TypeMetadata for Mysql {
Expand Down
5 changes: 1 addition & 4 deletions diesel/src/pg/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,7 @@ impl PgTypeMetadata {
impl Backend for Pg {
type QueryBuilder = PgQueryBuilder;
type RawValue<'a> = PgValue<'a>;
}

impl<'a> HasBindCollector<'a> for Pg {
type BindCollector = RawBytesBindCollector<Pg>;
type BindCollector<'a> = RawBytesBindCollector<Pg>;
}

impl TypeMetadata for Pg {
Expand Down
34 changes: 7 additions & 27 deletions diesel/src/query_builder/ast_pass.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt;

use crate::backend::{Backend, HasBindCollector};
use crate::backend::Backend;
use crate::query_builder::{BindCollector, QueryBuilder};
use crate::result::QueryResult;
use crate::serialize::ToSql;
Expand All @@ -25,7 +25,6 @@ pub struct AstPass<'a, 'b, DB>
where
DB: Backend,
DB::QueryBuilder: 'a,
<DB as HasBindCollector<'a>>::BindCollector: 'a,
DB::MetadataLookup: 'a,
'b: 'a,
{
Expand All @@ -50,7 +49,7 @@ where
}

pub(crate) fn collect_binds(
collector: &'a mut <DB as HasBindCollector<'b>>::BindCollector,
collector: &'a mut DB::BindCollector<'b>,
metadata_lookup: &'a mut DB::MetadataLookup,
backend: &'b DB,
) -> Self {
Expand Down Expand Up @@ -282,13 +281,12 @@ enum AstPassInternals<'a, 'b, DB>
where
DB: Backend,
DB::QueryBuilder: 'a,
<DB as HasBindCollector<'a>>::BindCollector: 'a,
DB::MetadataLookup: 'a,
'b: 'a,
{
ToSql(&'a mut DB::QueryBuilder, &'a mut AstPassToSqlOptions),
CollectBinds {
collector: &'a mut <DB as HasBindCollector<'b>>::BindCollector,
collector: &'a mut DB::BindCollector<'b>,
metadata_lookup: &'a mut DB::MetadataLookup,
},
IsSafeToCachePrepared(&'a mut bool),
Expand All @@ -314,7 +312,6 @@ pub trait AstPassHelper<'a, 'b, DB>
where
DB: Backend,
DB::QueryBuilder: 'a,
<DB as HasBindCollector<'a>>::BindCollector: 'a,
DB::MetadataLookup: 'a,
'b: 'a,
{
Expand All @@ -326,51 +323,39 @@ where
/// due to [compiler bugs](https://github.com/rust-lang/rust/issues/100712)
fn cast_database<DB2>(
self,
convert_bind_collector: impl Fn(
&'a mut <DB as HasBindCollector<'b>>::BindCollector,
) -> &'a mut <DB2 as HasBindCollector<'b>>::BindCollector,
convert_bind_collector: impl Fn(&'a mut DB::BindCollector<'b>) -> &'a mut DB2::BindCollector<'b>,
convert_query_builder: impl Fn(&mut DB::QueryBuilder) -> &mut DB2::QueryBuilder,
convert_backend: impl Fn(&DB) -> &DB2,
convert_lookup: impl Fn(&'a mut DB::MetadataLookup) -> &'a mut DB2::MetadataLookup,
) -> AstPass<'a, 'b, DB2>
where
DB2: Backend,
DB2::QueryBuilder: 'a,
<DB2 as HasBindCollector<'a>>::BindCollector: 'a,
DB2::MetadataLookup: 'a,
'b: 'a;

/// This function allows to access the inner bind collector if
/// this `AstPass` represents a collect binds pass.
fn bind_collector(
&mut self,
) -> Option<(
&mut <DB as HasBindCollector<'b>>::BindCollector,
&mut DB::MetadataLookup,
)>;
fn bind_collector(&mut self) -> Option<(&mut DB::BindCollector<'b>, &mut DB::MetadataLookup)>;
}

impl<'a, 'b, DB> AstPassHelper<'a, 'b, DB> for AstPass<'a, 'b, DB>
where
DB: Backend,
DB::QueryBuilder: 'a,
<DB as HasBindCollector<'a>>::BindCollector: 'a,
DB::MetadataLookup: 'a,
'b: 'a,
{
fn cast_database<DB2>(
self,
convert_bind_collector: impl Fn(
&'a mut <DB as HasBindCollector<'b>>::BindCollector,
) -> &'a mut <DB2 as HasBindCollector<'b>>::BindCollector,
convert_bind_collector: impl Fn(&'a mut DB::BindCollector<'b>) -> &'a mut DB2::BindCollector<'b>,
convert_query_builder: impl Fn(&mut DB::QueryBuilder) -> &mut DB2::QueryBuilder,
convert_backend: impl Fn(&DB) -> &DB2,
convert_lookup: impl Fn(&'a mut DB::MetadataLookup) -> &'a mut DB2::MetadataLookup,
) -> AstPass<'a, 'b, DB2>
where
DB2: Backend,
DB2::QueryBuilder: 'a,
<DB2 as HasBindCollector<'a>>::BindCollector: 'a,
DB2::MetadataLookup: 'a,
'b: 'a,
{
Expand Down Expand Up @@ -398,12 +383,7 @@ where
}
}

fn bind_collector(
&mut self,
) -> Option<(
&mut <DB as HasBindCollector<'b>>::BindCollector,
&mut DB::MetadataLookup,
)> {
fn bind_collector(&mut self) -> Option<(&mut DB::BindCollector<'b>, &mut DB::MetadataLookup)> {
if let AstPassInternals::CollectBinds {
collector,
metadata_lookup,
Expand Down
2 changes: 1 addition & 1 deletion diesel/src/query_builder/bind_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl<DB: Backend + TypeMetadata> RawBytesBindCollector<DB> {

impl<'a, DB> BindCollector<'a, DB> for RawBytesBindCollector<DB>
where
DB: Backend<BindCollector = Self> + TypeMetadata,
for<'b> DB: Backend<BindCollector<'b> = Self> + TypeMetadata,
{
type Buffer = ByteWrapper<'a>;

Expand Down
4 changes: 2 additions & 2 deletions diesel/src/query_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ pub(crate) use self::insert_statement::ColumnList;
#[cfg(feature = "postgres_backend")]
pub use crate::pg::query_builder::only::Only;

use crate::backend::{Backend, HasBindCollector};
use crate::backend::Backend;
use crate::result::QueryResult;
use std::error::Error;

Expand Down Expand Up @@ -233,7 +233,7 @@ pub trait QueryFragment<DB: Backend, SP = self::private::NotSpecialized> {
)]
fn collect_binds<'b>(
&'b self,
out: &mut <DB as HasBindCollector<'b>>::BindCollector,
out: &mut DB::BindCollector<'b>,
metadata_lookup: &mut DB::MetadataLookup,
backend: &'b DB,
) -> QueryResult<()> {
Expand Down
24 changes: 14 additions & 10 deletions diesel/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::fmt;
use std::io::{self, Write};
use std::result;

use crate::backend::{Backend, HasBindCollector};
use crate::backend::Backend;
use crate::query_builder::bind_collector::RawBytesBindCollector;
use crate::query_builder::BindCollector;

Expand Down Expand Up @@ -37,14 +37,14 @@ where
DB: Backend,
DB::MetadataLookup: 'a,
{
out: <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer,
out: <DB::BindCollector<'a> as BindCollector<'a, DB>>::Buffer,
metadata_lookup: Option<&'b mut DB::MetadataLookup>,
}

impl<'a, 'b, DB: Backend> Output<'a, 'b, DB> {
/// Construct a new `Output`
pub fn new(
out: <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer,
out: <DB::BindCollector<'a> as BindCollector<'a, DB>>::Buffer,
metadata_lookup: &'b mut DB::MetadataLookup,
) -> Self {
Output {
Expand All @@ -56,9 +56,7 @@ impl<'a, 'b, DB: Backend> Output<'a, 'b, DB> {
/// Consume the current `Output` structure to access the inner buffer type
///
/// This function is only useful for people implementing their own Backend.
pub fn into_inner(
self,
) -> <crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer {
pub fn into_inner(self) -> <DB::BindCollector<'a> as BindCollector<'a, DB>>::Buffer {
self.out
}

Expand All @@ -74,7 +72,7 @@ impl<'a, 'b, DB: Backend> Output<'a, 'b, DB> {
/// for your specific backend for supported types.
pub fn set_value<V>(&mut self, value: V)
where
V: Into<<crate::backend::BindCollector<'a, DB> as BindCollector<'a, DB>>::Buffer>,
V: Into<<DB::BindCollector<'a> as BindCollector<'a, DB>>::Buffer>,
{
self.out = value.into();
}
Expand All @@ -94,7 +92,10 @@ impl<'a, DB: Backend> Output<'a, 'static, DB> {
}
}

impl<'a, 'b, DB: Backend<BindCollector = RawBytesBindCollector<DB>>> Write for Output<'a, 'b, DB> {
impl<'a, 'b, DB> Write for Output<'a, 'b, DB>
where
for<'c> DB: Backend<BindCollector<'c> = RawBytesBindCollector<DB>>,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.out.0.write(buf)
}
Expand All @@ -112,7 +113,10 @@ impl<'a, 'b, DB: Backend<BindCollector = RawBytesBindCollector<DB>>> Write for O
}
}

impl<'a, 'b, DB: Backend<BindCollector = RawBytesBindCollector<DB>>> Output<'a, 'b, DB> {
impl<'a, 'b, DB> Output<'a, 'b, DB>
where
for<'c> DB: Backend<BindCollector<'c> = RawBytesBindCollector<DB>>,
{
/// Call this method whenever you pass an instance of `Output<DB>` by value.
///
/// Effectively copies `self`, with a narrower lifetime. When passing a
Expand All @@ -138,7 +142,7 @@ impl<'a, 'b, DB: Backend<BindCollector = RawBytesBindCollector<DB>>> Output<'a,

impl<'a, 'b, DB> fmt::Debug for Output<'a, 'b, DB>
where
<<DB as HasBindCollector<'a>>::BindCollector as BindCollector<'a, DB>>::Buffer: fmt::Debug,
<DB::BindCollector<'a> as BindCollector<'a, DB>>::Buffer: fmt::Debug,
DB: Backend,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down
5 changes: 1 addition & 4 deletions diesel/src/sqlite/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ pub enum SqliteType {
impl Backend for Sqlite {
type QueryBuilder = SqliteQueryBuilder;
type RawValue<'a> = SqliteValue<'a, 'a, 'a>;
}

impl<'a> HasBindCollector<'a> for Sqlite {
type BindCollector = SqliteBindCollector<'a>;
type BindCollector<'a> = SqliteBindCollector<'a>;
}

impl TypeMetadata for Sqlite {
Expand Down
4 changes: 2 additions & 2 deletions diesel/src/type_impls/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ where

impl<DB> ToSql<sql_types::Text, DB> for str
where
DB: Backend<BindCollector = RawBytesBindCollector<DB>>,
for<'a> DB: Backend<BindCollector<'a> = RawBytesBindCollector<DB>>,
{
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
out.write_all(self.as_bytes())
Expand Down Expand Up @@ -175,7 +175,7 @@ where

impl<DB> ToSql<sql_types::Binary, DB> for [u8]
where
DB: Backend<BindCollector = RawBytesBindCollector<DB>>,
for<'a> DB: Backend<BindCollector<'a> = RawBytesBindCollector<DB>>,
{
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
out.write_all(self)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ error[E0277]: the trait bound `{integer}: diesel::Expression` is not satisfied
(T0, T1, T2, T3, T4, T5, T6, T7)
and 124 others
= note: required for `diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>` to implement `diesel::Expression`
= note: 1 redundant requirement hidden
= note: required for `diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<string_primary_key::columns::id, {integer}>>` to implement `diesel::Expression`
note: required for `string_primary_key::columns::id` to implement `EqAll<{integer}>`
--> tests/fail/find_requires_correct_type.rs:13:9
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ error[E0277]: the trait bound `diesel::sql_types::Integer: BoolOrNullableBool` i
Bool
Nullable<Bool>
= note: required for `JoinOn<query_source::joins::Join<users::table, posts::table, Inner>, users::columns::id>` to implement `QuerySource`
= note: required because it appears within the type `FromClause<JoinOn<query_source::joins::Join<users::table, posts::table, Inner>, users::columns::id>>`
= note: required for `SelectStatement<FromClause<JoinOn<query_source::joins::Join<users::table, posts::table, Inner>, users::columns::id>>>` to implement `Query`
= note: required for `SelectStatement<FromClause<JoinOn<query_source::joins::Join<users::table, posts::table, Inner>, users::columns::id>>>` to implement `AsQuery`
= note: required for `SelectStatement<FromClause<users::table>>` to implement `InternalJoinDsl<posts::table, Inner, users::columns::id>`
= note: 1 redundant requirement hidden
= note: required for `users::table` to implement `InternalJoinDsl<posts::table, Inner, users::columns::id>`
Expand Down

0 comments on commit 464ef34

Please sign in to comment.