1use bytes::BufMut;
16use chrono::{NaiveDate, NaiveDateTime};
17use pgwire::types::ToSqlText;
18use pgwire::types::format::FormatOptions;
19use postgres_types::{IsNull, ToSql, Type};
20use session::session_config::{PGDateOrder, PGDateTimeStyle};
21
22#[derive(Debug)]
23pub struct StylingDate(pub NaiveDate, pub PGDateTimeStyle, pub PGDateOrder);
24
25#[derive(Debug)]
26pub struct StylingDateTime(pub NaiveDateTime, pub PGDateTimeStyle, pub PGDateOrder);
27
28fn date_format_string(style: PGDateTimeStyle, order: PGDateOrder) -> &'static str {
29 match style {
30 PGDateTimeStyle::ISO => "%Y-%m-%d",
31 PGDateTimeStyle::German => "%d.%m.%Y",
32 PGDateTimeStyle::Postgres => match order {
33 PGDateOrder::MDY | PGDateOrder::YMD => "%m-%d-%Y",
34 PGDateOrder::DMY => "%d-%m-%Y",
35 },
36 PGDateTimeStyle::SQL => match order {
37 PGDateOrder::MDY | PGDateOrder::YMD => "%m/%d/%Y",
38 PGDateOrder::DMY => "%d/%m/%Y",
39 },
40 }
41}
42
43fn datetime_format_string(style: PGDateTimeStyle, order: PGDateOrder) -> &'static str {
44 match style {
45 PGDateTimeStyle::ISO => "%Y-%m-%d %H:%M:%S%.6f",
46 PGDateTimeStyle::German => "%d.%m.%Y %H:%M:%S%.6f",
47 PGDateTimeStyle::Postgres => match order {
48 PGDateOrder::MDY | PGDateOrder::YMD => "%a %b %d %H:%M:%S%.6f %Y",
49 PGDateOrder::DMY => "%a %d %b %H:%M:%S%.6f %Y",
50 },
51 PGDateTimeStyle::SQL => match order {
52 PGDateOrder::MDY | PGDateOrder::YMD => "%m/%d/%Y %H:%M:%S%.6f",
53 PGDateOrder::DMY => "%d/%m/%Y %H:%M:%S%.6f",
54 },
55 }
56}
57impl ToSqlText for StylingDate {
58 fn to_sql_text(
59 &self,
60 ty: &Type,
61 out: &mut bytes::BytesMut,
62 format_options: &FormatOptions,
63 ) -> std::result::Result<IsNull, Box<dyn std::error::Error + Sync + Send>>
64 where
65 Self: Sized,
66 {
67 match *ty {
68 Type::DATE => {
69 let fmt = self
70 .0
71 .format(date_format_string(self.1, self.2))
72 .to_string();
73 out.put_slice(fmt.as_bytes());
74 }
75 _ => {
76 self.0.to_sql_text(ty, out, format_options)?;
77 }
78 }
79 Ok(IsNull::No)
80 }
81}
82
83impl ToSqlText for StylingDateTime {
84 fn to_sql_text(
85 &self,
86 ty: &Type,
87 out: &mut bytes::BytesMut,
88 format_options: &FormatOptions,
89 ) -> Result<IsNull, Box<dyn std::error::Error + Sync + Send>>
90 where
91 Self: Sized,
92 {
93 match *ty {
94 Type::TIMESTAMP => {
95 let fmt = self
96 .0
97 .format(datetime_format_string(self.1, self.2))
98 .to_string();
99 out.put_slice(fmt.as_bytes());
100 }
101 Type::DATE => {
102 let fmt = self
103 .0
104 .format(date_format_string(self.1, self.2))
105 .to_string();
106 out.put_slice(fmt.as_bytes());
107 }
108 _ => {
109 self.0.to_sql_text(ty, out, format_options)?;
110 }
111 }
112 Ok(IsNull::No)
113 }
114}
115
116macro_rules! delegate_to_sql {
117 ($delegator:ident, $delegatee:ident) => {
118 impl ToSql for $delegator {
119 fn to_sql(
120 &self,
121 ty: &Type,
122 out: &mut bytes::BytesMut,
123 ) -> std::result::Result<IsNull, Box<dyn std::error::Error + Sync + Send>> {
124 self.0.to_sql(ty, out)
125 }
126
127 fn accepts(ty: &Type) -> bool {
128 <$delegatee as ToSql>::accepts(ty)
129 }
130
131 fn to_sql_checked(
132 &self,
133 ty: &Type,
134 out: &mut bytes::BytesMut,
135 ) -> Result<IsNull, Box<dyn std::error::Error + Sync + Send>> {
136 self.0.to_sql_checked(ty, out)
137 }
138 }
139 };
140}
141
142delegate_to_sql!(StylingDate, NaiveDate);
143delegate_to_sql!(StylingDateTime, NaiveDateTime);
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn test_styling_date() {
151 let naive_date = NaiveDate::from_ymd_opt(1997, 12, 17).unwrap();
152
153 {
154 let styling_date = StylingDate(naive_date, PGDateTimeStyle::ISO, PGDateOrder::MDY);
155 let expected = "1997-12-17";
156 let mut out = bytes::BytesMut::new();
157 let is_null = styling_date
158 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
159 .unwrap();
160 assert!(matches!(is_null, IsNull::No));
161 assert_eq!(out, expected.as_bytes());
162 }
163
164 {
165 let styling_date = StylingDate(naive_date, PGDateTimeStyle::ISO, PGDateOrder::YMD);
166 let expected = "1997-12-17";
167 let mut out = bytes::BytesMut::new();
168 let is_null = styling_date
169 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
170 .unwrap();
171 assert!(matches!(is_null, IsNull::No));
172 assert_eq!(out, expected.as_bytes());
173 }
174
175 {
176 let styling_date = StylingDate(naive_date, PGDateTimeStyle::ISO, PGDateOrder::DMY);
177 let expected = "1997-12-17";
178 let mut out = bytes::BytesMut::new();
179 let is_null = styling_date
180 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
181 .unwrap();
182 assert!(matches!(is_null, IsNull::No));
183 assert_eq!(out, expected.as_bytes());
184 }
185
186 {
187 let styling_date = StylingDate(naive_date, PGDateTimeStyle::German, PGDateOrder::MDY);
188 let expected = "17.12.1997";
189 let mut out = bytes::BytesMut::new();
190 let is_null = styling_date
191 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
192 .unwrap();
193 assert!(matches!(is_null, IsNull::No));
194 assert_eq!(out, expected.as_bytes());
195 }
196
197 {
198 let styling_date = StylingDate(naive_date, PGDateTimeStyle::German, PGDateOrder::YMD);
199 let expected = "17.12.1997";
200 let mut out = bytes::BytesMut::new();
201 let is_null = styling_date
202 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
203 .unwrap();
204 assert!(matches!(is_null, IsNull::No));
205 assert_eq!(out, expected.as_bytes());
206 }
207
208 {
209 let styling_date = StylingDate(naive_date, PGDateTimeStyle::German, PGDateOrder::DMY);
210 let expected = "17.12.1997";
211 let mut out = bytes::BytesMut::new();
212 let is_null = styling_date
213 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
214 .unwrap();
215 assert!(matches!(is_null, IsNull::No));
216 assert_eq!(out, expected.as_bytes());
217 }
218
219 {
220 let styling_date = StylingDate(naive_date, PGDateTimeStyle::Postgres, PGDateOrder::MDY);
221 let expected = "12-17-1997";
222 let mut out = bytes::BytesMut::new();
223 let is_null = styling_date
224 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
225 .unwrap();
226 assert!(matches!(is_null, IsNull::No));
227 assert_eq!(out, expected.as_bytes());
228 }
229
230 {
231 let styling_date = StylingDate(naive_date, PGDateTimeStyle::Postgres, PGDateOrder::YMD);
232 let expected = "12-17-1997";
233 let mut out = bytes::BytesMut::new();
234 let is_null = styling_date
235 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
236 .unwrap();
237 assert!(matches!(is_null, IsNull::No));
238 assert_eq!(out, expected.as_bytes());
239 }
240
241 {
242 let styling_date = StylingDate(naive_date, PGDateTimeStyle::Postgres, PGDateOrder::DMY);
243 let expected = "17-12-1997";
244 let mut out = bytes::BytesMut::new();
245 let is_null = styling_date
246 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
247 .unwrap();
248 assert!(matches!(is_null, IsNull::No));
249 assert_eq!(out, expected.as_bytes());
250 }
251
252 {
253 let styling_date = StylingDate(naive_date, PGDateTimeStyle::SQL, PGDateOrder::MDY);
254 let expected = "12/17/1997";
255 let mut out = bytes::BytesMut::new();
256 let is_null = styling_date
257 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
258 .unwrap();
259 assert!(matches!(is_null, IsNull::No));
260 assert_eq!(out, expected.as_bytes());
261 }
262
263 {
264 let styling_date = StylingDate(naive_date, PGDateTimeStyle::SQL, PGDateOrder::YMD);
265 let expected = "12/17/1997";
266 let mut out = bytes::BytesMut::new();
267 let is_null = styling_date
268 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
269 .unwrap();
270 assert!(matches!(is_null, IsNull::No));
271 assert_eq!(out, expected.as_bytes());
272 }
273
274 {
275 let styling_date = StylingDate(naive_date, PGDateTimeStyle::SQL, PGDateOrder::DMY);
276 let expected = "17/12/1997";
277 let mut out = bytes::BytesMut::new();
278 let is_null = styling_date
279 .to_sql_text(&Type::DATE, &mut out, &FormatOptions::default())
280 .unwrap();
281 assert!(matches!(is_null, IsNull::No));
282 assert_eq!(out, expected.as_bytes());
283 }
284 }
285
286 #[test]
287 fn test_styling_datetime() {
288 let input =
289 NaiveDateTime::parse_from_str("2021-09-01 12:34:56.789012", "%Y-%m-%d %H:%M:%S%.f")
290 .unwrap();
291
292 {
293 let styling_datetime = StylingDateTime(input, PGDateTimeStyle::ISO, PGDateOrder::MDY);
294 let expected = "2021-09-01 12:34:56.789012";
295 let mut out = bytes::BytesMut::new();
296 let is_null = styling_datetime
297 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
298 .unwrap();
299 assert!(matches!(is_null, IsNull::No));
300 assert_eq!(out, expected.as_bytes());
301 }
302
303 {
304 let styling_datetime = StylingDateTime(input, PGDateTimeStyle::ISO, PGDateOrder::YMD);
305 let expected = "2021-09-01 12:34:56.789012";
306 let mut out = bytes::BytesMut::new();
307 let is_null = styling_datetime
308 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
309 .unwrap();
310 assert!(matches!(is_null, IsNull::No));
311 assert_eq!(out, expected.as_bytes());
312 }
313
314 {
315 let styling_datetime = StylingDateTime(input, PGDateTimeStyle::ISO, PGDateOrder::DMY);
316 let expected = "2021-09-01 12:34:56.789012";
317 let mut out = bytes::BytesMut::new();
318 let is_null = styling_datetime
319 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
320 .unwrap();
321 assert!(matches!(is_null, IsNull::No));
322 assert_eq!(out, expected.as_bytes());
323 }
324
325 {
326 let styling_datetime =
327 StylingDateTime(input, PGDateTimeStyle::German, PGDateOrder::MDY);
328 let expected = "01.09.2021 12:34:56.789012";
329 let mut out = bytes::BytesMut::new();
330 let is_null = styling_datetime
331 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
332 .unwrap();
333 assert!(matches!(is_null, IsNull::No));
334 assert_eq!(out, expected.as_bytes());
335 }
336
337 {
338 let styling_datetime =
339 StylingDateTime(input, PGDateTimeStyle::German, PGDateOrder::YMD);
340 let expected = "01.09.2021 12:34:56.789012";
341 let mut out = bytes::BytesMut::new();
342 let is_null = styling_datetime
343 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
344 .unwrap();
345 assert!(matches!(is_null, IsNull::No));
346 assert_eq!(out, expected.as_bytes());
347 }
348
349 {
350 let styling_datetime =
351 StylingDateTime(input, PGDateTimeStyle::German, PGDateOrder::DMY);
352 let expected = "01.09.2021 12:34:56.789012";
353 let mut out = bytes::BytesMut::new();
354 let is_null = styling_datetime
355 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
356 .unwrap();
357 assert!(matches!(is_null, IsNull::No));
358 assert_eq!(out, expected.as_bytes());
359 }
360
361 {
362 let styling_datetime =
363 StylingDateTime(input, PGDateTimeStyle::Postgres, PGDateOrder::MDY);
364 let expected = "Wed Sep 01 12:34:56.789012 2021";
365 let mut out = bytes::BytesMut::new();
366 let is_null = styling_datetime
367 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
368 .unwrap();
369 assert!(matches!(is_null, IsNull::No));
370 assert_eq!(out, expected.as_bytes());
371 }
372
373 {
374 let styling_datetime =
375 StylingDateTime(input, PGDateTimeStyle::Postgres, PGDateOrder::YMD);
376 let expected = "Wed Sep 01 12:34:56.789012 2021";
377 let mut out = bytes::BytesMut::new();
378 let is_null = styling_datetime
379 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
380 .unwrap();
381 assert!(matches!(is_null, IsNull::No));
382 assert_eq!(out, expected.as_bytes());
383 }
384
385 {
386 let styling_datetime =
387 StylingDateTime(input, PGDateTimeStyle::Postgres, PGDateOrder::DMY);
388 let expected = "Wed 01 Sep 12:34:56.789012 2021";
389 let mut out = bytes::BytesMut::new();
390 let is_null = styling_datetime
391 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
392 .unwrap();
393 assert!(matches!(is_null, IsNull::No));
394 assert_eq!(out, expected.as_bytes());
395 }
396
397 {
398 let styling_datetime = StylingDateTime(input, PGDateTimeStyle::SQL, PGDateOrder::MDY);
399 let expected = "09/01/2021 12:34:56.789012";
400 let mut out = bytes::BytesMut::new();
401 let is_null = styling_datetime
402 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
403 .unwrap();
404 assert!(matches!(is_null, IsNull::No));
405 assert_eq!(out, expected.as_bytes());
406 }
407
408 {
409 let styling_datetime = StylingDateTime(input, PGDateTimeStyle::SQL, PGDateOrder::YMD);
410 let expected = "09/01/2021 12:34:56.789012";
411 let mut out = bytes::BytesMut::new();
412 let is_null = styling_datetime
413 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
414 .unwrap();
415 assert!(matches!(is_null, IsNull::No));
416 assert_eq!(out, expected.as_bytes());
417 }
418
419 {
420 let styling_datetime = StylingDateTime(input, PGDateTimeStyle::SQL, PGDateOrder::DMY);
421 let expected = "01/09/2021 12:34:56.789012";
422 let mut out = bytes::BytesMut::new();
423 let is_null = styling_datetime
424 .to_sql_text(&Type::TIMESTAMP, &mut out, &FormatOptions::default())
425 .unwrap();
426 assert!(matches!(is_null, IsNull::No));
427 assert_eq!(out, expected.as_bytes());
428 }
429 }
430}