1use crate::{error::*, SelectGetableValue, SelectorRaw, Statement};
2use std::fmt;
3
4#[cfg(any(feature = "mock", feature = "proxy"))]
5use crate::debug_print;
6
7#[cfg(feature = "sqlx-dep")]
8use crate::driver::*;
9#[cfg(feature = "sqlx-dep")]
10use sqlx::Row;
11
12#[derive(Debug)]
14pub struct QueryResult {
15 pub(crate) row: QueryResultRow,
16}
17
18#[allow(clippy::enum_variant_names)]
19pub(crate) enum QueryResultRow {
20 #[cfg(feature = "sqlx-mysql")]
21 SqlxMySql(sqlx::mysql::MySqlRow),
22 #[cfg(feature = "sqlx-postgres")]
23 SqlxPostgres(sqlx::postgres::PgRow),
24 #[cfg(feature = "sqlx-sqlite")]
25 SqlxSqlite(sqlx::sqlite::SqliteRow),
26 #[cfg(feature = "mock")]
27 Mock(crate::MockRow),
28 #[cfg(feature = "proxy")]
29 Proxy(crate::ProxyRow),
30}
31
32pub trait TryGetable: Sized {
34 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError>;
36
37 fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError> {
39 if pre.is_empty() {
40 Self::try_get_by(res, col)
41 } else {
42 Self::try_get_by(res, format!("{pre}{col}").as_str())
43 }
44 }
45
46 fn try_get_by_index(res: &QueryResult, index: usize) -> Result<Self, TryGetError> {
48 Self::try_get_by(res, index)
49 }
50}
51
52#[derive(Debug)]
54pub enum TryGetError {
55 DbErr(DbErr),
57 Null(String),
59}
60
61impl From<TryGetError> for DbErr {
62 fn from(e: TryGetError) -> DbErr {
63 match e {
64 TryGetError::DbErr(e) => e,
65 TryGetError::Null(s) => {
66 type_err(format!("A null value was encountered while decoding {s}"))
67 }
68 }
69 }
70}
71
72impl From<DbErr> for TryGetError {
73 fn from(e: DbErr) -> TryGetError {
74 Self::DbErr(e)
75 }
76}
77
78impl QueryResult {
81 pub fn try_get_by<T, I>(&self, index: I) -> Result<T, DbErr>
83 where
84 T: TryGetable,
85 I: ColIdx,
86 {
87 Ok(T::try_get_by(self, index)?)
88 }
89
90 pub fn try_get<T>(&self, pre: &str, col: &str) -> Result<T, DbErr>
92 where
93 T: TryGetable,
94 {
95 Ok(T::try_get(self, pre, col)?)
96 }
97
98 pub fn try_get_by_index<T>(&self, idx: usize) -> Result<T, DbErr>
100 where
101 T: TryGetable,
102 {
103 Ok(T::try_get_by_index(self, idx)?)
104 }
105
106 pub fn try_get_many<T>(&self, pre: &str, cols: &[String]) -> Result<T, DbErr>
108 where
109 T: TryGetableMany,
110 {
111 Ok(T::try_get_many(self, pre, cols)?)
112 }
113
114 pub fn try_get_many_by_index<T>(&self) -> Result<T, DbErr>
116 where
117 T: TryGetableMany,
118 {
119 Ok(T::try_get_many_by_index(self)?)
120 }
121
122 pub fn column_names(&self) -> Vec<String> {
124 #[cfg(feature = "sqlx-dep")]
125 use sqlx::Column;
126
127 match &self.row {
128 #[cfg(feature = "sqlx-mysql")]
129 QueryResultRow::SqlxMySql(row) => {
130 row.columns().iter().map(|c| c.name().to_string()).collect()
131 }
132 #[cfg(feature = "sqlx-postgres")]
133 QueryResultRow::SqlxPostgres(row) => {
134 row.columns().iter().map(|c| c.name().to_string()).collect()
135 }
136 #[cfg(feature = "sqlx-sqlite")]
137 QueryResultRow::SqlxSqlite(row) => {
138 row.columns().iter().map(|c| c.name().to_string()).collect()
139 }
140 #[cfg(feature = "mock")]
141 QueryResultRow::Mock(row) => row
142 .clone()
143 .into_column_value_tuples()
144 .map(|(c, _)| c.to_string())
145 .collect(),
146 #[cfg(feature = "proxy")]
147 QueryResultRow::Proxy(row) => row
148 .clone()
149 .into_column_value_tuples()
150 .map(|(c, _)| c.to_string())
151 .collect(),
152 #[allow(unreachable_patterns)]
153 _ => unreachable!(),
154 }
155 }
156}
157
158#[allow(unused_variables)]
159impl fmt::Debug for QueryResultRow {
160 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161 match self {
162 #[cfg(feature = "sqlx-mysql")]
163 Self::SqlxMySql(row) => write!(f, "{row:?}"),
164 #[cfg(feature = "sqlx-postgres")]
165 Self::SqlxPostgres(_) => write!(f, "QueryResultRow::SqlxPostgres cannot be inspected"),
166 #[cfg(feature = "sqlx-sqlite")]
167 Self::SqlxSqlite(_) => write!(f, "QueryResultRow::SqlxSqlite cannot be inspected"),
168 #[cfg(feature = "mock")]
169 Self::Mock(row) => write!(f, "{row:?}"),
170 #[cfg(feature = "proxy")]
171 Self::Proxy(row) => write!(f, "{row:?}"),
172 #[allow(unreachable_patterns)]
173 _ => unreachable!(),
174 }
175 }
176}
177
178impl<T: TryGetable> TryGetable for Option<T> {
181 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
182 match T::try_get_by(res, index) {
183 Ok(v) => Ok(Some(v)),
184 Err(TryGetError::Null(_)) => Ok(None),
185 #[cfg(feature = "sqlx-dep")]
186 Err(TryGetError::DbErr(DbErr::Query(RuntimeErr::SqlxError(
187 sqlx::Error::ColumnNotFound(_),
188 )))) => Ok(None),
189 Err(e) => Err(e),
190 }
191 }
192}
193
194pub trait ColIdx: std::fmt::Debug + Copy {
196 #[cfg(feature = "sqlx-mysql")]
197 type SqlxMySqlIndex: sqlx::ColumnIndex<sqlx::mysql::MySqlRow>;
199 #[cfg(feature = "sqlx-postgres")]
200 type SqlxPostgresIndex: sqlx::ColumnIndex<sqlx::postgres::PgRow>;
202 #[cfg(feature = "sqlx-sqlite")]
203 type SqlxSqliteIndex: sqlx::ColumnIndex<sqlx::sqlite::SqliteRow>;
205
206 #[cfg(feature = "sqlx-mysql")]
207 fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex;
209 #[cfg(feature = "sqlx-postgres")]
210 fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex;
212 #[cfg(feature = "sqlx-sqlite")]
213 fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex;
215
216 fn as_str(&self) -> Option<&str>;
218 fn as_usize(&self) -> Option<&usize>;
220}
221
222impl ColIdx for &str {
223 #[cfg(feature = "sqlx-mysql")]
224 type SqlxMySqlIndex = Self;
225 #[cfg(feature = "sqlx-postgres")]
226 type SqlxPostgresIndex = Self;
227 #[cfg(feature = "sqlx-sqlite")]
228 type SqlxSqliteIndex = Self;
229
230 #[cfg(feature = "sqlx-mysql")]
231 #[inline]
232 fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex {
233 self
234 }
235 #[cfg(feature = "sqlx-postgres")]
236 #[inline]
237 fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex {
238 self
239 }
240 #[cfg(feature = "sqlx-sqlite")]
241 #[inline]
242 fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex {
243 self
244 }
245
246 #[inline]
247 fn as_str(&self) -> Option<&str> {
248 Some(self)
249 }
250 #[inline]
251 fn as_usize(&self) -> Option<&usize> {
252 None
253 }
254}
255
256impl ColIdx for usize {
257 #[cfg(feature = "sqlx-mysql")]
258 type SqlxMySqlIndex = Self;
259 #[cfg(feature = "sqlx-postgres")]
260 type SqlxPostgresIndex = Self;
261 #[cfg(feature = "sqlx-sqlite")]
262 type SqlxSqliteIndex = Self;
263
264 #[cfg(feature = "sqlx-mysql")]
265 #[inline]
266 fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex {
267 *self
268 }
269 #[cfg(feature = "sqlx-postgres")]
270 #[inline]
271 fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex {
272 *self
273 }
274 #[cfg(feature = "sqlx-sqlite")]
275 #[inline]
276 fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex {
277 *self
278 }
279
280 #[inline]
281 fn as_str(&self) -> Option<&str> {
282 None
283 }
284 #[inline]
285 fn as_usize(&self) -> Option<&usize> {
286 Some(self)
287 }
288}
289
290macro_rules! try_getable_all {
291 ( $type: ty ) => {
292 impl TryGetable for $type {
293 #[allow(unused_variables)]
294 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
295 match &res.row {
296 #[cfg(feature = "sqlx-mysql")]
297 QueryResultRow::SqlxMySql(row) => row
298 .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
299 .map_err(|e| sqlx_error_to_query_err(e).into())
300 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
301 #[cfg(feature = "sqlx-postgres")]
302 QueryResultRow::SqlxPostgres(row) => row
303 .try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
304 .map_err(|e| sqlx_error_to_query_err(e).into())
305 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
306 #[cfg(feature = "sqlx-sqlite")]
307 QueryResultRow::SqlxSqlite(row) => row
308 .try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
309 .map_err(|e| sqlx_error_to_query_err(e).into())
310 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
311 #[cfg(feature = "mock")]
312 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
313 debug_print!("{:#?}", e.to_string());
314 err_null_idx_col(idx)
315 }),
316 #[cfg(feature = "proxy")]
317 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
318 debug_print!("{:#?}", e.to_string());
319 err_null_idx_col(idx)
320 }),
321 #[allow(unreachable_patterns)]
322 _ => unreachable!(),
323 }
324 }
325 }
326 };
327}
328
329macro_rules! try_getable_unsigned {
330 ( $type: ty ) => {
331 impl TryGetable for $type {
332 #[allow(unused_variables)]
333 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
334 match &res.row {
335 #[cfg(feature = "sqlx-mysql")]
336 QueryResultRow::SqlxMySql(row) => row
337 .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
338 .map_err(|e| sqlx_error_to_query_err(e).into())
339 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
340 #[cfg(feature = "sqlx-postgres")]
341 QueryResultRow::SqlxPostgres(_) => Err(type_err(format!(
342 "{} unsupported by sqlx-postgres",
343 stringify!($type)
344 ))
345 .into()),
346 #[cfg(feature = "sqlx-sqlite")]
347 QueryResultRow::SqlxSqlite(row) => row
348 .try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
349 .map_err(|e| sqlx_error_to_query_err(e).into())
350 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
351 #[cfg(feature = "mock")]
352 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
353 debug_print!("{:#?}", e.to_string());
354 err_null_idx_col(idx)
355 }),
356 #[cfg(feature = "proxy")]
357 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
358 debug_print!("{:#?}", e.to_string());
359 err_null_idx_col(idx)
360 }),
361 #[allow(unreachable_patterns)]
362 _ => unreachable!(),
363 }
364 }
365 }
366 };
367}
368
369macro_rules! try_getable_mysql {
370 ( $type: ty ) => {
371 impl TryGetable for $type {
372 #[allow(unused_variables)]
373 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
374 match &res.row {
375 #[cfg(feature = "sqlx-mysql")]
376 QueryResultRow::SqlxMySql(row) => row
377 .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
378 .map_err(|e| sqlx_error_to_query_err(e).into())
379 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
380 #[cfg(feature = "sqlx-postgres")]
381 QueryResultRow::SqlxPostgres(_) => Err(type_err(format!(
382 "{} unsupported by sqlx-postgres",
383 stringify!($type)
384 ))
385 .into()),
386 #[cfg(feature = "sqlx-sqlite")]
387 QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
388 "{} unsupported by sqlx-sqlite",
389 stringify!($type)
390 ))
391 .into()),
392 #[cfg(feature = "mock")]
393 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
394 debug_print!("{:#?}", e.to_string());
395 err_null_idx_col(idx)
396 }),
397 #[cfg(feature = "proxy")]
398 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
399 debug_print!("{:#?}", e.to_string());
400 err_null_idx_col(idx)
401 }),
402 #[allow(unreachable_patterns)]
403 _ => unreachable!(),
404 }
405 }
406 }
407 };
408}
409
410#[allow(unused_macros)]
411macro_rules! try_getable_date_time {
412 ( $type: ty ) => {
413 impl TryGetable for $type {
414 #[allow(unused_variables)]
415 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
416 match &res.row {
417 #[cfg(feature = "sqlx-mysql")]
418 QueryResultRow::SqlxMySql(row) => {
419 use chrono::{DateTime, Utc};
420 row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_mysql_index())
421 .map_err(|e| sqlx_error_to_query_err(e).into())
422 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
423 .map(|v| v.into())
424 }
425 #[cfg(feature = "sqlx-postgres")]
426 QueryResultRow::SqlxPostgres(row) => row
427 .try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
428 .map_err(|e| sqlx_error_to_query_err(e).into())
429 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
430 #[cfg(feature = "sqlx-sqlite")]
431 QueryResultRow::SqlxSqlite(row) => {
432 use chrono::{DateTime, Utc};
433 row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_sqlite_index())
434 .map_err(|e| sqlx_error_to_query_err(e).into())
435 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
436 .map(|v| v.into())
437 }
438 #[cfg(feature = "mock")]
439 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
440 debug_print!("{:#?}", e.to_string());
441 err_null_idx_col(idx)
442 }),
443 #[cfg(feature = "proxy")]
444 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
445 debug_print!("{:#?}", e.to_string());
446 err_null_idx_col(idx)
447 }),
448 #[allow(unreachable_patterns)]
449 _ => unreachable!(),
450 }
451 }
452 }
453 };
454}
455
456try_getable_all!(bool);
457try_getable_all!(i8);
458try_getable_all!(i16);
459try_getable_all!(i32);
460try_getable_all!(i64);
461try_getable_unsigned!(u8);
462try_getable_unsigned!(u16);
463try_getable_mysql!(u64);
464try_getable_all!(f32);
465try_getable_all!(f64);
466try_getable_all!(Vec<u8>);
467
468#[cfg(feature = "with-json")]
469try_getable_all!(serde_json::Value);
470
471#[cfg(feature = "with-chrono")]
472try_getable_all!(chrono::NaiveDate);
473
474#[cfg(feature = "with-chrono")]
475try_getable_all!(chrono::NaiveTime);
476
477#[cfg(feature = "with-chrono")]
478try_getable_all!(chrono::NaiveDateTime);
479
480#[cfg(feature = "with-chrono")]
481try_getable_date_time!(chrono::DateTime<chrono::FixedOffset>);
482
483#[cfg(feature = "with-chrono")]
484try_getable_all!(chrono::DateTime<chrono::Utc>);
485
486#[cfg(feature = "with-chrono")]
487try_getable_all!(chrono::DateTime<chrono::Local>);
488
489#[cfg(feature = "with-time")]
490try_getable_all!(time::Date);
491
492#[cfg(feature = "with-time")]
493try_getable_all!(time::Time);
494
495#[cfg(feature = "with-time")]
496try_getable_all!(time::PrimitiveDateTime);
497
498#[cfg(feature = "with-time")]
499try_getable_all!(time::OffsetDateTime);
500
501#[cfg(feature = "with-rust_decimal")]
502use rust_decimal::Decimal;
503
504#[cfg(feature = "with-rust_decimal")]
505impl TryGetable for Decimal {
506 #[allow(unused_variables)]
507 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
508 match &res.row {
509 #[cfg(feature = "sqlx-mysql")]
510 QueryResultRow::SqlxMySql(row) => row
511 .try_get::<Option<Decimal>, _>(idx.as_sqlx_mysql_index())
512 .map_err(|e| sqlx_error_to_query_err(e).into())
513 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
514 #[cfg(feature = "sqlx-postgres")]
515 QueryResultRow::SqlxPostgres(row) => row
516 .try_get::<Option<Decimal>, _>(idx.as_sqlx_postgres_index())
517 .map_err(|e| sqlx_error_to_query_err(e).into())
518 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
519 #[cfg(feature = "sqlx-sqlite")]
520 QueryResultRow::SqlxSqlite(row) => {
521 let val: Option<f64> = row
522 .try_get(idx.as_sqlx_sqlite_index())
523 .map_err(sqlx_error_to_query_err)?;
524 match val {
525 Some(v) => Decimal::try_from(v).map_err(|e| {
526 DbErr::TryIntoErr {
527 from: "f64",
528 into: "Decimal",
529 source: Box::new(e),
530 }
531 .into()
532 }),
533 None => Err(err_null_idx_col(idx)),
534 }
535 }
536 #[cfg(feature = "mock")]
537 #[allow(unused_variables)]
538 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
539 debug_print!("{:#?}", e.to_string());
540 err_null_idx_col(idx)
541 }),
542 #[cfg(feature = "proxy")]
543 #[allow(unused_variables)]
544 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
545 debug_print!("{:#?}", e.to_string());
546 err_null_idx_col(idx)
547 }),
548 #[allow(unreachable_patterns)]
549 _ => unreachable!(),
550 }
551 }
552}
553
554#[cfg(feature = "with-bigdecimal")]
555use bigdecimal::BigDecimal;
556
557#[cfg(feature = "with-bigdecimal")]
558impl TryGetable for BigDecimal {
559 #[allow(unused_variables)]
560 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
561 match &res.row {
562 #[cfg(feature = "sqlx-mysql")]
563 QueryResultRow::SqlxMySql(row) => row
564 .try_get::<Option<BigDecimal>, _>(idx.as_sqlx_mysql_index())
565 .map_err(|e| sqlx_error_to_query_err(e).into())
566 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
567 #[cfg(feature = "sqlx-postgres")]
568 QueryResultRow::SqlxPostgres(row) => row
569 .try_get::<Option<BigDecimal>, _>(idx.as_sqlx_postgres_index())
570 .map_err(|e| sqlx_error_to_query_err(e).into())
571 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
572 #[cfg(feature = "sqlx-sqlite")]
573 QueryResultRow::SqlxSqlite(row) => {
574 let val: Option<f64> = row
575 .try_get(idx.as_sqlx_sqlite_index())
576 .map_err(sqlx_error_to_query_err)?;
577 match val {
578 Some(v) => BigDecimal::try_from(v).map_err(|e| {
579 DbErr::TryIntoErr {
580 from: "f64",
581 into: "BigDecimal",
582 source: Box::new(e),
583 }
584 .into()
585 }),
586 None => Err(err_null_idx_col(idx)),
587 }
588 }
589 #[cfg(feature = "mock")]
590 #[allow(unused_variables)]
591 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
592 debug_print!("{:#?}", e.to_string());
593 err_null_idx_col(idx)
594 }),
595 #[cfg(feature = "proxy")]
596 #[allow(unused_variables)]
597 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
598 debug_print!("{:#?}", e.to_string());
599 err_null_idx_col(idx)
600 }),
601 #[allow(unreachable_patterns)]
602 _ => unreachable!(),
603 }
604 }
605}
606
607#[allow(unused_macros)]
608macro_rules! try_getable_uuid {
609 ( $type: ty, $conversion_fn: expr ) => {
610 #[allow(unused_variables, unreachable_code)]
611 impl TryGetable for $type {
612 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
613 let res: Result<uuid::Uuid, TryGetError> = match &res.row {
614 #[cfg(feature = "sqlx-mysql")]
615 QueryResultRow::SqlxMySql(row) => row
616 .try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_mysql_index())
617 .map_err(|e| sqlx_error_to_query_err(e).into())
618 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
619 #[cfg(feature = "sqlx-postgres")]
620 QueryResultRow::SqlxPostgres(row) => row
621 .try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_postgres_index())
622 .map_err(|e| sqlx_error_to_query_err(e).into())
623 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
624 #[cfg(feature = "sqlx-sqlite")]
625 QueryResultRow::SqlxSqlite(row) => row
626 .try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_sqlite_index())
627 .map_err(|e| sqlx_error_to_query_err(e).into())
628 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
629 #[cfg(feature = "mock")]
630 #[allow(unused_variables)]
631 QueryResultRow::Mock(row) => row.try_get::<uuid::Uuid, _>(idx).map_err(|e| {
632 debug_print!("{:#?}", e.to_string());
633 err_null_idx_col(idx)
634 }),
635 #[cfg(feature = "proxy")]
636 #[allow(unused_variables)]
637 QueryResultRow::Proxy(row) => row.try_get::<uuid::Uuid, _>(idx).map_err(|e| {
638 debug_print!("{:#?}", e.to_string());
639 err_null_idx_col(idx)
640 }),
641 #[allow(unreachable_patterns)]
642 _ => unreachable!(),
643 };
644 res.map($conversion_fn)
645 }
646 }
647 };
648}
649
650#[cfg(feature = "with-uuid")]
651try_getable_uuid!(uuid::Uuid, Into::into);
652
653#[cfg(feature = "with-uuid")]
654try_getable_uuid!(uuid::fmt::Braced, uuid::Uuid::braced);
655
656#[cfg(feature = "with-uuid")]
657try_getable_uuid!(uuid::fmt::Hyphenated, uuid::Uuid::hyphenated);
658
659#[cfg(feature = "with-uuid")]
660try_getable_uuid!(uuid::fmt::Simple, uuid::Uuid::simple);
661
662#[cfg(feature = "with-uuid")]
663try_getable_uuid!(uuid::fmt::Urn, uuid::Uuid::urn);
664
665impl TryGetable for u32 {
666 #[allow(unused_variables)]
667 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
668 match &res.row {
669 #[cfg(feature = "sqlx-mysql")]
670 QueryResultRow::SqlxMySql(row) => row
671 .try_get::<Option<u32>, _>(idx.as_sqlx_mysql_index())
672 .map_err(|e| sqlx_error_to_query_err(e).into())
673 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
674 #[cfg(feature = "sqlx-postgres")]
675 QueryResultRow::SqlxPostgres(row) => {
676 use sqlx::postgres::types::Oid;
677 row.try_get::<Option<Oid>, _>(idx.as_sqlx_postgres_index())
680 .map_err(|e| sqlx_error_to_query_err(e).into())
681 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
682 .map(|oid| oid.0)
683 }
684 #[cfg(feature = "sqlx-sqlite")]
685 QueryResultRow::SqlxSqlite(row) => row
686 .try_get::<Option<u32>, _>(idx.as_sqlx_sqlite_index())
687 .map_err(|e| sqlx_error_to_query_err(e).into())
688 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
689 #[cfg(feature = "mock")]
690 #[allow(unused_variables)]
691 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
692 debug_print!("{:#?}", e.to_string());
693 err_null_idx_col(idx)
694 }),
695 #[cfg(feature = "proxy")]
696 #[allow(unused_variables)]
697 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
698 debug_print!("{:#?}", e.to_string());
699 err_null_idx_col(idx)
700 }),
701 #[allow(unreachable_patterns)]
702 _ => unreachable!(),
703 }
704 }
705}
706
707impl TryGetable for String {
708 #[allow(unused_variables)]
709 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
710 match &res.row {
711 #[cfg(feature = "sqlx-mysql")]
712 QueryResultRow::SqlxMySql(row) => row
713 .try_get::<Option<Vec<u8>>, _>(idx.as_sqlx_mysql_index())
714 .map_err(|e| sqlx_error_to_query_err(e).into())
715 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
716 .map(|bytes| {
717 String::from_utf8(bytes).map_err(|e| {
718 DbErr::TryIntoErr {
719 from: "Vec<u8>",
720 into: "String",
721 source: Box::new(e),
722 }
723 .into()
724 })
725 })?,
726 #[cfg(feature = "sqlx-postgres")]
727 QueryResultRow::SqlxPostgres(row) => row
728 .try_get::<Option<String>, _>(idx.as_sqlx_postgres_index())
729 .map_err(|e| sqlx_error_to_query_err(e).into())
730 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
731 #[cfg(feature = "sqlx-sqlite")]
732 QueryResultRow::SqlxSqlite(row) => row
733 .try_get::<Option<String>, _>(idx.as_sqlx_sqlite_index())
734 .map_err(|e| sqlx_error_to_query_err(e).into())
735 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
736 #[cfg(feature = "mock")]
737 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
738 debug_print!("{:#?}", e.to_string());
739 err_null_idx_col(idx)
740 }),
741 #[cfg(feature = "proxy")]
742 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
743 debug_print!("{:#?}", e.to_string());
744 err_null_idx_col(idx)
745 }),
746 #[allow(unreachable_patterns)]
747 _ => unreachable!(),
748 }
749 }
750}
751
752#[allow(dead_code)]
753fn err_null_idx_col<I: ColIdx>(idx: I) -> TryGetError {
754 TryGetError::Null(format!("{idx:?}"))
755}
756
757#[cfg(feature = "postgres-array")]
758mod postgres_array {
759 use super::*;
760
761 #[allow(unused_macros)]
762 macro_rules! try_getable_postgres_array {
763 ( $type: ty ) => {
764 #[allow(unused_variables)]
765 impl TryGetable for Vec<$type> {
766 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
767 match &res.row {
768 #[cfg(feature = "sqlx-mysql")]
769 QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
770 "{} unsupported by sqlx-mysql",
771 stringify!($type)
772 ))
773 .into()),
774 #[cfg(feature = "sqlx-postgres")]
775 QueryResultRow::SqlxPostgres(row) => row
776 .try_get::<Option<Vec<$type>>, _>(idx.as_sqlx_postgres_index())
777 .map_err(|e| sqlx_error_to_query_err(e).into())
778 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
779 #[cfg(feature = "sqlx-sqlite")]
780 QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
781 "{} unsupported by sqlx-sqlite",
782 stringify!($type)
783 ))
784 .into()),
785 #[cfg(feature = "mock")]
786 #[allow(unused_variables)]
787 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
788 debug_print!("{:#?}", e.to_string());
789 err_null_idx_col(idx)
790 }),
791 #[cfg(feature = "proxy")]
792 #[allow(unused_variables)]
793 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
794 debug_print!("{:#?}", e.to_string());
795 err_null_idx_col(idx)
796 }),
797 #[allow(unreachable_patterns)]
798 _ => unreachable!(),
799 }
800 }
801 }
802 };
803 }
804
805 try_getable_postgres_array!(bool);
806 try_getable_postgres_array!(i8);
807 try_getable_postgres_array!(i16);
808 try_getable_postgres_array!(i32);
809 try_getable_postgres_array!(i64);
810 try_getable_postgres_array!(f32);
811 try_getable_postgres_array!(f64);
812 try_getable_postgres_array!(String);
813
814 #[cfg(feature = "with-json")]
815 try_getable_postgres_array!(serde_json::Value);
816
817 #[cfg(feature = "with-chrono")]
818 try_getable_postgres_array!(chrono::NaiveDate);
819
820 #[cfg(feature = "with-chrono")]
821 try_getable_postgres_array!(chrono::NaiveTime);
822
823 #[cfg(feature = "with-chrono")]
824 try_getable_postgres_array!(chrono::NaiveDateTime);
825
826 #[cfg(feature = "with-chrono")]
827 try_getable_postgres_array!(chrono::DateTime<chrono::FixedOffset>);
828
829 #[cfg(feature = "with-chrono")]
830 try_getable_postgres_array!(chrono::DateTime<chrono::Utc>);
831
832 #[cfg(feature = "with-chrono")]
833 try_getable_postgres_array!(chrono::DateTime<chrono::Local>);
834
835 #[cfg(feature = "with-time")]
836 try_getable_postgres_array!(time::Date);
837
838 #[cfg(feature = "with-time")]
839 try_getable_postgres_array!(time::Time);
840
841 #[cfg(feature = "with-time")]
842 try_getable_postgres_array!(time::PrimitiveDateTime);
843
844 #[cfg(feature = "with-time")]
845 try_getable_postgres_array!(time::OffsetDateTime);
846
847 #[cfg(feature = "with-rust_decimal")]
848 try_getable_postgres_array!(rust_decimal::Decimal);
849
850 #[cfg(feature = "with-bigdecimal")]
851 try_getable_postgres_array!(bigdecimal::BigDecimal);
852
853 #[allow(unused_macros)]
854 macro_rules! try_getable_postgres_array_uuid {
855 ( $type: ty, $conversion_fn: expr ) => {
856 #[allow(unused_variables, unreachable_code)]
857 impl TryGetable for Vec<$type> {
858 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
859 let res: Result<Vec<uuid::Uuid>, TryGetError> = match &res.row {
860 #[cfg(feature = "sqlx-mysql")]
861 QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
862 "{} unsupported by sqlx-mysql",
863 stringify!($type)
864 ))
865 .into()),
866 #[cfg(feature = "sqlx-postgres")]
867 QueryResultRow::SqlxPostgres(row) => row
868 .try_get::<Option<Vec<uuid::Uuid>>, _>(idx.as_sqlx_postgres_index())
869 .map_err(|e| sqlx_error_to_query_err(e).into())
870 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
871 #[cfg(feature = "sqlx-sqlite")]
872 QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
873 "{} unsupported by sqlx-sqlite",
874 stringify!($type)
875 ))
876 .into()),
877 #[cfg(feature = "mock")]
878 QueryResultRow::Mock(row) => {
879 row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
880 debug_print!("{:#?}", e.to_string());
881 err_null_idx_col(idx)
882 })
883 }
884 #[cfg(feature = "proxy")]
885 QueryResultRow::Proxy(row) => {
886 row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
887 debug_print!("{:#?}", e.to_string());
888 err_null_idx_col(idx)
889 })
890 }
891 #[allow(unreachable_patterns)]
892 _ => unreachable!(),
893 };
894 res.map(|vec| vec.into_iter().map($conversion_fn).collect())
895 }
896 }
897 };
898 }
899
900 #[cfg(feature = "with-uuid")]
901 try_getable_postgres_array_uuid!(uuid::Uuid, Into::into);
902
903 #[cfg(feature = "with-uuid")]
904 try_getable_postgres_array_uuid!(uuid::fmt::Braced, uuid::Uuid::braced);
905
906 #[cfg(feature = "with-uuid")]
907 try_getable_postgres_array_uuid!(uuid::fmt::Hyphenated, uuid::Uuid::hyphenated);
908
909 #[cfg(feature = "with-uuid")]
910 try_getable_postgres_array_uuid!(uuid::fmt::Simple, uuid::Uuid::simple);
911
912 #[cfg(feature = "with-uuid")]
913 try_getable_postgres_array_uuid!(uuid::fmt::Urn, uuid::Uuid::urn);
914
915 impl TryGetable for Vec<u32> {
916 #[allow(unused_variables)]
917 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
918 match &res.row {
919 #[cfg(feature = "sqlx-mysql")]
920 QueryResultRow::SqlxMySql(_) => {
921 Err(type_err(format!("{} unsupported by sqlx-mysql", stringify!($type))).into())
922 }
923 #[cfg(feature = "sqlx-postgres")]
924 QueryResultRow::SqlxPostgres(row) => {
925 use sqlx::postgres::types::Oid;
926 row.try_get::<Option<Vec<Oid>>, _>(idx.as_sqlx_postgres_index())
929 .map_err(|e| sqlx_error_to_query_err(e).into())
930 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
931 .map(|oids| oids.into_iter().map(|oid| oid.0).collect())
932 }
933 #[cfg(feature = "sqlx-sqlite")]
934 QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
935 "{} unsupported by sqlx-sqlite",
936 stringify!($type)
937 ))
938 .into()),
939 #[cfg(feature = "mock")]
940 #[allow(unused_variables)]
941 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
942 debug_print!("{:#?}", e.to_string());
943 err_null_idx_col(idx)
944 }),
945 #[cfg(feature = "proxy")]
946 #[allow(unused_variables)]
947 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
948 debug_print!("{:#?}", e.to_string());
949 err_null_idx_col(idx)
950 }),
951 #[allow(unreachable_patterns)]
952 _ => unreachable!(),
953 }
954 }
955 }
956}
957
958pub trait TryGetableMany: Sized {
962 fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
964
965 fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError>;
967
968 fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
1026 where
1027 C: strum::IntoEnumIterator + sea_query::Iden,
1028 {
1029 SelectorRaw::<SelectGetableValue<Self, C>>::with_columns(stmt)
1030 }
1031}
1032
1033impl<T> TryGetableMany for T
1034where
1035 T: TryGetable,
1036{
1037 fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1038 try_get_many_with_slice_len_of(1, cols)?;
1039 T::try_get(res, pre, &cols[0])
1040 }
1041
1042 fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1043 T::try_get_by_index(res, 0)
1044 }
1045}
1046
1047impl<T> TryGetableMany for (T,)
1048where
1049 T: TryGetableMany,
1050{
1051 fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1052 T::try_get_many(res, pre, cols).map(|r| (r,))
1053 }
1054
1055 fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1056 T::try_get_many_by_index(res).map(|r| (r,))
1057 }
1058}
1059
1060macro_rules! impl_try_get_many {
1061 ( $LEN:expr, $($T:ident : $N:expr),+ $(,)? ) => {
1062 impl< $($T),+ > TryGetableMany for ( $($T),+ )
1063 where
1064 $($T: TryGetable),+
1065 {
1066 fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1067 try_get_many_with_slice_len_of($LEN, cols)?;
1068 Ok((
1069 $($T::try_get(res, pre, &cols[$N])?),+
1070 ))
1071 }
1072
1073 fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1074 Ok((
1075 $($T::try_get_by_index(res, $N)?),+
1076 ))
1077 }
1078 }
1079 };
1080}
1081
1082#[rustfmt::skip]
1083mod impl_try_get_many {
1084 use super::*;
1085
1086 impl_try_get_many!( 2, T0:0, T1:1);
1087 impl_try_get_many!( 3, T0:0, T1:1, T2:2);
1088 impl_try_get_many!( 4, T0:0, T1:1, T2:2, T3:3);
1089 impl_try_get_many!( 5, T0:0, T1:1, T2:2, T3:3, T4:4);
1090 impl_try_get_many!( 6, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
1091 impl_try_get_many!( 7, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
1092 impl_try_get_many!( 8, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
1093 impl_try_get_many!( 9, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
1094 impl_try_get_many!(10, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9);
1095 impl_try_get_many!(11, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10);
1096 impl_try_get_many!(12, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10, T11:11);
1097}
1098
1099fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
1100 if cols.len() < len {
1101 Err(type_err(format!(
1102 "Expect {} column names supplied but got slice of length {}",
1103 len,
1104 cols.len()
1105 ))
1106 .into())
1107 } else {
1108 Ok(())
1109 }
1110}
1111
1112pub trait TryGetableArray: Sized {
1118 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<Self>, TryGetError>;
1120}
1121
1122impl<T> TryGetable for Vec<T>
1123where
1124 T: TryGetableArray,
1125{
1126 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1127 T::try_get_by(res, index)
1128 }
1129}
1130
1131#[cfg(feature = "with-json")]
1135pub trait TryGetableFromJson: Sized
1136where
1137 for<'de> Self: serde::Deserialize<'de>,
1138{
1139 #[allow(unused_variables, unreachable_code)]
1141 fn try_get_from_json<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1142 match &res.row {
1143 #[cfg(feature = "sqlx-mysql")]
1144 QueryResultRow::SqlxMySql(row) => row
1145 .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_mysql_index())
1146 .map_err(|e| sqlx_error_to_query_err(e).into())
1147 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1148 #[cfg(feature = "sqlx-postgres")]
1149 QueryResultRow::SqlxPostgres(row) => row
1150 .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_postgres_index())
1151 .map_err(|e| sqlx_error_to_query_err(e).into())
1152 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1153 #[cfg(feature = "sqlx-sqlite")]
1154 QueryResultRow::SqlxSqlite(row) => row
1155 .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_sqlite_index())
1156 .map_err(|e| sqlx_error_to_query_err(e).into())
1157 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1158 #[cfg(feature = "mock")]
1159 QueryResultRow::Mock(row) => row
1160 .try_get::<serde_json::Value, I>(idx)
1161 .map_err(|e| {
1162 debug_print!("{:#?}", e.to_string());
1163 err_null_idx_col(idx)
1164 })
1165 .and_then(|json| serde_json::from_value(json).map_err(|e| json_err(e).into())),
1166 #[cfg(feature = "proxy")]
1167 QueryResultRow::Proxy(row) => row
1168 .try_get::<serde_json::Value, I>(idx)
1169 .map_err(|e| {
1170 debug_print!("{:#?}", e.to_string());
1171 err_null_idx_col(idx)
1172 })
1173 .and_then(|json| serde_json::from_value(json).map_err(|e| json_err(e).into())),
1174 #[allow(unreachable_patterns)]
1175 _ => unreachable!(),
1176 }
1177 }
1178
1179 fn from_json_vec(value: serde_json::Value) -> Result<Vec<Self>, TryGetError> {
1181 match value {
1182 serde_json::Value::Array(values) => {
1183 let mut res = Vec::new();
1184 for item in values {
1185 res.push(serde_json::from_value(item).map_err(json_err)?);
1186 }
1187 Ok(res)
1188 }
1189 _ => Err(TryGetError::DbErr(DbErr::Json(
1190 "Value is not an Array".to_owned(),
1191 ))),
1192 }
1193 }
1194}
1195
1196#[cfg(feature = "with-json")]
1197impl<T> TryGetable for T
1198where
1199 T: TryGetableFromJson,
1200{
1201 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1202 T::try_get_from_json(res, index)
1203 }
1204}
1205
1206#[cfg(feature = "with-json")]
1207impl<T> TryGetableArray for T
1208where
1209 T: TryGetableFromJson,
1210{
1211 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<T>, TryGetError> {
1212 T::from_json_vec(serde_json::Value::try_get_by(res, index)?)
1213 }
1214}
1215
1216pub trait TryFromU64: Sized {
1219 fn try_from_u64(n: u64) -> Result<Self, DbErr>;
1221}
1222
1223macro_rules! try_from_u64_err {
1224 ( $type: ty ) => {
1225 impl TryFromU64 for $type {
1226 fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1227 Err(DbErr::ConvertFromU64(stringify!($type)))
1228 }
1229 }
1230 };
1231
1232 ( $($gen_type: ident),* ) => {
1233 impl<$( $gen_type, )*> TryFromU64 for ($( $gen_type, )*)
1234 where
1235 $( $gen_type: TryFromU64, )*
1236 {
1237 fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1238 Err(DbErr::ConvertFromU64(stringify!($($gen_type,)*)))
1239 }
1240 }
1241 };
1242}
1243
1244#[rustfmt::skip]
1245mod try_from_u64_err {
1246 use super::*;
1247
1248 try_from_u64_err!(T0, T1);
1249 try_from_u64_err!(T0, T1, T2);
1250 try_from_u64_err!(T0, T1, T2, T3);
1251 try_from_u64_err!(T0, T1, T2, T3, T4);
1252 try_from_u64_err!(T0, T1, T2, T3, T4, T5);
1253 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6);
1254 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7);
1255 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
1256 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
1257 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
1258 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
1259}
1260
1261macro_rules! try_from_u64_numeric {
1262 ( $type: ty ) => {
1263 impl TryFromU64 for $type {
1264 fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1265 use std::convert::TryInto;
1266 n.try_into().map_err(|e| DbErr::TryIntoErr {
1267 from: stringify!(u64),
1268 into: stringify!($type),
1269 source: Box::new(e),
1270 })
1271 }
1272 }
1273 };
1274}
1275
1276try_from_u64_numeric!(i8);
1277try_from_u64_numeric!(i16);
1278try_from_u64_numeric!(i32);
1279try_from_u64_numeric!(i64);
1280try_from_u64_numeric!(u8);
1281try_from_u64_numeric!(u16);
1282try_from_u64_numeric!(u32);
1283try_from_u64_numeric!(u64);
1284
1285macro_rules! try_from_u64_string {
1286 ( $type: ty ) => {
1287 impl TryFromU64 for $type {
1288 fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1289 Ok(n.to_string())
1290 }
1291 }
1292 };
1293}
1294
1295try_from_u64_string!(String);
1296
1297try_from_u64_err!(bool);
1298try_from_u64_err!(f32);
1299try_from_u64_err!(f64);
1300try_from_u64_err!(Vec<u8>);
1301
1302#[cfg(feature = "with-json")]
1303try_from_u64_err!(serde_json::Value);
1304
1305#[cfg(feature = "with-chrono")]
1306try_from_u64_err!(chrono::NaiveDate);
1307
1308#[cfg(feature = "with-chrono")]
1309try_from_u64_err!(chrono::NaiveTime);
1310
1311#[cfg(feature = "with-chrono")]
1312try_from_u64_err!(chrono::NaiveDateTime);
1313
1314#[cfg(feature = "with-chrono")]
1315try_from_u64_err!(chrono::DateTime<chrono::FixedOffset>);
1316
1317#[cfg(feature = "with-chrono")]
1318try_from_u64_err!(chrono::DateTime<chrono::Utc>);
1319
1320#[cfg(feature = "with-chrono")]
1321try_from_u64_err!(chrono::DateTime<chrono::Local>);
1322
1323#[cfg(feature = "with-time")]
1324try_from_u64_err!(time::Date);
1325
1326#[cfg(feature = "with-time")]
1327try_from_u64_err!(time::Time);
1328
1329#[cfg(feature = "with-time")]
1330try_from_u64_err!(time::PrimitiveDateTime);
1331
1332#[cfg(feature = "with-time")]
1333try_from_u64_err!(time::OffsetDateTime);
1334
1335#[cfg(feature = "with-rust_decimal")]
1336try_from_u64_err!(rust_decimal::Decimal);
1337
1338#[cfg(feature = "with-uuid")]
1339try_from_u64_err!(uuid::Uuid);
1340
1341#[cfg(test)]
1342mod tests {
1343 use std::collections::BTreeMap;
1344
1345 use sea_query::Value;
1346
1347 use super::*;
1348
1349 #[test]
1350 fn from_try_get_error() {
1351 let try_get_error = TryGetError::DbErr(DbErr::Query(RuntimeErr::Internal(
1353 "expected error message".to_owned(),
1354 )));
1355 assert_eq!(
1356 DbErr::from(try_get_error),
1357 DbErr::Query(RuntimeErr::Internal("expected error message".to_owned()))
1358 );
1359
1360 let try_get_error = TryGetError::Null("column".to_owned());
1362 let expected = "A null value was encountered while decoding column".to_owned();
1363 assert_eq!(DbErr::from(try_get_error), DbErr::Type(expected));
1364 }
1365
1366 #[test]
1367 fn build_with_query() {
1368 use sea_orm::{DbBackend, Statement};
1369 use sea_query::*;
1370
1371 let base_query = SelectStatement::new()
1372 .column(Alias::new("id"))
1373 .expr(1i32)
1374 .column(Alias::new("next"))
1375 .column(Alias::new("value"))
1376 .from(Alias::new("table"))
1377 .to_owned();
1378
1379 let cte_referencing = SelectStatement::new()
1380 .column(Alias::new("id"))
1381 .expr(Expr::col(Alias::new("depth")).add(1i32))
1382 .column(Alias::new("next"))
1383 .column(Alias::new("value"))
1384 .from(Alias::new("table"))
1385 .join(
1386 JoinType::InnerJoin,
1387 Alias::new("cte_traversal"),
1388 Expr::col((Alias::new("cte_traversal"), Alias::new("next")))
1389 .equals((Alias::new("table"), Alias::new("id"))),
1390 )
1391 .to_owned();
1392
1393 let common_table_expression = CommonTableExpression::new()
1394 .query(
1395 base_query
1396 .clone()
1397 .union(UnionType::All, cte_referencing)
1398 .to_owned(),
1399 )
1400 .columns([
1401 Alias::new("id"),
1402 Alias::new("depth"),
1403 Alias::new("next"),
1404 Alias::new("value"),
1405 ])
1406 .table_name(Alias::new("cte_traversal"))
1407 .to_owned();
1408
1409 let select = SelectStatement::new()
1410 .column(ColumnRef::Asterisk)
1411 .from(Alias::new("cte_traversal"))
1412 .to_owned();
1413
1414 let with_clause = WithClause::new()
1415 .recursive(true)
1416 .cte(common_table_expression)
1417 .cycle(Cycle::new_from_expr_set_using(
1418 SimpleExpr::Column(ColumnRef::Column(Alias::new("id").into_iden())),
1419 Alias::new("looped"),
1420 Alias::new("traversal_path"),
1421 ))
1422 .to_owned();
1423
1424 let with_query = select.with(with_clause).to_owned();
1425
1426 assert_eq!(
1427 DbBackend::MySql.build(&with_query),
1428 Statement::from_sql_and_values(
1429 DbBackend::MySql,
1430 r#"WITH RECURSIVE `cte_traversal` (`id`, `depth`, `next`, `value`) AS (SELECT `id`, ?, `next`, `value` FROM `table` UNION ALL (SELECT `id`, `depth` + ?, `next`, `value` FROM `table` INNER JOIN `cte_traversal` ON `cte_traversal`.`next` = `table`.`id`)) SELECT * FROM `cte_traversal`"#,
1431 [1.into(), 1.into()]
1432 )
1433 );
1434 }
1435
1436 #[test]
1437 fn column_names_from_query_result() {
1438 let mut values = BTreeMap::new();
1439 values.insert("id".to_string(), Value::Int(Some(1)));
1440 values.insert(
1441 "name".to_string(),
1442 Value::String(Some(Box::new("Abc".to_owned()))),
1443 );
1444 let query_result = QueryResult {
1445 row: QueryResultRow::Mock(crate::MockRow { values }),
1446 };
1447 assert_eq!(
1448 query_result.column_names(),
1449 vec!["id".to_owned(), "name".to_owned()]
1450 );
1451 }
1452}