Skip to content

Commit

Permalink
Provide non-conflicting impls up to a tuple size of 5
Browse files Browse the repository at this point in the history
(This also uses a different strategy to generate these impls as that
results in more maintainable code)
  • Loading branch information
weiznich committed May 24, 2023
1 parent 47392e7 commit 20e00a4
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 226 deletions.
53 changes: 51 additions & 2 deletions diesel/src/pg/query_builder/distinct_on.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::query_builder::{
use crate::query_dsl::methods::DistinctOnDsl;
use crate::query_dsl::order_dsl::ValidOrderingForDistinct;
use crate::result::QueryResult;
use crate::{Expression, QuerySource};
use crate::QuerySource;
use diesel::query_builder::order_clause::OrderClause;

/// Represents `DISTINCT ON (...)`
Expand All @@ -17,7 +17,56 @@ pub struct DistinctOnClause<T>(pub(crate) T);

impl<T> ValidOrderingForDistinct<DistinctOnClause<T>> for NoOrderClause {}
impl<T> ValidOrderingForDistinct<DistinctOnClause<T>> for OrderClause<(T,)> {}
impl<T> ValidOrderingForDistinct<DistinctOnClause<T>> for OrderClause<T> where T: Expression {}
impl<T> ValidOrderingForDistinct<DistinctOnClause<T>> for OrderClause<T> where T: crate::Column {}

macro_rules! valid_ordering {
(@skip: ($ST1: ident, $($ST:ident,)*), $T1:ident, ) => {};
(@skip: ($ST1: ident, $($ST:ident,)*), $T1:ident, $($T:ident,)+) => {
valid_ordering!(($($ST,)*), ($ST1,), $($T,)*);
};
(($ST1: ident,), ($($OT:ident,)*), $T1:ident,) => {
impl<$T1, $ST1, $($OT,)*> ValidOrderingForDistinct<DistinctOnClause<($ST1, $($OT,)*)>> for OrderClause<($T1,)>
where $T1: crate::pg::OrderDecorator<Column = $ST1>,
{}
impl<$T1, $ST1, $($OT,)*> ValidOrderingForDistinct<DistinctOnClause<($T1,)>> for OrderClause<($ST1, $($OT,)*)>
where $ST1: crate::pg::OrderDecorator<Column = $T1>,
{}

impl<$T1, $ST1, $($OT,)*> ValidOrderingForDistinct<DistinctOnClause<$T1>> for OrderClause<($ST1, $($OT,)*)>
where $ST1: crate::pg::OrderDecorator<Column = $T1>,
$T1: crate::Column,
{}
};
(($ST1: ident, $($ST:ident,)*), ($($OT: ident,)*), $T1:ident, $($T:ident,)+) => {
impl<$T1, $($T,)* $ST1, $($ST,)* $($OT,)*> ValidOrderingForDistinct<DistinctOnClause<($ST1, $($ST,)* $($OT,)*)>> for OrderClause<($T1, $($T,)*)>
where $T1: crate::pg::OrderDecorator<Column = $ST1>,
$($T: crate::pg::OrderDecorator<Column = $ST>,)*
{}
impl<$T1, $($T,)* $ST1, $($ST,)* $($OT,)*> ValidOrderingForDistinct<DistinctOnClause<($T1, $($T,)*)>> for OrderClause<($ST1, $($ST,)* $($OT,)*)>
where $ST1: crate::pg::OrderDecorator<Column = $T1>,
$($ST: crate::pg::OrderDecorator<Column = $T>,)*
{}
valid_ordering!(($($ST,)*), ($($OT,)* $ST1,), $($T,)*);
};
($(
$Tuple:tt {
$(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
}
)+) => {
$(
impl<$($T,)* $($ST,)*> ValidOrderingForDistinct<DistinctOnClause<($($T,)*)>> for OrderClause<($($ST,)*)>
where $($ST: crate::pg::OrderDecorator<Column = $T>,)*
{}
valid_ordering!(@skip: ($($ST,)*), $($T,)*);
)*
}
}

// we only generate these impl up to a tuple size of 5 as we generate n*n + 4 impls here
// If we would generate these impls up to max_table_column_count tuple elements that
// would be a really large number for 128 tuple elements (~64k trait impls)
// It's fine to increase this number at some point in the future gradually
diesel_derives::__diesel_for_each_tuple!(valid_ordering, 5);

/// A decorator trait for [`OrderClause`]
/// It helps to have bounds on either Col, Asc<Col> and Desc<Col>.
Expand Down
220 changes: 0 additions & 220 deletions diesel/src/type_impls/tuples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use crate::result::QueryResult;
use crate::row::*;
use crate::sql_types::{HasSqlType, IntoNullable, Nullable, OneIsNullable, SqlType};
use crate::util::{TupleAppend, TupleSize};
use paste::paste;

impl<T> TupleSize for T
where
Expand Down Expand Up @@ -363,18 +362,6 @@ macro_rules! tuple_impls {
impl<$($ST,)*> SqlTypeOrSelectable for Nullable<($($ST,)*)>
where ($($ST,)*): SqlTypeOrSelectable
{}

#[cfg(feature = "postgres")]
impl<__D, $($T,)*> crate::query_dsl::order_dsl::ValidOrderingForDistinct<crate::pg::DistinctOnClause<__D>>
for crate::query_builder::order_clause::OrderClause<(__D, $($T,)*)> {}

#[cfg(feature = "postgres")]
impl<__D, $($T,)*> crate::query_dsl::order_dsl::ValidOrderingForDistinct<crate::pg::DistinctOnClause<__D>>
for crate::query_builder::order_clause::OrderClause<(crate::helper_types::Desc<__D>, $($T,)*)> {}

#[cfg(feature = "postgres")]
impl<__D, $($T,)*> crate::query_dsl::order_dsl::ValidOrderingForDistinct<crate::pg::DistinctOnClause<__D>>
for crate::query_builder::order_clause::OrderClause<(crate::helper_types::Asc<__D>, $($T,)*)> {}
)+
}
}
Expand Down Expand Up @@ -542,210 +529,3 @@ macro_rules! impl_sql_type {
}

