Skip to main content

tank_tests/
time.rs

1use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
2use std::{
3    sync::LazyLock,
4    time::{SystemTime, UNIX_EPOCH},
5};
6use tank::{
7    AsValue, Entity, Executor, Operand, QueryBuilder, Result, cols, expr,
8    stream::{StreamExt, TryStreamExt},
9};
10use time::{Date, Month, PrimitiveDateTime, Time};
11use tokio::sync::Mutex;
12
13static MUTEX: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
14
15#[derive(Entity, Debug, Clone, PartialEq, Eq, Hash)]
16pub struct Times {
17    pub timestamp_1: PrimitiveDateTime,
18    pub timestamp_2: chrono::NaiveDateTime,
19    pub date_1: Date,
20    pub date_2: NaiveDate,
21    pub time_1: time::Time,
22    pub time_2: NaiveTime,
23}
24
25pub async fn times(executor: &mut impl Executor) {
26    let _lock = MUTEX.lock().await;
27
28    // Setup
29    Times::drop_table(executor, true, false)
30        .await
31        .expect("Failed to drop Times table");
32    Times::create_table(executor, false, true)
33        .await
34        .expect("Failed to create Times table");
35
36    // Insert times
37    let timestamps = [
38        // 1980-01-01 00:00:00
39        Times {
40            timestamp_1: PrimitiveDateTime::new(
41                Date::from_calendar_date(1980, Month::January, 1).unwrap(),
42                Time::from_hms(0, 0, 0).unwrap(),
43            ),
44            timestamp_2: NaiveDateTime::new(
45                NaiveDate::from_ymd_opt(1980, 1, 1).unwrap(),
46                NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
47            ),
48            date_1: Date::from_calendar_date(1980, Month::January, 1).unwrap(),
49            date_2: NaiveDate::from_ymd_opt(1980, 1, 1).unwrap(),
50            time_1: Time::from_hms(0, 0, 0).unwrap(),
51            time_2: NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
52        },
53        // 1987-10-05 14:09:00
54        Times {
55            timestamp_1: PrimitiveDateTime::new(
56                Date::from_calendar_date(1987, Month::October, 5).unwrap(),
57                Time::from_hms(14, 9, 0).unwrap(),
58            ),
59            timestamp_2: NaiveDateTime::new(
60                NaiveDate::from_ymd_opt(1987, 10, 5).unwrap(),
61                NaiveTime::from_hms_opt(14, 9, 0).unwrap(),
62            ),
63            date_1: Date::from_calendar_date(1987, Month::October, 5).unwrap(),
64            date_2: NaiveDate::from_ymd_opt(1987, 10, 5).unwrap(),
65            time_1: Time::from_hms(14, 9, 0).unwrap(),
66            time_2: NaiveTime::from_hms_opt(14, 9, 0).unwrap(),
67        },
68        // 1999-12-31 23:59:00
69        Times {
70            timestamp_1: PrimitiveDateTime::new(
71                Date::from_calendar_date(1999, Month::December, 31).unwrap(),
72                Time::from_hms(23, 59, 0).unwrap(),
73            ),
74            timestamp_2: NaiveDateTime::new(
75                NaiveDate::from_ymd_opt(1999, 12, 31).unwrap(),
76                NaiveTime::from_hms_opt(23, 59, 0).unwrap(),
77            ),
78            date_1: Date::from_calendar_date(1999, Month::December, 31).unwrap(),
79            date_2: NaiveDate::from_ymd_opt(1999, 12, 31).unwrap(),
80            time_1: Time::from_hms(23, 59, 0).unwrap(),
81            time_2: NaiveTime::from_hms_opt(23, 59, 0).unwrap(),
82        },
83        // 2025-01-01 00:00:00
84        Times {
85            timestamp_1: PrimitiveDateTime::new(
86                Date::from_calendar_date(2025, Month::January, 1).unwrap(),
87                Time::from_hms(0, 0, 0).unwrap(),
88            ),
89            timestamp_2: NaiveDateTime::new(
90                NaiveDate::from_ymd_opt(2025, 1, 1).unwrap(),
91                NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
92            ),
93            date_1: Date::from_calendar_date(2025, Month::January, 1).unwrap(),
94            date_2: NaiveDate::from_ymd_opt(2025, 1, 1).unwrap(),
95            time_1: Time::from_hms(0, 0, 0).unwrap(),
96            time_2: NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
97        },
98        // 1950-06-15 08:30:00
99        Times {
100            timestamp_1: PrimitiveDateTime::new(
101                Date::from_calendar_date(1950, Month::June, 15).unwrap(),
102                Time::from_hms(8, 30, 0).unwrap(),
103            ),
104            timestamp_2: NaiveDateTime::new(
105                NaiveDate::from_ymd_opt(1950, 6, 15).unwrap(),
106                NaiveTime::from_hms_opt(8, 30, 0).unwrap(),
107            ),
108            date_1: Date::from_calendar_date(1950, Month::June, 15).unwrap(),
109            date_2: NaiveDate::from_ymd_opt(1950, 6, 15).unwrap(),
110            time_1: Time::from_hms(8, 30, 0).unwrap(),
111            time_2: NaiveTime::from_hms_opt(8, 30, 0).unwrap(),
112        },
113        // 2038-01-19 03:14:07
114        Times {
115            timestamp_1: PrimitiveDateTime::new(
116                Date::from_calendar_date(2038, Month::January, 19).unwrap(),
117                Time::from_hms(3, 14, 7).unwrap(),
118            ),
119            timestamp_2: NaiveDateTime::new(
120                NaiveDate::from_ymd_opt(2038, 1, 19).unwrap(),
121                NaiveTime::from_hms_opt(3, 14, 7).unwrap(),
122            ),
123            date_1: Date::from_calendar_date(2038, Month::January, 19).unwrap(),
124            date_2: NaiveDate::from_ymd_opt(2038, 1, 19).unwrap(),
125            time_1: Time::from_hms(3, 14, 7).unwrap(),
126            time_2: NaiveTime::from_hms_opt(3, 14, 7).unwrap(),
127        },
128        // 2025-07-19 09:42:00
129        Times {
130            timestamp_1: PrimitiveDateTime::new(
131                Date::from_calendar_date(2025, Month::July, 19).unwrap(),
132                Time::from_hms(9, 42, 0).unwrap(),
133            ),
134            timestamp_2: NaiveDateTime::new(
135                NaiveDate::from_ymd_opt(2025, 7, 19).unwrap(),
136                NaiveTime::from_hms_opt(9, 42, 0).unwrap(),
137            ),
138            date_1: Date::from_calendar_date(2025, Month::July, 19).unwrap(),
139            date_2: NaiveDate::from_ymd_opt(2025, 7, 19).unwrap(),
140            time_1: Time::from_hms(9, 42, 0).unwrap(),
141            time_2: NaiveTime::from_hms_opt(9, 42, 0).unwrap(),
142        },
143        // 2050-11-11 18:45:59
144        Times {
145            timestamp_1: PrimitiveDateTime::new(
146                Date::from_calendar_date(2050, Month::November, 11).unwrap(),
147                Time::from_hms(18, 45, 59).unwrap(),
148            ),
149            timestamp_2: NaiveDateTime::new(
150                NaiveDate::from_ymd_opt(2050, 11, 11).unwrap(),
151                NaiveTime::from_hms_opt(18, 45, 59).unwrap(),
152            ),
153            date_1: Date::from_calendar_date(2050, Month::November, 11).unwrap(),
154            date_2: NaiveDate::from_ymd_opt(2050, 11, 11).unwrap(),
155            time_1: Time::from_hms(18, 45, 59).unwrap(),
156            time_2: NaiveTime::from_hms_opt(18, 45, 59).unwrap(),
157        },
158        // 2050-09-09 00:00:00
159        Times {
160            timestamp_1: PrimitiveDateTime::new(
161                Date::from_calendar_date(2050, Month::September, 9).unwrap(),
162                Time::from_hms(0, 0, 0).unwrap(),
163            ),
164            timestamp_2: NaiveDateTime::new(
165                NaiveDate::from_ymd_opt(2050, 9, 9).unwrap(),
166                NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
167            ),
168            date_1: Date::from_calendar_date(2050, Month::September, 9).unwrap(),
169            date_2: NaiveDate::from_ymd_opt(2050, 9, 9).unwrap(),
170            time_1: Time::from_hms(0, 0, 0).unwrap(),
171            time_2: NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
172        },
173    ];
174
175    Times::insert_many(executor, &timestamps)
176        .await
177        .expect("Failed to insert timestamps");
178
179    /*
180     * 1987-10-05 14:09:00
181     * 1999-12-31 23:59:00
182     * 2025-01-01 00:00:00
183     * 1950-06-15 08:30:00
184     * 1900-01-01 00:00:00
185     * 2038-01-19 03:14:07
186     * 2025-07-19 09:42:00
187     * 2050-11-11 18:45:59
188     * 2050-09-09 00:00:00
189     */
190
191    // Query timestamp 1
192    let mut query_timestamp_1 = executor
193        .prepare(
194            QueryBuilder::new()
195                .select([Times::timestamp_1])
196                .from(Times::table())
197                .where_expr(expr!(Times::timestamp_2 > ?))
198                .order_by(cols!(Times::timestamp_1 DESC))
199                .build(&executor.driver()),
200        )
201        .await
202        .expect("Could not prepare the query timestamp 1");
203    query_timestamp_1
204        .bind(PrimitiveDateTime::new(
205            Date::from_calendar_date(1999, Month::December, 31).unwrap(),
206            Time::from_hms(23, 59, 59).unwrap(),
207        ))
208        .expect("Could not bind the timestamp 1");
209    let values = executor
210        .fetch(&mut query_timestamp_1)
211        .and_then(|v| async {
212            PrimitiveDateTime::try_from_value(
213                v.values
214                    .into_iter()
215                    .next()
216                    .expect("Could not get the first column"),
217            )
218            .map(|v| v.to_string())
219        })
220        .try_collect::<Vec<_>>()
221        .await
222        .expect("Could not collect the values from the stream");
223    assert_eq!(
224        values,
225        [
226            "2050-11-11 18:45:59.0",
227            "2050-09-09 0:00:00.0",
228            "2038-01-19 3:14:07.0",
229            "2025-07-19 9:42:00.0",
230            "2025-01-01 0:00:00.0",
231        ]
232    );
233    query_timestamp_1
234        .clear_bindings()
235        .expect("Could not clear the bindings for query timestamp 1");
236    query_timestamp_1
237        .bind(PrimitiveDateTime::new(
238            Date::from_calendar_date(1800, Month::January, 1).unwrap(),
239            Time::from_hms(0, 0, 0).unwrap(),
240        ))
241        .expect("Could not bind the timestamp 1");
242    let values = executor
243        .fetch(&mut query_timestamp_1)
244        .and_then(|v| async {
245            NaiveDateTime::try_from_value(
246                v.values
247                    .into_iter()
248                    .next()
249                    .expect("Could not get the first column"),
250            )
251            .map(|v| v.to_string())
252        })
253        .try_collect::<Vec<_>>()
254        .await
255        .expect("Could not collect the values from the stream");
256    assert_eq!(
257        values,
258        [
259            "2050-11-11 18:45:59",
260            "2050-09-09 00:00:00",
261            "2038-01-19 03:14:07",
262            "2025-07-19 09:42:00",
263            "2025-01-01 00:00:00",
264            "1999-12-31 23:59:00",
265            "1987-10-05 14:09:00",
266            "1980-01-01 00:00:00",
267            "1950-06-15 08:30:00",
268        ]
269    );
270
271    // Query timestamp 2
272    let mut query_timestamp_2 = executor
273        .prepare(
274            QueryBuilder::new()
275                .select([Times::timestamp_2])
276                .from(Times::table())
277                .where_expr(expr!(Times::timestamp_1 <= ?))
278                .order_by(cols!(Times::timestamp_2 ASC))
279                .build(&executor.driver()),
280        )
281        .await
282        .expect("Could not prepare the query timestamp 1");
283    query_timestamp_2
284        .bind(NaiveDateTime::new(
285            NaiveDate::from_ymd_opt(2025, 1, 1).unwrap(),
286            NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
287        ))
288        .expect("Could not bind the timestamp 1");
289    let values = executor
290        .fetch(&mut query_timestamp_2)
291        .and_then(|v| async {
292            NaiveDateTime::try_from_value(
293                v.values
294                    .into_iter()
295                    .next()
296                    .expect("Could not get the first column"),
297            )
298            .map(|v| v.to_string())
299        })
300        .try_collect::<Vec<_>>()
301        .await
302        .expect("Could not collect the values from the stream");
303    assert_eq!(
304        values,
305        [
306            "1950-06-15 08:30:00",
307            "1980-01-01 00:00:00",
308            "1987-10-05 14:09:00",
309            "1999-12-31 23:59:00",
310            "2025-01-01 00:00:00",
311        ]
312    );
313
314    // Query time 1
315    let mut query_time_1 = executor
316        .prepare(
317            QueryBuilder::new()
318                .select([Times::time_1])
319                .from(Times::table())
320                .where_expr(true)
321                .order_by(cols!(Times::time_1 DESC))
322                .build(&executor.driver()),
323        )
324        .await
325        .expect("Could not prepare the query timestamp 1");
326    let values = executor
327        .fetch(&mut query_time_1)
328        .and_then(|v| async {
329            NaiveTime::try_from_value(
330                v.values
331                    .into_iter()
332                    .next()
333                    .expect("Could not get the first column"),
334            )
335            .map(|v| v.to_string())
336        })
337        .try_collect::<Vec<_>>()
338        .await
339        .expect("Could not collect the values from the stream");
340    assert_eq!(
341        values,
342        [
343            "23:59:00", "18:45:59", "14:09:00", "09:42:00", "08:30:00", "03:14:07", "00:00:00",
344            "00:00:00", "00:00:00",
345        ]
346    );
347
348    // Current timestamp ms
349    let before = SystemTime::now()
350        .duration_since(UNIX_EPOCH)
351        .unwrap()
352        .as_millis()
353        - 2;
354    let timestamp_ms = executor
355        .fetch(
356            QueryBuilder::new()
357                .select([&Operand::CurrentTimestampMs])
358                .from(Times::table())
359                .where_expr(true)
360                .limit(Some(1))
361                .build(&executor.driver()),
362        )
363        .map_ok(|v| u128::try_from_value(v.values.into_iter().nth(0).expect("There is no column")))
364        .map(Result::flatten)
365        .try_collect::<Vec<_>>()
366        .await
367        .expect("Could not get the current timestamp");
368    let after = SystemTime::now()
369        .duration_since(UNIX_EPOCH)
370        .unwrap()
371        .as_millis()
372        + 2;
373    let timestamp_ms = timestamp_ms.into_iter().next().unwrap();
374    assert!(before <= timestamp_ms, "{before} <= {timestamp_ms}");
375    assert!(timestamp_ms <= after, "{timestamp_ms} <= {after}");
376}