mirror of
https://github.com/diesel-rs/diesel.git
synced 2024-10-04 01:28:13 +03:00
Allow operators to be used in more places
This implements `std::ops::{Add, Sub, Mul, Div}` for every type I could think of. I've done this by introducing a new derive that we can use for any type with a `where` clause on its `Expression` impl. I've left it undocumented for now, because I think we may just want to bake this into a different derive once RFC 2056 is stable. I've also cleaned up the SQL type implementations, and added new ones for `Interval`. Fixes #1639.
This commit is contained in:
parent
c44b2db5fb
commit
b2edcdb02a
@ -23,6 +23,11 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
|
||||
* Added `sqlite-bundled` feature to `diesel_cli` to make installing on
|
||||
some platforms easier.
|
||||
|
||||
* All functions and operators provided by Diesel can now be used with numeric
|
||||
operators if the SQL type supports it.
|
||||
|
||||
* `PgInterval` can now be used with `-`, `*`, and `/`.
|
||||
|
||||
### Changed
|
||||
|
||||
* `sql_function!` has been redesigned. The syntax is now `sql_function!(fn
|
||||
|
@ -4,10 +4,10 @@ use backend::Backend;
|
||||
use query_builder::*;
|
||||
use result::QueryResult;
|
||||
use serialize::ToSql;
|
||||
use super::*;
|
||||
use sql_types::HasSqlType;
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, DieselNumericOps)]
|
||||
pub struct Bound<T, U> {
|
||||
item: U,
|
||||
_marker: PhantomData<T>,
|
||||
|
@ -5,7 +5,7 @@ use expression::*;
|
||||
use query_builder::*;
|
||||
use result::QueryResult;
|
||||
|
||||
#[derive(Debug, Copy, Clone, QueryId)]
|
||||
#[derive(Debug, Copy, Clone, QueryId, DieselNumericOps)]
|
||||
#[doc(hidden)]
|
||||
/// Coerces an expression to be another type. No checks are performed to ensure
|
||||
/// that the new type is valid in all positions that the previous type was.
|
||||
|
@ -55,7 +55,7 @@ pub fn count_star() -> CountStar {
|
||||
CountStar
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, QueryId)]
|
||||
#[derive(Debug, Clone, Copy, QueryId, DieselNumericOps)]
|
||||
#[doc(hidden)]
|
||||
pub struct CountStar;
|
||||
|
||||
|
@ -192,7 +192,7 @@ macro_rules! __diesel_sql_function_body {
|
||||
use super::*;
|
||||
use $crate::sql_types::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, QueryId)]
|
||||
#[derive(Debug, Clone, Copy, QueryId, DieselNumericOps)]
|
||||
pub struct $fn_name<$($type_args,)* $($arg_name),*> {
|
||||
$(pub(in super) $arg_name: $arg_name,)*
|
||||
$(pub(in super) $type_args: ::std::marker::PhantomData<$type_args>,)*
|
||||
@ -209,7 +209,7 @@ macro_rules! __diesel_sql_function_body {
|
||||
$crate::expression::Expression
|
||||
for $fn_name<$($type_args,)* $($arg_name),*>
|
||||
where
|
||||
for <'a> ($(&'a $arg_name),*): $crate::expression::Expression,
|
||||
($($arg_name),*): $crate::expression::Expression,
|
||||
{
|
||||
type SqlType = $return_type;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use expression::{Expression, NonAggregate};
|
||||
use query_builder::*;
|
||||
use result::QueryResult;
|
||||
|
||||
#[derive(Debug, Copy, Clone, QueryId, Default)]
|
||||
#[derive(Debug, Copy, Clone, QueryId, Default, DieselNumericOps)]
|
||||
pub struct Grouped<T>(pub T);
|
||||
|
||||
impl<T: Expression> Expression for Grouped<T> {
|
||||
|
@ -4,7 +4,7 @@ use query_builder::*;
|
||||
use result::QueryResult;
|
||||
use sql_types::IntoNullable;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, DieselNumericOps)]
|
||||
pub struct Nullable<T>(T);
|
||||
|
||||
impl<T> Nullable<T> {
|
||||
|
@ -61,7 +61,7 @@ macro_rules! __diesel_operator_body {
|
||||
expression_ty_params = ($($expression_ty_params:ident,)*),
|
||||
expression_bounds = ($($expression_bounds:tt)*),
|
||||
) => {
|
||||
#[derive(Debug, Clone, Copy, QueryId)]
|
||||
#[derive(Debug, Clone, Copy, QueryId, DieselNumericOps)]
|
||||
#[doc(hidden)]
|
||||
pub struct $name<$($ty_param,)+> {
|
||||
$(pub(crate) $field_name: $ty_param,)+
|
||||
|
@ -6,7 +6,7 @@ use query_builder::*;
|
||||
use query_dsl::RunQueryDsl;
|
||||
use result::QueryResult;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, DieselNumericOps)]
|
||||
#[must_use = "Queries are only executed when calling `load`, `get_result`, or similar."]
|
||||
/// Returned by the [`sql()`] function.
|
||||
///
|
||||
|
@ -492,25 +492,15 @@ pub mod sql_types {
|
||||
mod ops {
|
||||
use super::sql_types::*;
|
||||
use sql_types::ops::*;
|
||||
use sql_types::{Interval, Nullable};
|
||||
use sql_types::Interval;
|
||||
|
||||
impl Add for Timestamptz {
|
||||
type Rhs = Interval;
|
||||
type Output = Timestamptz;
|
||||
}
|
||||
|
||||
impl Add for Nullable<Timestamptz> {
|
||||
type Rhs = Nullable<Interval>;
|
||||
type Output = Nullable<Timestamptz>;
|
||||
}
|
||||
|
||||
impl Sub for Timestamptz {
|
||||
type Rhs = Interval;
|
||||
type Output = Timestamptz;
|
||||
}
|
||||
|
||||
impl Sub for Nullable<Timestamptz> {
|
||||
type Rhs = Nullable<Interval>;
|
||||
type Output = Nullable<Timestamptz>;
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,8 @@
|
||||
//! satisfied all constraints, Rust would not know which one to use, and there
|
||||
//! would be no way for the user to specify which one should be used.
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Represents SQL types which can be added.
|
||||
pub trait Add {
|
||||
/// The SQL type which can be added to this one
|
||||
@ -66,44 +68,24 @@ pub trait Div {
|
||||
macro_rules! numeric_type {
|
||||
($($tpe: ident),*) => {
|
||||
$(
|
||||
impl Add for super::$tpe {
|
||||
type Rhs = super::$tpe;
|
||||
type Output = super::$tpe;
|
||||
impl Add for $tpe {
|
||||
type Rhs = $tpe;
|
||||
type Output = $tpe;
|
||||
}
|
||||
|
||||
impl Add for super::Nullable<super::$tpe> {
|
||||
type Rhs = super::Nullable<super::$tpe>;
|
||||
type Output = super::Nullable<super::$tpe>;
|
||||
impl Sub for $tpe {
|
||||
type Rhs = $tpe;
|
||||
type Output = $tpe;
|
||||
}
|
||||
|
||||
impl Sub for super::$tpe {
|
||||
type Rhs = super::$tpe;
|
||||
type Output = super::$tpe;
|
||||
impl Mul for $tpe {
|
||||
type Rhs = $tpe;
|
||||
type Output = $tpe;
|
||||
}
|
||||
|
||||
impl Sub for super::Nullable<super::$tpe> {
|
||||
type Rhs = super::Nullable<super::$tpe>;
|
||||
type Output = super::Nullable<super::$tpe>;
|
||||
}
|
||||
|
||||
impl Mul for super::$tpe {
|
||||
type Rhs = super::$tpe;
|
||||
type Output = super::$tpe;
|
||||
}
|
||||
|
||||
impl Mul for super::Nullable<super::$tpe> {
|
||||
type Rhs = super::Nullable<super::$tpe>;
|
||||
type Output = super::Nullable<super::$tpe>;
|
||||
}
|
||||
|
||||
impl Div for super::$tpe {
|
||||
type Rhs = super::$tpe;
|
||||
type Output = super::$tpe;
|
||||
}
|
||||
|
||||
impl Div for super::Nullable<super::$tpe> {
|
||||
type Rhs = super::Nullable<super::$tpe>;
|
||||
type Output = super::Nullable<super::$tpe>;
|
||||
impl Div for $tpe {
|
||||
type Rhs = $tpe;
|
||||
type Output = $tpe;
|
||||
}
|
||||
)*
|
||||
}
|
||||
@ -111,62 +93,92 @@ macro_rules! numeric_type {
|
||||
|
||||
numeric_type!(SmallInt, Integer, BigInt, Float, Double, Numeric);
|
||||
|
||||
impl Add for super::Time {
|
||||
type Rhs = super::Interval;
|
||||
type Output = super::Time;
|
||||
impl Add for Time {
|
||||
type Rhs = Interval;
|
||||
type Output = Time;
|
||||
}
|
||||
|
||||
impl Add for super::Nullable<super::Time> {
|
||||
type Rhs = super::Nullable<super::Interval>;
|
||||
type Output = super::Nullable<super::Time>;
|
||||
impl Sub for Time {
|
||||
type Rhs = Interval;
|
||||
type Output = Time;
|
||||
}
|
||||
|
||||
impl Sub for super::Time {
|
||||
type Rhs = super::Interval;
|
||||
type Output = super::Time;
|
||||
impl Add for Date {
|
||||
type Rhs = Interval;
|
||||
type Output = Timestamp;
|
||||
}
|
||||
|
||||
impl Sub for super::Nullable<super::Time> {
|
||||
type Rhs = super::Nullable<super::Interval>;
|
||||
type Output = super::Nullable<super::Time>;
|
||||
impl Sub for Date {
|
||||
type Rhs = Interval;
|
||||
type Output = Timestamp;
|
||||
}
|
||||
|
||||
impl Add for super::Date {
|
||||
type Rhs = super::Interval;
|
||||
type Output = super::Timestamp;
|
||||
impl Add for Timestamp {
|
||||
type Rhs = Interval;
|
||||
type Output = Timestamp;
|
||||
}
|
||||
|
||||
impl Add for super::Nullable<super::Date> {
|
||||
type Rhs = super::Nullable<super::Interval>;
|
||||
type Output = super::Nullable<super::Timestamp>;
|
||||
impl Sub for Timestamp {
|
||||
type Rhs = Interval;
|
||||
type Output = Timestamp;
|
||||
}
|
||||
|
||||
impl Sub for super::Date {
|
||||
type Rhs = super::Interval;
|
||||
type Output = super::Timestamp;
|
||||
impl Add for Interval {
|
||||
type Rhs = Interval;
|
||||
type Output = Interval;
|
||||
}
|
||||
|
||||
impl Sub for super::Nullable<super::Date> {
|
||||
type Rhs = super::Nullable<super::Interval>;
|
||||
type Output = super::Nullable<super::Timestamp>;
|
||||
impl Sub for Interval {
|
||||
type Rhs = Interval;
|
||||
type Output = Interval;
|
||||
}
|
||||
|
||||
impl Add for super::Timestamp {
|
||||
type Rhs = super::Interval;
|
||||
type Output = super::Timestamp;
|
||||
impl Mul for Interval {
|
||||
type Rhs = Integer;
|
||||
type Output = Interval;
|
||||
}
|
||||
|
||||
impl Add for super::Nullable<super::Timestamp> {
|
||||
type Rhs = super::Nullable<super::Interval>;
|
||||
type Output = super::Nullable<super::Timestamp>;
|
||||
impl Div for Interval {
|
||||
type Rhs = Integer;
|
||||
type Output = Interval;
|
||||
}
|
||||
|
||||
impl Sub for super::Timestamp {
|
||||
type Rhs = super::Interval;
|
||||
type Output = super::Timestamp;
|
||||
impl<T> Add for Nullable<T>
|
||||
where
|
||||
T: Add + NotNull,
|
||||
T::Rhs: NotNull,
|
||||
T::Output: NotNull,
|
||||
{
|
||||
type Rhs = Nullable<T::Rhs>;
|
||||
type Output = Nullable<T::Output>;
|
||||
}
|
||||
|
||||
impl Sub for super::Nullable<super::Timestamp> {
|
||||
type Rhs = super::Nullable<super::Interval>;
|
||||
type Output = super::Nullable<super::Timestamp>;
|
||||
impl<T> Sub for Nullable<T>
|
||||
where
|
||||
T: Sub + NotNull,
|
||||
T::Rhs: NotNull,
|
||||
T::Output: NotNull,
|
||||
{
|
||||
type Rhs = Nullable<T::Rhs>;
|
||||
type Output = Nullable<T::Output>;
|
||||
}
|
||||
|
||||
impl<T> Mul for Nullable<T>
|
||||
where
|
||||
T: Mul + NotNull,
|
||||
T::Rhs: NotNull,
|
||||
T::Output: NotNull,
|
||||
{
|
||||
type Rhs = Nullable<T::Rhs>;
|
||||
type Output = Nullable<T::Output>;
|
||||
}
|
||||
|
||||
impl<T> Div for Nullable<T>
|
||||
where
|
||||
T: Div + NotNull,
|
||||
T::Rhs: NotNull,
|
||||
T::Output: NotNull,
|
||||
{
|
||||
type Rhs = Nullable<T::Rhs>;
|
||||
type Output = Nullable<T::Output>;
|
||||
}
|
||||
|
78
diesel_derives/src/diesel_numeric_ops.rs
Normal file
78
diesel_derives/src/diesel_numeric_ops.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use quote;
|
||||
use syn;
|
||||
|
||||
use util::*;
|
||||
|
||||
pub fn derive(mut item: syn::DeriveInput) -> Result<quote::Tokens, Diagnostic> {
|
||||
let struct_name = item.ident;
|
||||
|
||||
{
|
||||
let where_clause = item.generics
|
||||
.where_clause
|
||||
.get_or_insert(parse_quote!(where));
|
||||
where_clause.predicates.push(parse_quote!(Self: Expression));
|
||||
where_clause.predicates.push_punct(Default::default());
|
||||
}
|
||||
let (_, ty_generics, where_clause) = item.generics.split_for_impl();
|
||||
let mut impl_generics = item.generics.clone();
|
||||
impl_generics.params.push(parse_quote!(__Rhs));
|
||||
let (impl_generics, _, _) = impl_generics.split_for_impl();
|
||||
|
||||
let dummy_name = format!("_impl_diesel_numeric_ops_for_{}", item.ident);
|
||||
|
||||
Ok(wrap_in_dummy_mod(
|
||||
dummy_name.to_lowercase().into(),
|
||||
quote! {
|
||||
use self::diesel::expression::{ops, Expression, AsExpression};
|
||||
use self::diesel::sql_types::ops::{Add, Sub, Mul, Div};
|
||||
|
||||
impl #impl_generics self::std::ops::Add<__Rhs> for #struct_name #ty_generics
|
||||
#where_clause
|
||||
<Self as Expression>::SqlType: Add,
|
||||
__Rhs: AsExpression<<<Self as Expression>::SqlType as Add>::Rhs>,
|
||||
{
|
||||
type Output = ops::Add<Self, __Rhs::Expression>;
|
||||
|
||||
fn add(self, rhs: __Rhs) -> Self::Output {
|
||||
ops::Add::new(self, rhs.as_expression())
|
||||
}
|
||||
}
|
||||
|
||||
impl #impl_generics self::std::ops::Sub<__Rhs> for #struct_name #ty_generics
|
||||
#where_clause
|
||||
<Self as Expression>::SqlType: Sub,
|
||||
__Rhs: AsExpression<<<Self as Expression>::SqlType as Sub>::Rhs>,
|
||||
{
|
||||
type Output = ops::Sub<Self, __Rhs::Expression>;
|
||||
|
||||
fn sub(self, rhs: __Rhs) -> Self::Output {
|
||||
ops::Sub::new(self, rhs.as_expression())
|
||||
}
|
||||
}
|
||||
|
||||
impl #impl_generics self::std::ops::Mul<__Rhs> for #struct_name #ty_generics
|
||||
#where_clause
|
||||
<Self as Expression>::SqlType: Mul,
|
||||
__Rhs: AsExpression<<<Self as Expression>::SqlType as Mul>::Rhs>,
|
||||
{
|
||||
type Output = ops::Mul<Self, __Rhs::Expression>;
|
||||
|
||||
fn mul(self, rhs: __Rhs) -> Self::Output {
|
||||
ops::Mul::new(self, rhs.as_expression())
|
||||
}
|
||||
}
|
||||
|
||||
impl #impl_generics self::std::ops::Div<__Rhs> for #struct_name #ty_generics
|
||||
#where_clause
|
||||
<Self as Expression>::SqlType: Div,
|
||||
__Rhs: AsExpression<<<Self as Expression>::SqlType as Div>::Rhs>,
|
||||
{
|
||||
type Output = ops::Div<Self, __Rhs::Expression>;
|
||||
|
||||
fn div(self, rhs: __Rhs) -> Self::Output {
|
||||
ops::Div::new(self, rhs.as_expression())
|
||||
}
|
||||
}
|
||||
},
|
||||
))
|
||||
}
|
@ -30,6 +30,7 @@ mod util;
|
||||
mod as_changeset;
|
||||
mod as_expression;
|
||||
mod associations;
|
||||
mod diesel_numeric_ops;
|
||||
mod from_sql_row;
|
||||
mod identifiable;
|
||||
mod insertable;
|
||||
@ -56,6 +57,11 @@ pub fn derive_associations(input: TokenStream) -> TokenStream {
|
||||
expand_derive(input, associations::derive)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(DieselNumericOps)]
|
||||
pub fn derive_diesel_numeric_ops(input: TokenStream) -> TokenStream {
|
||||
expand_derive(input, diesel_numeric_ops::derive)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(FromSqlRow, attributes(diesel))]
|
||||
pub fn derive_from_sql_row(input: TokenStream) -> TokenStream {
|
||||
expand_derive(input, from_sql_row::derive)
|
||||
|
Loading…
Reference in New Issue
Block a user