diesel_derives::__diesel_for_each_tuple!(tuple_impls);

macro_rules! valid_distinct_order {
(
distinct_t = [$($distinct_t: ident),*],
order_t = [$($order_t: ident),*],
bounds_on = [$($bounds_on: ident),*],
)=> {
valid_distinct_order!{
@build
distinct_t = [$($distinct_t),*],
order_t = [$($order_t),*],
bounds = [],
bounds_on = [$($bounds_on),*],
}
};
(
@build
distinct_t = [$($distinct_t: tt)*],
order_t = [$($order_t: tt)*],
bounds = [$($bounds: tt)*],
bounds_on = [$T1: ident, $($T: ident),*],
)=> {
paste! {
valid_distinct_order!{
@build
distinct_t = [$($distinct_t)*],
order_t = [$($order_t)*],
bounds = [$($bounds)* [<_O $T1>]: crate::pg::OrderDecorator<Column=$T1>, $T1: Column,],
bounds_on = [$($T),*],
}
}
};
(
@build
distinct_t = [$($distinct_t: tt)*],
order_t = [$($order_t: tt)*],
bounds = [$($bounds: tt)*],
bounds_on = [$T1: ident],
)=> {
paste! {
#[allow(unused_parens)]
#[cfg(feature = "postgres")]
impl<$($order_t)* , $($distinct_t)*> crate::query_dsl::order_dsl::ValidOrderingForDistinct<crate::pg::DistinctOnClause<($($distinct_t)*,)>>
for crate::query_builder::order_clause::OrderClause<($($order_t)*,)>
where $($bounds)* [<_O $T1>]: crate::pg::OrderDecorator<Column=$T1>, $T1: Column,
{}
}
};
}

valid_distinct_order! {
distinct_t = [T1],
order_t = [_OT1],
bounds_on = [T1],
}

valid_distinct_order! {
distinct_t = [T1],
order_t = [_OT1, _OT2],
bounds_on = [T1],
}

valid_distinct_order! {
distinct_t = [T1],
order_t = [_OT1, _OT2, _OT3],
bounds_on = [T1],
}

valid_distinct_order! {
distinct_t = [T1],
order_t = [_OT1, _OT2, _OT3, _OT4],
bounds_on = [T1],
}

valid_distinct_order! {
distinct_t = [T1],
order_t = [_OT1, _OT2, _OT3, _OT4, _OT5],
bounds_on = [T1],
}

//

valid_distinct_order! {
distinct_t = [T1, T2],
order_t = [_OT1],
bounds_on = [T1],
}

valid_distinct_order! {
distinct_t = [T1, T2],
order_t = [_OT1, _OT2],
bounds_on = [T1, T2],
}

