diesel/sql_types/
ops.rs

1//! Represents the output of numeric operators in SQL
2//!
3//! Apps should not need to concern themselves with this module.
4//! If you are looking for where the actual implementation of `std::ops::Add`
5//! and friends are generated for columns, see
6//! [`numeric_expr!`](super::super::numeric_expr!).
7//!
8//! Crates which add new types which allow numeric operators should implement
9//! these traits to specify what the output is for a given right hand side.
10//!
11//! Unlike the traits in `std::ops`, the right hand side is an associated type
12//! rather than a type parameter. The biggest drawback of this is that any type
13//! can only have one right hand type which can be added/subtracted, etc. The
14//! most immediately noticeable effect of this is that you cannot add a nullable
15//! number to one that is not nullable.
16//!
17//! The reason for this is because of the impl of `std::ops::Add` that we need
18//! to be able to write. We want the right hand side to allow Rust values which
19//! should be sent as bind parameters, not just other Diesel expressions. That
20//! means the impl would look like this:
21//!
22//! ```ignore
23//! impl<ST, T> std::ops::Add<T> for my_column
24//! where
25//!     T: AsExpression<ST>,
26//!     my_column::SqlType: diesel::ops::Add<ST>,
27//! ```
28//!
29//! This impl is not valid in Rust, as `ST` is not constrained by the trait or
30//! the implementing type. If there were two valid types for `ST` which
31//! satisfied all constraints, Rust would not know which one to use, and there
32//! would be no way for the user to specify which one should be used.
33
34use super::*;
35
36/// Represents SQL types which can be added.
37pub trait Add {
38    /// The SQL type which can be added to this one
39    type Rhs: SqlType;
40    /// The SQL type of the result of adding `Rhs` to `Self`
41    type Output: SqlType;
42}
43
44/// Represents SQL types which can be subtracted.
45pub trait Sub {
46    /// The SQL type which can be subtracted from this one
47    type Rhs: SqlType;
48    /// The SQL type of the result of subtracting `Rhs` from `Self`
49    type Output: SqlType;
50}
51
52/// Represents SQL types which can be multiplied.
53pub trait Mul {
54    /// The SQL type which this can be multiplied by
55    type Rhs: SqlType;
56    /// The SQL type of the result of multiplying `Self` by `Rhs`
57    type Output: SqlType;
58}
59
60/// Represents SQL types which can be divided.
61pub trait Div {
62    /// The SQL type which this one can be divided by
63    type Rhs: SqlType;
64    /// The SQL type of the result of dividing `Self` by `Rhs`
65    type Output: SqlType;
66}
67
68macro_rules! numeric_type {
69    ($($tpe: ident),*) => {
70        $(
71        impl Add for $tpe {
72            type Rhs = $tpe;
73            type Output = $tpe;
74        }
75
76        impl Sub for $tpe {
77            type Rhs = $tpe;
78            type Output = $tpe;
79        }
80
81        impl Mul for $tpe {
82            type Rhs = $tpe;
83            type Output = $tpe;
84        }
85
86        impl Div for $tpe {
87            type Rhs = $tpe;
88            type Output = $tpe;
89        }
90        )*
91    }
92}
93
94numeric_type!(SmallInt, Integer, BigInt, Float, Double, Numeric);
95
96impl Add for Time {
97    type Rhs = Interval;
98    type Output = Time;
99}
100
101impl Sub for Time {
102    type Rhs = Interval;
103    type Output = Time;
104}
105
106impl Add for Date {
107    type Rhs = Interval;
108    type Output = Timestamp;
109}
110
111impl Sub for Date {
112    type Rhs = Interval;
113    type Output = Timestamp;
114}
115
116impl Add for Timestamp {
117    type Rhs = Interval;
118    type Output = Timestamp;
119}
120
121impl Sub for Timestamp {
122    type Rhs = Interval;
123    type Output = Timestamp;
124}
125
126impl Add for Interval {
127    type Rhs = Interval;
128    type Output = Interval;
129}
130
131impl Sub for Interval {
132    type Rhs = Interval;
133    type Output = Interval;
134}
135
136impl Mul for Interval {
137    type Rhs = Integer;
138    type Output = Interval;
139}
140
141impl Div for Interval {
142    type Rhs = Integer;
143    type Output = Interval;
144}
145
146impl<T> Add for Nullable<T>
147where
148    T: Add + SqlType<IsNull = is_nullable::NotNull>,
149    T::Rhs: SqlType<IsNull = is_nullable::NotNull>,
150    T::Output: SqlType<IsNull = is_nullable::NotNull>,
151{
152    type Rhs = Nullable<T::Rhs>;
153    type Output = Nullable<T::Output>;
154}
155
156impl<T> Sub for Nullable<T>
157where
158    T: Sub + SqlType<IsNull = is_nullable::NotNull>,
159    T::Rhs: SqlType<IsNull = is_nullable::NotNull>,
160    T::Output: SqlType<IsNull = is_nullable::NotNull>,
161{
162    type Rhs = Nullable<T::Rhs>;
163    type Output = Nullable<T::Output>;
164}
165
166impl<T> Mul for Nullable<T>
167where
168    T: Mul + SqlType<IsNull = is_nullable::NotNull>,
169    T::Rhs: SqlType<IsNull = is_nullable::NotNull>,
170    T::Output: SqlType<IsNull = is_nullable::NotNull>,
171{
172    type Rhs = Nullable<T::Rhs>;
173    type Output = Nullable<T::Output>;
174}
175
176impl<T> Div for Nullable<T>
177where
178    T: Div + SqlType<IsNull = is_nullable::NotNull>,
179    T::Rhs: SqlType<IsNull = is_nullable::NotNull>,
180    T::Output: SqlType<IsNull = is_nullable::NotNull>,
181{
182    type Rhs = Nullable<T::Rhs>;
183    type Output = Nullable<T::Output>;
184}