diesel/pg/expression/extensions/
interval_dsl.rs1use std::ops::Mul;
2
3use data_types::PgInterval;
4
5pub trait IntervalDsl: Sized + From<i32> + Mul<Self, Output = Self> {
76 fn microseconds(self) -> PgInterval;
78 fn days(self) -> PgInterval;
80 fn months(self) -> PgInterval;
82
83 fn milliseconds(self) -> PgInterval {
85 (self * 1000.into()).microseconds()
86 }
87
88 fn seconds(self) -> PgInterval {
90 (self * 1000.into()).milliseconds()
91 }
92
93 fn minutes(self) -> PgInterval {
95 (self * 60.into()).seconds()
96 }
97
98 fn hours(self) -> PgInterval {
100 (self * 60.into()).minutes()
101 }
102
103 fn weeks(self) -> PgInterval {
109 (self * 7.into()).days()
110 }
111
112 fn years(self) -> PgInterval {
124 (self * 12.into()).months()
125 }
126
127 fn microsecond(self) -> PgInterval {
129 self.microseconds()
130 }
131
132 fn millisecond(self) -> PgInterval {
134 self.milliseconds()
135 }
136
137 fn second(self) -> PgInterval {
139 self.seconds()
140 }
141
142 fn minute(self) -> PgInterval {
144 self.minutes()
145 }
146
147 fn hour(self) -> PgInterval {
149 self.hours()
150 }
151
152 fn day(self) -> PgInterval {
154 self.days()
155 }
156
157 fn week(self) -> PgInterval {
159 self.weeks()
160 }
161
162 fn month(self) -> PgInterval {
164 self.months()
165 }
166
167 fn year(self) -> PgInterval {
169 self.years()
170 }
171}
172
173impl IntervalDsl for i32 {
174 fn microseconds(self) -> PgInterval {
175 i64::from(self).microseconds()
176 }
177
178 fn days(self) -> PgInterval {
179 PgInterval::from_days(self)
180 }
181
182 fn months(self) -> PgInterval {
183 PgInterval::from_months(self)
184 }
185
186 fn milliseconds(self) -> PgInterval {
187 i64::from(self).milliseconds()
188 }
189
190 fn seconds(self) -> PgInterval {
191 i64::from(self).seconds()
192 }
193
194 fn minutes(self) -> PgInterval {
195 i64::from(self).minutes()
196 }
197
198 fn hours(self) -> PgInterval {
199 i64::from(self).hours()
200 }
201}
202
203impl IntervalDsl for i64 {
204 fn microseconds(self) -> PgInterval {
205 PgInterval::from_microseconds(self)
206 }
207
208 fn days(self) -> PgInterval {
209 (self as i32).days()
210 }
211
212 fn months(self) -> PgInterval {
213 (self as i32).months()
214 }
215}
216
217impl IntervalDsl for f64 {
218 fn microseconds(self) -> PgInterval {
219 (self.round() as i64).microseconds()
220 }
221
222 fn days(self) -> PgInterval {
223 let fractional_days = (self.fract() * 86_400.0).seconds();
224 PgInterval::from_days(self.trunc() as i32) + fractional_days
225 }
226
227 fn months(self) -> PgInterval {
228 let fractional_months = (self.fract() * 30.0).days();
229 PgInterval::from_months(self.trunc() as i32) + fractional_months
230 }
231
232 fn years(self) -> PgInterval {
233 ((self * 12.0).trunc() as i32).months()
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 extern crate dotenv;
240 extern crate quickcheck;
241
242 use self::dotenv::dotenv;
243 use self::quickcheck::quickcheck;
244
245 use super::*;
246 use data_types::PgInterval;
247 use dsl::sql;
248 use prelude::*;
249 use {select, sql_types};
250
251 thread_local! {
252 static CONN: PgConnection = {
253 dotenv().ok();
254
255 let connection_url = ::std::env::var("PG_DATABASE_URL")
256 .or_else(|_| ::std::env::var("DATABASE_URL"))
257 .expect("DATABASE_URL must be set in order to run tests");
258 PgConnection::establish(&connection_url).unwrap()
259 }
260 }
261
262 macro_rules! test_fn {
263 ($tpe:ty, $test_name:ident, $units:ident) => {
264 fn $test_name(val: $tpe) -> bool {
265 CONN.with(|connection| {
266 let sql_str = format!(concat!("'{} ", stringify!($units), "'::interval"), val);
267 let query = select(sql::<sql_types::Interval>(&sql_str));
268 let val = val.$units();
269 query
270 .get_result::<PgInterval>(connection)
271 .map(|res| {
272 val.months == res.months
273 && val.days == res.days
274 && val.microseconds - res.microseconds.abs() <= 1
275 })
276 .unwrap_or(false)
277 })
278 }
279
280 quickcheck($test_name as fn($tpe) -> bool);
281 };
282 }
283
284 #[test]
285 fn intervals_match_pg_values_i32() {
286 test_fn!(i32, test_microseconds, microseconds);
287 test_fn!(i32, test_milliseconds, milliseconds);
288 test_fn!(i32, test_seconds, seconds);
289 test_fn!(i32, test_minutes, minutes);
290 test_fn!(i32, test_hours, hours);
291 test_fn!(i32, test_days, days);
292 test_fn!(i32, test_weeks, weeks);
293 test_fn!(i32, test_months, months);
294 test_fn!(i32, test_years, years);
295 }
296
297 #[test]
298 fn intervals_match_pg_values_i64() {
299 test_fn!(i64, test_microseconds, microseconds);
300 test_fn!(i64, test_milliseconds, milliseconds);
301 test_fn!(i64, test_seconds, seconds);
302 test_fn!(i64, test_minutes, minutes);
303 test_fn!(i64, test_hours, hours);
304 test_fn!(i64, test_days, days);
305 test_fn!(i64, test_weeks, weeks);
306 test_fn!(i64, test_months, months);
307 test_fn!(i64, test_years, years);
308 }
309
310 #[test]
311 fn intervals_match_pg_values_f64() {
312 test_fn!(f64, test_microseconds, microseconds);
313 test_fn!(f64, test_milliseconds, milliseconds);
314 test_fn!(f64, test_seconds, seconds);
315 test_fn!(f64, test_minutes, minutes);
316 test_fn!(f64, test_hours, hours);
317 test_fn!(f64, test_days, days);
318 test_fn!(f64, test_weeks, weeks);
319 test_fn!(f64, test_months, months);
320 test_fn!(f64, test_years, years);
321 }
322}