valid_distinct_order! {
distinct_t = [T1, T2],
order_t = [_OT1, _OT2, _OT3],
bounds_on = [T1, T2],
}

valid_distinct_order! {
distinct_t = [T1, T2],
order_t = [_OT1, _OT2, _OT3, _OT4],
bounds_on = [T1, T2],
}

valid_distinct_order! {
distinct_t = [T1, T2],
order_t = [_OT1, _OT2, _OT3, _OT4, _OT5],
bounds_on = [T1, T2],
}

//

valid_distinct_order! {
distinct_t = [T1, T2, T3],
order_t = [_OT1],
bounds_on = [T1],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3],
order_t = [_OT1, _OT2],
bounds_on = [T1, T2],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3],
order_t = [_OT1, _OT2, _OT3],
bounds_on = [T1, T2, T3],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3],
order_t = [_OT1, _OT2, _OT3, _OT4],
bounds_on = [T1, T2, T3],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3],
order_t = [_OT1, _OT2, _OT3, _OT4, _OT5],
bounds_on = [T1, T2, T3],
}

//

valid_distinct_order! {
distinct_t = [T1, T2, T3, T4],
order_t = [_OT1],
bounds_on = [T1],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3, T4],
order_t = [_OT1, _OT2],
bounds_on = [T1, T2],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3, T4],
order_t = [_OT1, _OT2, _OT3],
bounds_on = [T1, T2, T3],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3, T4],
order_t = [_OT1, _OT2, _OT3, _OT4],
bounds_on = [T1, T2, T3, T4],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3, T4],
order_t = [_OT1, _OT2, _OT3, _OT4, _OT5],
bounds_on = [T1, T2, T3, T4],
}

//

valid_distinct_order! {
distinct_t = [T1, T2, T3, T4, T5],
order_t = [_OT1],
bounds_on = [T1],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3, T4, T5],
order_t = [_OT1, _OT2],
bounds_on = [T1, T2],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3, T4, T5],
order_t = [_OT1, _OT2, _OT3],
bounds_on = [T1, T2, T3],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3, T4, T5],
order_t = [_OT1, _OT2, _OT3, _OT4],
bounds_on = [T1, T2, T3, T4],
}

valid_distinct_order! {
distinct_t = [T1, T2, T3, T4, T5],
order_t = [_OT1, _OT2, _OT3, _OT4, _OT5],
bounds_on = [T1, T2, T3, T4, T5],
}
29 changes: 25 additions & 4 deletions diesel_derives/src/diesel_for_each_tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ pub const MAX_TUPLE_SIZE: i32 = 64;
#[cfg(feature = "128-column-tables")]
pub const MAX_TUPLE_SIZE: i32 = 128;

pub(crate) fn expand(input: Ident) -> TokenStream {
pub(crate) fn expand(input: ForEachTupleInput) -> TokenStream {
let call_side = Span::mixed_site();

let pairs = (0..MAX_TUPLE_SIZE as usize)
let pairs = (0..input.max_size as usize)
.map(|i| {
let t = Ident::new(&format!("T{i}"), call_side);
let st = Ident::new(&format!("ST{i}"), call_side);
Expand All @@ -23,9 +23,9 @@ pub(crate) fn expand(input: Ident) -> TokenStream {
})
.collect::<Vec<_>>();

let mut out = Vec::with_capacity(MAX_TUPLE_SIZE as usize);
let mut out = Vec::with_capacity(input.max_size as usize);

for i in 0..MAX_TUPLE_SIZE {
for i in 0..input.max_size {
let items = &pairs[0..=i as usize];
let tuple = i + 1;
out.push(quote! {
Expand All @@ -34,10 +34,31 @@ pub(crate) fn expand(input: Ident) -> TokenStream {
}
});
}
let input = input.inner;

quote! {
#input! {
#(#out)*
}
}
}

pub struct ForEachTupleInput {
inner: Ident,
max_size: i32,
}

impl syn::parse::Parse for ForEachTupleInput {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let inner = input.parse()?;
let max_size = if input.peek(syn::Token![,]) {
let _ = input.parse::<syn::Token![,]>();
input.parse::<syn::LitInt>()?.base10_parse()?
} else if input.is_empty() {
MAX_TUPLE_SIZE
} else {
unreachable!("Invalid syntax")
};
Ok(Self { inner, max_size })
}
}

0 comments on commit 20e00a4

Please sign in to comment.