1pub use crate::error::TryGetError;
2use crate::{
3 SelectGetableValue, SelectorRaw, Statement,
4 error::{DbErr, type_err},
5};
6use std::{fmt::Debug, marker::PhantomData, sync::Arc};
7
8#[cfg(any(feature = "mock", feature = "proxy"))]
9use crate::debug_print;
10
11#[cfg(feature = "sqlx-dep")]
12use crate::driver::*;
13#[cfg(feature = "sqlx-dep")]
14use sqlx::Row;
15
16#[derive(Debug)]
18pub struct QueryResult {
19 pub(crate) row: QueryResultRow,
20}
21
22#[allow(clippy::enum_variant_names)]
23pub(crate) enum QueryResultRow {
24 #[cfg(feature = "sqlx-mysql")]
25 SqlxMySql(sqlx::mysql::MySqlRow),
26 #[cfg(feature = "sqlx-postgres")]
27 SqlxPostgres(sqlx::postgres::PgRow),
28 #[cfg(feature = "sqlx-sqlite")]
29 SqlxSqlite(sqlx::sqlite::SqliteRow),
30 #[cfg(feature = "rusqlite")]
31 Rusqlite(crate::driver::rusqlite::RusqliteRow),
32 #[cfg(feature = "mock")]
33 Mock(crate::MockRow),
34 #[cfg(feature = "proxy")]
35 Proxy(crate::ProxyRow),
36}
37
38pub trait TryGetable: Sized {
40 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError>;
42
43 fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError> {
45 if pre.is_empty() {
46 Self::try_get_by(res, col)
47 } else {
48 Self::try_get_by(res, format!("{pre}{col}").as_str())
49 }
50 }
51
52 fn try_get_by_index(res: &QueryResult, index: usize) -> Result<Self, TryGetError> {
54 Self::try_get_by(res, index)
55 }
56}
57
58impl From<TryGetError> for DbErr {
59 fn from(e: TryGetError) -> DbErr {
60 match e {
61 TryGetError::DbErr(e) => e,
62 TryGetError::Null(s) => {
63 type_err(format!("A null value was encountered while decoding {s}"))
64 }
65 }
66 }
67}
68
69impl From<DbErr> for TryGetError {
70 fn from(e: DbErr) -> TryGetError {
71 Self::DbErr(e)
72 }
73}
74
75impl QueryResult {
78 pub fn try_get_by<T, I>(&self, index: I) -> Result<T, DbErr>
80 where
81 T: TryGetable,
82 I: ColIdx,
83 {
84 Ok(T::try_get_by(self, index)?)
85 }
86
87 pub fn try_get_by_nullable<T, I>(&self, index: I) -> Result<T, TryGetError>
89 where
90 T: TryGetable,
91 I: ColIdx,
92 {
93 T::try_get_by(self, index)
94 }
95
96 pub fn try_get<T>(&self, pre: &str, col: &str) -> Result<T, DbErr>
98 where
99 T: TryGetable,
100 {
101 Ok(T::try_get(self, pre, col)?)
102 }
103
104 pub fn try_get_nullable<T>(&self, pre: &str, col: &str) -> Result<T, TryGetError>
106 where
107 T: TryGetable,
108 {
109 T::try_get(self, pre, col)
110 }
111
112 pub fn try_get_by_index<T>(&self, idx: usize) -> Result<T, DbErr>
114 where
115 T: TryGetable,
116 {
117 Ok(T::try_get_by_index(self, idx)?)
118 }
119
120 pub fn try_get_by_index_nullable<T>(&self, idx: usize) -> Result<T, TryGetError>
122 where
123 T: TryGetable,
124 {
125 T::try_get_by_index(self, idx)
126 }
127
128 pub fn try_get_many<T>(&self, pre: &str, cols: &[String]) -> Result<T, DbErr>
130 where
131 T: TryGetableMany,
132 {
133 Ok(T::try_get_many(self, pre, cols)?)
134 }
135
136 pub fn try_get_many_by_index<T>(&self) -> Result<T, DbErr>
138 where
139 T: TryGetableMany,
140 {
141 Ok(T::try_get_many_by_index(self)?)
142 }
143
144 pub fn column_names(&self) -> Vec<String> {
146 #[cfg(feature = "sqlx-dep")]
147 use sqlx::Column;
148
149 match &self.row {
150 #[cfg(feature = "sqlx-mysql")]
151 QueryResultRow::SqlxMySql(row) => {
152 row.columns().iter().map(|c| c.name().to_string()).collect()
153 }
154 #[cfg(feature = "sqlx-postgres")]
155 QueryResultRow::SqlxPostgres(row) => {
156 row.columns().iter().map(|c| c.name().to_string()).collect()
157 }
158 #[cfg(feature = "sqlx-sqlite")]
159 QueryResultRow::SqlxSqlite(row) => {
160 row.columns().iter().map(|c| c.name().to_string()).collect()
161 }
162 #[cfg(feature = "rusqlite")]
163 QueryResultRow::Rusqlite(row) => row.columns().iter().map(|c| c.to_string()).collect(),
164 #[cfg(feature = "mock")]
165 QueryResultRow::Mock(row) => row
166 .clone()
167 .into_column_value_tuples()
168 .map(|(c, _)| c.to_string())
169 .collect(),
170 #[cfg(feature = "proxy")]
171 QueryResultRow::Proxy(row) => row
172 .clone()
173 .into_column_value_tuples()
174 .map(|(c, _)| c.to_string())
175 .collect(),
176 #[allow(unreachable_patterns)]
177 _ => unreachable!(),
178 }
179 }
180
181 #[cfg(feature = "sqlx-mysql")]
183 pub fn try_as_mysql_row(&self) -> Option<&sqlx::mysql::MySqlRow> {
184 match &self.row {
185 QueryResultRow::SqlxMySql(mysql_row) => Some(mysql_row),
186 #[allow(unreachable_patterns)]
187 _ => None,
188 }
189 }
190
191 #[cfg(feature = "sqlx-postgres")]
193 pub fn try_as_pg_row(&self) -> Option<&sqlx::postgres::PgRow> {
194 match &self.row {
195 QueryResultRow::SqlxPostgres(pg_row) => Some(pg_row),
196 #[allow(unreachable_patterns)]
197 _ => None,
198 }
199 }
200
201 #[cfg(feature = "sqlx-sqlite")]
203 pub fn try_as_sqlite_row(&self) -> Option<&sqlx::sqlite::SqliteRow> {
204 match &self.row {
205 QueryResultRow::SqlxSqlite(sqlite_row) => Some(sqlite_row),
206 #[allow(unreachable_patterns)]
207 _ => None,
208 }
209 }
210
211 #[cfg(feature = "mock")]
213 pub fn try_as_mock_row(&self) -> Option<&crate::MockRow> {
214 match &self.row {
215 QueryResultRow::Mock(mock_row) => Some(mock_row),
216 #[allow(unreachable_patterns)]
217 _ => None,
218 }
219 }
220
221 #[cfg(feature = "proxy")]
223 pub fn try_as_proxy_row(&self) -> Option<&crate::ProxyRow> {
224 match &self.row {
225 QueryResultRow::Proxy(proxy_row) => Some(proxy_row),
226 #[allow(unreachable_patterns)]
227 _ => None,
228 }
229 }
230}
231
232#[allow(unused_variables)]
233impl Debug for QueryResultRow {
234 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
235 match self {
236 #[cfg(feature = "sqlx-mysql")]
237 Self::SqlxMySql(row) => write!(f, "{row:?}"),
238 #[cfg(feature = "sqlx-postgres")]
239 Self::SqlxPostgres(_) => write!(f, "QueryResultRow::SqlxPostgres cannot be inspected"),
240 #[cfg(feature = "sqlx-sqlite")]
241 Self::SqlxSqlite(_) => write!(f, "QueryResultRow::SqlxSqlite cannot be inspected"),
242 #[cfg(feature = "rusqlite")]
243 Self::Rusqlite(row) => write!(f, "{row:?}"),
244 #[cfg(feature = "mock")]
245 Self::Mock(row) => write!(f, "{row:?}"),
246 #[cfg(feature = "proxy")]
247 Self::Proxy(row) => write!(f, "{row:?}"),
248 #[allow(unreachable_patterns)]
249 _ => unreachable!(),
250 }
251 }
252}
253
254impl<T: TryGetable> TryGetable for Option<T> {
257 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
258 match T::try_get_by(res, index) {
259 Ok(v) => Ok(Some(v)),
260 Err(TryGetError::Null(_)) => Ok(None),
261 #[cfg(feature = "sqlx-dep")]
262 Err(TryGetError::DbErr(DbErr::Query(crate::RuntimeErr::SqlxError(err)))) => {
263 use std::ops::Deref;
264 match err.deref() {
265 sqlx::Error::ColumnNotFound(_) => Ok(None),
266 _ => Err(TryGetError::DbErr(DbErr::Query(
267 crate::RuntimeErr::SqlxError(err),
268 ))),
269 }
270 }
271 Err(e) => Err(e),
272 }
273 }
274}
275
276pub trait ColIdx: Debug + Copy {
278 #[cfg(feature = "sqlx-mysql")]
279 type SqlxMySqlIndex: sqlx::ColumnIndex<sqlx::mysql::MySqlRow>;
281 #[cfg(feature = "sqlx-postgres")]
282 type SqlxPostgresIndex: sqlx::ColumnIndex<sqlx::postgres::PgRow>;
284 #[cfg(feature = "sqlx-sqlite")]
285 type SqlxSqliteIndex: sqlx::ColumnIndex<sqlx::sqlite::SqliteRow>;
287
288 #[cfg(feature = "sqlx-mysql")]
289 fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex;
291 #[cfg(feature = "sqlx-postgres")]
292 fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex;
294 #[cfg(feature = "sqlx-sqlite")]
295 fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex;
297
298 fn as_str(&self) -> Option<&str>;
300 fn as_usize(&self) -> Option<&usize>;
302}
303
304impl ColIdx for &str {
305 #[cfg(feature = "sqlx-mysql")]
306 type SqlxMySqlIndex = Self;
307 #[cfg(feature = "sqlx-postgres")]
308 type SqlxPostgresIndex = Self;
309 #[cfg(feature = "sqlx-sqlite")]
310 type SqlxSqliteIndex = Self;
311
312 #[cfg(feature = "sqlx-mysql")]
313 #[inline]
314 fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex {
315 self
316 }
317 #[cfg(feature = "sqlx-postgres")]
318 #[inline]
319 fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex {
320 self
321 }
322 #[cfg(feature = "sqlx-sqlite")]
323 #[inline]
324 fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex {
325 self
326 }
327
328 #[inline]
329 fn as_str(&self) -> Option<&str> {
330 Some(self)
331 }
332 #[inline]
333 fn as_usize(&self) -> Option<&usize> {
334 None
335 }
336}
337
338impl ColIdx for usize {
339 #[cfg(feature = "sqlx-mysql")]
340 type SqlxMySqlIndex = Self;
341 #[cfg(feature = "sqlx-postgres")]
342 type SqlxPostgresIndex = Self;
343 #[cfg(feature = "sqlx-sqlite")]
344 type SqlxSqliteIndex = Self;
345
346 #[cfg(feature = "sqlx-mysql")]
347 #[inline]
348 fn as_sqlx_mysql_index(&self) -> Self::SqlxMySqlIndex {
349 *self
350 }
351 #[cfg(feature = "sqlx-postgres")]
352 #[inline]
353 fn as_sqlx_postgres_index(&self) -> Self::SqlxPostgresIndex {
354 *self
355 }
356 #[cfg(feature = "sqlx-sqlite")]
357 #[inline]
358 fn as_sqlx_sqlite_index(&self) -> Self::SqlxSqliteIndex {
359 *self
360 }
361
362 #[inline]
363 fn as_str(&self) -> Option<&str> {
364 None
365 }
366 #[inline]
367 fn as_usize(&self) -> Option<&usize> {
368 Some(self)
369 }
370}
371
372macro_rules! try_getable_all {
373 ( $type: ty ) => {
374 impl TryGetable for $type {
375 #[allow(unused_variables)]
376 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
377 match &res.row {
378 #[cfg(feature = "sqlx-mysql")]
379 QueryResultRow::SqlxMySql(row) => row
380 .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
381 .map_err(|e| sqlx_error_to_query_err(e).into())
382 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
383 #[cfg(feature = "sqlx-postgres")]
384 QueryResultRow::SqlxPostgres(row) => row
385 .try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
386 .map_err(|e| sqlx_error_to_query_err(e).into())
387 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
388 #[cfg(feature = "sqlx-sqlite")]
389 QueryResultRow::SqlxSqlite(row) => row
390 .try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
391 .map_err(|e| sqlx_error_to_query_err(e).into())
392 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
393 #[cfg(feature = "rusqlite")]
394 QueryResultRow::Rusqlite(row) => row
395 .try_get::<Option<$type>, _>(idx)
396 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
397 #[cfg(feature = "mock")]
398 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
399 debug_print!("{:#?}", e.to_string());
400 err_null_idx_col(idx)
401 }),
402 #[cfg(feature = "proxy")]
403 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
404 debug_print!("{:#?}", e.to_string());
405 err_null_idx_col(idx)
406 }),
407 #[allow(unreachable_patterns)]
408 _ => unreachable!(),
409 }
410 }
411 }
412 };
413}
414
415macro_rules! try_getable_unsigned {
416 ( $type: ty ) => {
417 impl TryGetable for $type {
418 #[allow(unused_variables)]
419 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
420 match &res.row {
421 #[cfg(feature = "sqlx-mysql")]
422 QueryResultRow::SqlxMySql(row) => row
423 .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
424 .map_err(|e| sqlx_error_to_query_err(e).into())
425 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
426 #[cfg(feature = "sqlx-postgres")]
427 QueryResultRow::SqlxPostgres(_) => Err(type_err(format!(
428 "{} unsupported by sqlx-postgres",
429 stringify!($type)
430 ))
431 .into()),
432 #[cfg(feature = "sqlx-sqlite")]
433 QueryResultRow::SqlxSqlite(row) => row
434 .try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
435 .map_err(|e| sqlx_error_to_query_err(e).into())
436 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
437 #[cfg(feature = "rusqlite")]
438 QueryResultRow::Rusqlite(row) => row
439 .try_get::<Option<$type>, _>(idx)
440 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
441 #[cfg(feature = "mock")]
442 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
443 debug_print!("{:#?}", e.to_string());
444 err_null_idx_col(idx)
445 }),
446 #[cfg(feature = "proxy")]
447 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
448 debug_print!("{:#?}", e.to_string());
449 err_null_idx_col(idx)
450 }),
451 #[allow(unreachable_patterns)]
452 _ => unreachable!(),
453 }
454 }
455 }
456 };
457}
458
459macro_rules! try_getable_mysql {
460 ( $type: ty ) => {
461 impl TryGetable for $type {
462 #[allow(unused_variables)]
463 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
464 match &res.row {
465 #[cfg(feature = "sqlx-mysql")]
466 QueryResultRow::SqlxMySql(row) => row
467 .try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
468 .map_err(|e| sqlx_error_to_query_err(e).into())
469 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
470 #[cfg(feature = "sqlx-postgres")]
471 QueryResultRow::SqlxPostgres(_) => Err(type_err(format!(
472 "{} unsupported by sqlx-postgres",
473 stringify!($type)
474 ))
475 .into()),
476 #[cfg(feature = "sqlx-sqlite")]
477 QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
478 "{} unsupported by sqlx-sqlite",
479 stringify!($type)
480 ))
481 .into()),
482 #[cfg(feature = "rusqlite")]
483 QueryResultRow::Rusqlite(row) => Err(type_err(format!(
484 "{} unsupported by rusqlite",
485 stringify!($type)
486 ))
487 .into()),
488 #[cfg(feature = "mock")]
489 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
490 debug_print!("{:#?}", e.to_string());
491 err_null_idx_col(idx)
492 }),
493 #[cfg(feature = "proxy")]
494 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
495 debug_print!("{:#?}", e.to_string());
496 err_null_idx_col(idx)
497 }),
498 #[allow(unreachable_patterns)]
499 _ => unreachable!(),
500 }
501 }
502 }
503 };
504}
505
506#[allow(unused_macros)]
507macro_rules! try_getable_postgres {
508 ( $type: ty ) => {
509 impl TryGetable for $type {
510 #[allow(unused_variables)]
511 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
512 match &res.row {
513 #[cfg(feature = "sqlx-mysql")]
514 QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
515 "{} unsupported by sqlx-mysql",
516 stringify!($type)
517 ))
518 .into()),
519 #[cfg(feature = "sqlx-postgres")]
520 QueryResultRow::SqlxPostgres(row) => row
521 .try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
522 .map_err(|e| sqlx_error_to_query_err(e).into())
523 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
524 #[cfg(feature = "sqlx-sqlite")]
525 QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
526 "{} unsupported by sqlx-sqlite",
527 stringify!($type)
528 ))
529 .into()),
530 #[cfg(feature = "rusqlite")]
531 QueryResultRow::Rusqlite(row) => Err(type_err(format!(
532 "{} unsupported by rusqlite",
533 stringify!($type)
534 ))
535 .into()),
536 #[cfg(feature = "mock")]
537 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
538 debug_print!("{:#?}", e.to_string());
539 err_null_idx_col(idx)
540 }),
541 #[cfg(feature = "proxy")]
542 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
543 debug_print!("{:#?}", e.to_string());
544 err_null_idx_col(idx)
545 }),
546 #[allow(unreachable_patterns)]
547 _ => unreachable!(),
548 }
549 }
550 }
551 };
552}
553
554#[allow(unused_macros)]
555macro_rules! try_getable_date_time {
556 ( $type: ty ) => {
557 impl TryGetable for $type {
558 #[allow(unused_variables)]
559 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
560 match &res.row {
561 #[cfg(feature = "sqlx-mysql")]
562 QueryResultRow::SqlxMySql(row) => {
563 use chrono::{DateTime, Utc};
564 row.try_get::<Option<DateTime<Utc>>, _>(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 .map(|v| v.into())
568 }
569 #[cfg(feature = "sqlx-postgres")]
570 QueryResultRow::SqlxPostgres(row) => row
571 .try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
572 .map_err(|e| sqlx_error_to_query_err(e).into())
573 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
574 #[cfg(feature = "sqlx-sqlite")]
575 QueryResultRow::SqlxSqlite(row) => {
576 use chrono::{DateTime, Utc};
577 row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_sqlite_index())
578 .map_err(|e| sqlx_error_to_query_err(e).into())
579 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
580 .map(|v| v.into())
581 }
582 #[cfg(feature = "rusqlite")]
583 QueryResultRow::Rusqlite(row) => {
584 use chrono::{DateTime, Utc};
585 row.try_get::<Option<DateTime<Utc>>, _>(idx)
586 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
587 .map(|v| v.into())
588 }
589 #[cfg(feature = "mock")]
590 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
591 debug_print!("{:#?}", e.to_string());
592 err_null_idx_col(idx)
593 }),
594 #[cfg(feature = "proxy")]
595 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
596 debug_print!("{:#?}", e.to_string());
597 err_null_idx_col(idx)
598 }),
599 #[allow(unreachable_patterns)]
600 _ => unreachable!(),
601 }
602 }
603 }
604 };
605}
606
607try_getable_all!(bool);
608try_getable_all!(i8);
609try_getable_all!(i16);
610try_getable_all!(i32);
611try_getable_all!(i64);
612try_getable_unsigned!(u8);
613try_getable_unsigned!(u16);
614try_getable_mysql!(u64);
615try_getable_all!(f32);
616try_getable_all!(f64);
617try_getable_all!(Vec<u8>);
618
619#[cfg(feature = "with-json")]
620try_getable_all!(serde_json::Value);
621
622#[cfg(feature = "with-chrono")]
623try_getable_all!(chrono::NaiveDate);
624
625#[cfg(feature = "with-chrono")]
626try_getable_all!(chrono::NaiveTime);
627
628#[cfg(feature = "with-chrono")]
629try_getable_all!(chrono::NaiveDateTime);
630
631#[cfg(feature = "with-chrono")]
632try_getable_date_time!(chrono::DateTime<chrono::FixedOffset>);
633
634#[cfg(feature = "with-chrono")]
635try_getable_all!(chrono::DateTime<chrono::Utc>);
636
637#[cfg(feature = "with-chrono")]
638try_getable_all!(chrono::DateTime<chrono::Local>);
639
640#[cfg(feature = "with-time")]
641try_getable_all!(time::Date);
642
643#[cfg(feature = "with-time")]
644try_getable_all!(time::Time);
645
646#[cfg(feature = "with-time")]
647try_getable_all!(time::PrimitiveDateTime);
648
649#[cfg(feature = "with-time")]
650try_getable_all!(time::OffsetDateTime);
651
652#[cfg(feature = "with-rust_decimal")]
653use rust_decimal::Decimal;
654
655#[cfg(feature = "with-rust_decimal")]
656impl TryGetable for Decimal {
657 #[allow(unused_variables)]
658 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
659 match &res.row {
660 #[cfg(feature = "sqlx-mysql")]
661 QueryResultRow::SqlxMySql(row) => row
662 .try_get::<Option<Decimal>, _>(idx.as_sqlx_mysql_index())
663 .map_err(|e| sqlx_error_to_query_err(e).into())
664 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
665 #[cfg(feature = "sqlx-postgres")]
666 QueryResultRow::SqlxPostgres(row) => row
667 .try_get::<Option<Decimal>, _>(idx.as_sqlx_postgres_index())
668 .map_err(|e| sqlx_error_to_query_err(e).into())
669 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
670 #[cfg(feature = "sqlx-sqlite")]
671 QueryResultRow::SqlxSqlite(row) => {
672 let val: Option<f64> = row
673 .try_get(idx.as_sqlx_sqlite_index())
674 .map_err(sqlx_error_to_query_err)?;
675 match val {
676 Some(v) => Decimal::try_from(v).map_err(|e| {
677 DbErr::TryIntoErr {
678 from: "f64",
679 into: "Decimal",
680 source: Arc::new(e),
681 }
682 .into()
683 }),
684 None => Err(err_null_idx_col(idx)),
685 }
686 }
687 #[cfg(feature = "rusqlite")]
688 QueryResultRow::Rusqlite(row) => {
689 let val: Option<f64> = row.try_get(idx)?;
690 match val {
691 Some(v) => Decimal::try_from(v).map_err(|e| {
692 DbErr::TryIntoErr {
693 from: "f64",
694 into: "Decimal",
695 source: Arc::new(e),
696 }
697 .into()
698 }),
699 None => Err(err_null_idx_col(idx)),
700 }
701 }
702 #[cfg(feature = "mock")]
703 #[allow(unused_variables)]
704 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
705 debug_print!("{:#?}", e.to_string());
706 err_null_idx_col(idx)
707 }),
708 #[cfg(feature = "proxy")]
709 #[allow(unused_variables)]
710 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
711 debug_print!("{:#?}", e.to_string());
712 err_null_idx_col(idx)
713 }),
714 #[allow(unreachable_patterns)]
715 _ => unreachable!(),
716 }
717 }
718}
719
720#[cfg(feature = "with-bigdecimal")]
721use bigdecimal::BigDecimal;
722
723#[cfg(feature = "with-bigdecimal")]
724impl TryGetable for BigDecimal {
725 #[allow(unused_variables)]
726 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
727 match &res.row {
728 #[cfg(feature = "sqlx-mysql")]
729 QueryResultRow::SqlxMySql(row) => row
730 .try_get::<Option<BigDecimal>, _>(idx.as_sqlx_mysql_index())
731 .map_err(|e| sqlx_error_to_query_err(e).into())
732 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
733 #[cfg(feature = "sqlx-postgres")]
734 QueryResultRow::SqlxPostgres(row) => row
735 .try_get::<Option<BigDecimal>, _>(idx.as_sqlx_postgres_index())
736 .map_err(|e| sqlx_error_to_query_err(e).into())
737 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
738 #[cfg(feature = "sqlx-sqlite")]
739 QueryResultRow::SqlxSqlite(row) => {
740 let val: Option<f64> = row
741 .try_get(idx.as_sqlx_sqlite_index())
742 .map_err(sqlx_error_to_query_err)?;
743 match val {
744 Some(v) => BigDecimal::try_from(v).map_err(|e| {
745 DbErr::TryIntoErr {
746 from: "f64",
747 into: "BigDecimal",
748 source: Arc::new(e),
749 }
750 .into()
751 }),
752 None => Err(err_null_idx_col(idx)),
753 }
754 }
755 #[cfg(feature = "rusqlite")]
756 QueryResultRow::Rusqlite(row) => {
757 let val: Option<f64> = row.try_get(idx)?;
758 match val {
759 Some(v) => BigDecimal::try_from(v).map_err(|e| {
760 DbErr::TryIntoErr {
761 from: "f64",
762 into: "BigDecimal",
763 source: Arc::new(e),
764 }
765 .into()
766 }),
767 None => Err(err_null_idx_col(idx)),
768 }
769 }
770 #[cfg(feature = "mock")]
771 #[allow(unused_variables)]
772 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
773 debug_print!("{:#?}", e.to_string());
774 err_null_idx_col(idx)
775 }),
776 #[cfg(feature = "proxy")]
777 #[allow(unused_variables)]
778 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
779 debug_print!("{:#?}", e.to_string());
780 err_null_idx_col(idx)
781 }),
782 #[allow(unreachable_patterns)]
783 _ => unreachable!(),
784 }
785 }
786}
787
788#[allow(unused_macros)]
789macro_rules! try_getable_uuid {
790 ( $type: ty, $conversion_fn: expr ) => {
791 #[allow(unused_variables, unreachable_code)]
792 impl TryGetable for $type {
793 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
794 let res: Result<uuid::Uuid, TryGetError> = match &res.row {
795 #[cfg(feature = "sqlx-mysql")]
796 QueryResultRow::SqlxMySql(row) => row
797 .try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_mysql_index())
798 .map_err(|e| sqlx_error_to_query_err(e).into())
799 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
800 .or_else(|_| {
801 row.try_get::<Option<Vec<u8>>, _>(idx.as_sqlx_mysql_index())
804 .map_err(|e| sqlx_error_to_query_err(e).into())
805 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
806 .map(|bytes| {
807 String::from_utf8(bytes).map_err(|e| {
808 DbErr::TryIntoErr {
809 from: "Vec<u8>",
810 into: "String",
811 source: Arc::new(e),
812 }
813 .into()
814 })
815 })?
816 .and_then(|s| {
817 uuid::Uuid::parse_str(&s).map_err(|e| {
818 DbErr::TryIntoErr {
819 from: "String",
820 into: "uuid::Uuid",
821 source: Arc::new(e),
822 }
823 .into()
824 })
825 })
826 }),
827 #[cfg(feature = "sqlx-postgres")]
828 QueryResultRow::SqlxPostgres(row) => row
829 .try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_postgres_index())
830 .map_err(|e| sqlx_error_to_query_err(e).into())
831 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
832 #[cfg(feature = "sqlx-sqlite")]
833 QueryResultRow::SqlxSqlite(row) => row
834 .try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_sqlite_index())
835 .map_err(|e| sqlx_error_to_query_err(e).into())
836 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
837 #[cfg(feature = "rusqlite")]
838 QueryResultRow::Rusqlite(row) => row
839 .try_get::<Option<uuid::Uuid>, _>(idx)
840 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
841 #[cfg(feature = "mock")]
842 #[allow(unused_variables)]
843 QueryResultRow::Mock(row) => row.try_get::<uuid::Uuid, _>(idx).map_err(|e| {
844 debug_print!("{:#?}", e.to_string());
845 err_null_idx_col(idx)
846 }),
847 #[cfg(feature = "proxy")]
848 #[allow(unused_variables)]
849 QueryResultRow::Proxy(row) => row.try_get::<uuid::Uuid, _>(idx).map_err(|e| {
850 debug_print!("{:#?}", e.to_string());
851 err_null_idx_col(idx)
852 }),
853 #[allow(unreachable_patterns)]
854 _ => unreachable!(),
855 };
856 res.map($conversion_fn)
857 }
858 }
859 };
860}
861
862#[cfg(feature = "with-uuid")]
863try_getable_uuid!(uuid::Uuid, Into::into);
864
865#[cfg(feature = "with-uuid")]
866try_getable_uuid!(uuid::fmt::Braced, uuid::Uuid::braced);
867
868#[cfg(feature = "with-uuid")]
869try_getable_uuid!(uuid::fmt::Hyphenated, uuid::Uuid::hyphenated);
870
871#[cfg(feature = "with-uuid")]
872try_getable_uuid!(uuid::fmt::Simple, uuid::Uuid::simple);
873
874#[cfg(feature = "with-uuid")]
875try_getable_uuid!(uuid::fmt::Urn, uuid::Uuid::urn);
876
877#[cfg(feature = "with-ipnetwork")]
878try_getable_postgres!(ipnetwork::IpNetwork);
879
880#[cfg(feature = "with-mac_address")]
881try_getable_postgres!(mac_address::MacAddress);
882
883impl TryGetable for u32 {
884 #[allow(unused_variables)]
885 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
886 match &res.row {
887 #[cfg(feature = "sqlx-mysql")]
888 QueryResultRow::SqlxMySql(row) => row
889 .try_get::<Option<u32>, _>(idx.as_sqlx_mysql_index())
890 .map_err(|e| sqlx_error_to_query_err(e).into())
891 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
892 #[cfg(feature = "sqlx-postgres")]
893 QueryResultRow::SqlxPostgres(row) => {
894 use sqlx::postgres::types::Oid;
895 match row.try_get::<Option<Oid>, _>(idx.as_sqlx_postgres_index()) {
898 Ok(opt) => opt.ok_or_else(|| err_null_idx_col(idx)).map(|oid| oid.0),
899 Err(_) => row
900 .try_get::<i32, _>(idx.as_sqlx_postgres_index())
902 .map_err(|e| sqlx_error_to_query_err(e).into())
903 .map(|v| {
904 v.try_into().map_err(|e| {
905 DbErr::TryIntoErr {
906 from: "i32",
907 into: "u32",
908 source: Arc::new(e),
909 }
910 .into()
911 })
912 })
913 .and_then(|r| r),
914 }
915 }
916 #[cfg(feature = "sqlx-sqlite")]
917 QueryResultRow::SqlxSqlite(row) => row
918 .try_get::<Option<u32>, _>(idx.as_sqlx_sqlite_index())
919 .map_err(|e| sqlx_error_to_query_err(e).into())
920 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
921 #[cfg(feature = "rusqlite")]
922 QueryResultRow::Rusqlite(row) => row
923 .try_get::<Option<u32>, _>(idx)
924 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
925 #[cfg(feature = "mock")]
926 #[allow(unused_variables)]
927 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
928 debug_print!("{:#?}", e.to_string());
929 err_null_idx_col(idx)
930 }),
931 #[cfg(feature = "proxy")]
932 #[allow(unused_variables)]
933 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
934 debug_print!("{:#?}", e.to_string());
935 err_null_idx_col(idx)
936 }),
937 #[allow(unreachable_patterns)]
938 _ => unreachable!(),
939 }
940 }
941}
942
943impl TryGetable for String {
944 #[allow(unused_variables)]
945 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
946 match &res.row {
947 #[cfg(feature = "sqlx-mysql")]
948 QueryResultRow::SqlxMySql(row) => row
949 .try_get::<Option<Vec<u8>>, _>(idx.as_sqlx_mysql_index())
950 .map_err(|e| sqlx_error_to_query_err(e).into())
951 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
952 .map(|bytes| {
953 String::from_utf8(bytes).map_err(|e| {
954 DbErr::TryIntoErr {
955 from: "Vec<u8>",
956 into: "String",
957 source: Arc::new(e),
958 }
959 .into()
960 })
961 })?,
962 #[cfg(feature = "sqlx-postgres")]
963 QueryResultRow::SqlxPostgres(row) => row
964 .try_get::<Option<String>, _>(idx.as_sqlx_postgres_index())
965 .map_err(|e| sqlx_error_to_query_err(e).into())
966 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
967 #[cfg(feature = "sqlx-sqlite")]
968 QueryResultRow::SqlxSqlite(row) => row
969 .try_get::<Option<String>, _>(idx.as_sqlx_sqlite_index())
970 .map_err(|e| sqlx_error_to_query_err(e).into())
971 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
972 #[cfg(feature = "rusqlite")]
973 QueryResultRow::Rusqlite(row) => row
974 .try_get::<Option<String>, _>(idx)
975 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
976 #[cfg(feature = "mock")]
977 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
978 debug_print!("{:#?}", e.to_string());
979 err_null_idx_col(idx)
980 }),
981 #[cfg(feature = "proxy")]
982 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
983 debug_print!("{:#?}", e.to_string());
984 err_null_idx_col(idx)
985 }),
986 #[allow(unreachable_patterns)]
987 _ => unreachable!(),
988 }
989 }
990}
991
992#[allow(dead_code)]
993fn err_null_idx_col<I: ColIdx>(idx: I) -> TryGetError {
994 TryGetError::Null(format!("{idx:?}"))
995}
996
997#[cfg(feature = "postgres-array")]
998mod postgres_array {
999 use super::*;
1000
1001 #[allow(unused_macros)]
1002 macro_rules! try_getable_postgres_array {
1003 ( $type: ty ) => {
1004 #[allow(unused_variables)]
1005 impl TryGetable for Vec<$type> {
1006 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1007 match &res.row {
1008 #[cfg(feature = "sqlx-mysql")]
1009 QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
1010 "{} unsupported by sqlx-mysql",
1011 stringify!($type)
1012 ))
1013 .into()),
1014 #[cfg(feature = "sqlx-postgres")]
1015 QueryResultRow::SqlxPostgres(row) => row
1016 .try_get::<Option<Vec<$type>>, _>(idx.as_sqlx_postgres_index())
1017 .map_err(|e| sqlx_error_to_query_err(e).into())
1018 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1019 #[cfg(feature = "sqlx-sqlite")]
1020 QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1021 "{} unsupported by sqlx-sqlite",
1022 stringify!($type)
1023 ))
1024 .into()),
1025 #[cfg(feature = "rusqlite")]
1026 QueryResultRow::Rusqlite(_) => Err(type_err(format!(
1027 "{} unsupported by rusqlite",
1028 stringify!($type)
1029 ))
1030 .into()),
1031 #[cfg(feature = "mock")]
1032 #[allow(unused_variables)]
1033 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
1034 debug_print!("{:#?}", e.to_string());
1035 err_null_idx_col(idx)
1036 }),
1037 #[cfg(feature = "proxy")]
1038 #[allow(unused_variables)]
1039 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
1040 debug_print!("{:#?}", e.to_string());
1041 err_null_idx_col(idx)
1042 }),
1043 #[allow(unreachable_patterns)]
1044 _ => unreachable!(),
1045 }
1046 }
1047 }
1048 };
1049 }
1050
1051 try_getable_postgres_array!(bool);
1052 try_getable_postgres_array!(i8);
1053 try_getable_postgres_array!(i16);
1054 try_getable_postgres_array!(i32);
1055 try_getable_postgres_array!(i64);
1056 try_getable_postgres_array!(f32);
1057 try_getable_postgres_array!(f64);
1058 try_getable_postgres_array!(String);
1059 try_getable_postgres_array!(Vec<u8>);
1060
1061 #[cfg(feature = "with-json")]
1062 try_getable_postgres_array!(serde_json::Value);
1063
1064 #[cfg(feature = "with-chrono")]
1065 try_getable_postgres_array!(chrono::NaiveDate);
1066
1067 #[cfg(feature = "with-chrono")]
1068 try_getable_postgres_array!(chrono::NaiveTime);
1069
1070 #[cfg(feature = "with-chrono")]
1071 try_getable_postgres_array!(chrono::NaiveDateTime);
1072
1073 #[cfg(feature = "with-chrono")]
1074 try_getable_postgres_array!(chrono::DateTime<chrono::FixedOffset>);
1075
1076 #[cfg(feature = "with-chrono")]
1077 try_getable_postgres_array!(chrono::DateTime<chrono::Utc>);
1078
1079 #[cfg(feature = "with-chrono")]
1080 try_getable_postgres_array!(chrono::DateTime<chrono::Local>);
1081
1082 #[cfg(feature = "with-time")]
1083 try_getable_postgres_array!(time::Date);
1084
1085 #[cfg(feature = "with-time")]
1086 try_getable_postgres_array!(time::Time);
1087
1088 #[cfg(feature = "with-time")]
1089 try_getable_postgres_array!(time::PrimitiveDateTime);
1090
1091 #[cfg(feature = "with-time")]
1092 try_getable_postgres_array!(time::OffsetDateTime);
1093
1094 #[cfg(feature = "with-rust_decimal")]
1095 try_getable_postgres_array!(rust_decimal::Decimal);
1096
1097 #[cfg(feature = "with-bigdecimal")]
1098 try_getable_postgres_array!(bigdecimal::BigDecimal);
1099
1100 #[cfg(feature = "with-ipnetwork")]
1101 try_getable_postgres_array!(ipnetwork::IpNetwork);
1102
1103 #[cfg(feature = "with-mac_address")]
1104 try_getable_postgres_array!(mac_address::MacAddress);
1105
1106 #[allow(unused_macros)]
1107 macro_rules! try_getable_postgres_array_uuid {
1108 ( $type: ty, $conversion_fn: expr ) => {
1109 #[allow(unused_variables, unreachable_code)]
1110 impl TryGetable for Vec<$type> {
1111 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1112 let res: Result<Vec<uuid::Uuid>, TryGetError> = match &res.row {
1113 #[cfg(feature = "sqlx-mysql")]
1114 QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
1115 "{} unsupported by sqlx-mysql",
1116 stringify!($type)
1117 ))
1118 .into()),
1119 #[cfg(feature = "sqlx-postgres")]
1120 QueryResultRow::SqlxPostgres(row) => row
1121 .try_get::<Option<Vec<uuid::Uuid>>, _>(idx.as_sqlx_postgres_index())
1122 .map_err(|e| sqlx_error_to_query_err(e).into())
1123 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1124 #[cfg(feature = "sqlx-sqlite")]
1125 QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1126 "{} unsupported by sqlx-sqlite",
1127 stringify!($type)
1128 ))
1129 .into()),
1130 #[cfg(feature = "rusqlite")]
1131 QueryResultRow::Rusqlite(_) => Err(type_err(format!(
1132 "{} unsupported by rusqlite",
1133 stringify!($type)
1134 ))
1135 .into()),
1136 #[cfg(feature = "mock")]
1137 QueryResultRow::Mock(row) => {
1138 row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
1139 debug_print!("{:#?}", e.to_string());
1140 err_null_idx_col(idx)
1141 })
1142 }
1143 #[cfg(feature = "proxy")]
1144 QueryResultRow::Proxy(row) => {
1145 row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
1146 debug_print!("{:#?}", e.to_string());
1147 err_null_idx_col(idx)
1148 })
1149 }
1150 #[allow(unreachable_patterns)]
1151 _ => unreachable!(),
1152 };
1153 res.map(|vec| vec.into_iter().map($conversion_fn).collect())
1154 }
1155 }
1156 };
1157 }
1158
1159 #[cfg(feature = "with-uuid")]
1160 try_getable_postgres_array_uuid!(uuid::Uuid, Into::into);
1161
1162 #[cfg(feature = "with-uuid")]
1163 try_getable_postgres_array_uuid!(uuid::fmt::Braced, uuid::Uuid::braced);
1164
1165 #[cfg(feature = "with-uuid")]
1166 try_getable_postgres_array_uuid!(uuid::fmt::Hyphenated, uuid::Uuid::hyphenated);
1167
1168 #[cfg(feature = "with-uuid")]
1169 try_getable_postgres_array_uuid!(uuid::fmt::Simple, uuid::Uuid::simple);
1170
1171 #[cfg(feature = "with-uuid")]
1172 try_getable_postgres_array_uuid!(uuid::fmt::Urn, uuid::Uuid::urn);
1173
1174 impl TryGetable for Vec<u32> {
1175 #[allow(unused_variables)]
1176 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1177 match &res.row {
1178 #[cfg(feature = "sqlx-mysql")]
1179 QueryResultRow::SqlxMySql(_) => {
1180 Err(type_err(format!("{} unsupported by sqlx-mysql", stringify!($type))).into())
1181 }
1182 #[cfg(feature = "sqlx-postgres")]
1183 QueryResultRow::SqlxPostgres(row) => {
1184 use sqlx::postgres::types::Oid;
1185 row.try_get::<Option<Vec<Oid>>, _>(idx.as_sqlx_postgres_index())
1188 .map_err(|e| sqlx_error_to_query_err(e).into())
1189 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
1190 .map(|oids| oids.into_iter().map(|oid| oid.0).collect())
1191 }
1192 #[cfg(feature = "sqlx-sqlite")]
1193 QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
1194 "{} unsupported by sqlx-sqlite",
1195 stringify!($type)
1196 ))
1197 .into()),
1198 #[cfg(feature = "rusqlite")]
1199 QueryResultRow::Rusqlite(_) => {
1200 Err(type_err(format!("{} unsupported by rusqlite", stringify!($type))).into())
1201 }
1202 #[cfg(feature = "mock")]
1203 #[allow(unused_variables)]
1204 QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
1205 debug_print!("{:#?}", e.to_string());
1206 err_null_idx_col(idx)
1207 }),
1208 #[cfg(feature = "proxy")]
1209 #[allow(unused_variables)]
1210 QueryResultRow::Proxy(row) => row.try_get(idx).map_err(|e| {
1211 debug_print!("{:#?}", e.to_string());
1212 err_null_idx_col(idx)
1213 }),
1214 #[allow(unreachable_patterns)]
1215 _ => unreachable!(),
1216 }
1217 }
1218 }
1219}
1220
1221#[cfg(feature = "postgres-vector")]
1222impl TryGetable for pgvector::Vector {
1223 #[allow(unused_variables)]
1224 fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1225 match &res.row {
1226 #[cfg(feature = "sqlx-mysql")]
1227 QueryResultRow::SqlxMySql(_) => {
1228 Err(type_err("Vector unsupported by sqlx-mysql").into())
1229 }
1230 #[cfg(feature = "sqlx-postgres")]
1231 QueryResultRow::SqlxPostgres(row) => row
1232 .try_get::<Option<pgvector::Vector>, _>(idx.as_sqlx_postgres_index())
1233 .map_err(|e| sqlx_error_to_query_err(e).into())
1234 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
1235 #[cfg(feature = "sqlx-sqlite")]
1236 QueryResultRow::SqlxSqlite(_) => {
1237 Err(type_err("Vector unsupported by sqlx-sqlite").into())
1238 }
1239 #[cfg(feature = "rusqlite")]
1240 QueryResultRow::Rusqlite(_) => Err(type_err("Vector unsupported by rusqlite").into()),
1241 #[cfg(feature = "mock")]
1242 QueryResultRow::Mock(row) => row.try_get::<pgvector::Vector, _>(idx).map_err(|e| {
1243 debug_print!("{:#?}", e.to_string());
1244 err_null_idx_col(idx)
1245 }),
1246 #[cfg(feature = "proxy")]
1247 QueryResultRow::Proxy(row) => row.try_get::<pgvector::Vector, _>(idx).map_err(|e| {
1248 debug_print!("{:#?}", e.to_string());
1249 err_null_idx_col(idx)
1250 }),
1251 #[allow(unreachable_patterns)]
1252 _ => unreachable!(),
1253 }
1254 }
1255}
1256
1257pub trait TryGetableMany: Sized {
1261 fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError>;
1263
1264 fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError>;
1266
1267 fn find_by_statement<C>(stmt: Statement) -> SelectorRaw<SelectGetableValue<Self, C>>
1325 where
1326 C: strum::IntoEnumIterator + sea_query::Iden,
1327 {
1328 SelectorRaw {
1329 stmt,
1330 selector: PhantomData,
1331 }
1332 }
1333}
1334
1335impl<T> TryGetableMany for T
1336where
1337 T: TryGetable,
1338{
1339 fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1340 try_get_many_with_slice_len_of(1, cols)?;
1341 T::try_get(res, pre, &cols[0])
1342 }
1343
1344 fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1345 T::try_get_by_index(res, 0)
1346 }
1347}
1348
1349impl<T> TryGetableMany for (T,)
1350where
1351 T: TryGetableMany,
1352{
1353 fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1354 T::try_get_many(res, pre, cols).map(|r| (r,))
1355 }
1356
1357 fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1358 T::try_get_many_by_index(res).map(|r| (r,))
1359 }
1360}
1361
1362macro_rules! impl_try_get_many {
1363 ( $LEN:expr, $($T:ident : $N:expr),+ $(,)? ) => {
1364 impl< $($T),+ > TryGetableMany for ( $($T),+ )
1365 where
1366 $($T: TryGetable),+
1367 {
1368 fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
1369 try_get_many_with_slice_len_of($LEN, cols)?;
1370 Ok((
1371 $($T::try_get(res, pre, &cols[$N])?),+
1372 ))
1373 }
1374
1375 fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
1376 Ok((
1377 $($T::try_get_by_index(res, $N)?),+
1378 ))
1379 }
1380 }
1381 };
1382}
1383
1384#[rustfmt::skip]
1385mod impl_try_get_many {
1386 use super::*;
1387
1388 impl_try_get_many!( 2, T0:0, T1:1);
1389 impl_try_get_many!( 3, T0:0, T1:1, T2:2);
1390 impl_try_get_many!( 4, T0:0, T1:1, T2:2, T3:3);
1391 impl_try_get_many!( 5, T0:0, T1:1, T2:2, T3:3, T4:4);
1392 impl_try_get_many!( 6, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
1393 impl_try_get_many!( 7, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
1394 impl_try_get_many!( 8, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
1395 impl_try_get_many!( 9, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
1396 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);
1397 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);
1398 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);
1399}
1400
1401fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
1402 if cols.len() < len {
1403 Err(type_err(format!(
1404 "Expect {} column names supplied but got slice of length {}",
1405 len,
1406 cols.len()
1407 ))
1408 .into())
1409 } else {
1410 Ok(())
1411 }
1412}
1413
1414pub trait TryGetableArray: Sized {
1420 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<Self>, TryGetError>;
1422}
1423
1424impl<T> TryGetable for Vec<T>
1425where
1426 T: TryGetableArray,
1427{
1428 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1429 T::try_get_by(res, index)
1430 }
1431}
1432
1433#[cfg(feature = "with-json")]
1437pub trait TryGetableFromJson: Sized
1438where
1439 for<'de> Self: serde::Deserialize<'de>,
1440{
1441 #[allow(unused_variables, unreachable_code)]
1443 fn try_get_from_json<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
1444 match &res.row {
1445 #[cfg(feature = "sqlx-mysql")]
1446 QueryResultRow::SqlxMySql(row) => row
1447 .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_mysql_index())
1448 .map_err(|e| sqlx_error_to_query_err(e).into())
1449 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1450 #[cfg(feature = "sqlx-postgres")]
1451 QueryResultRow::SqlxPostgres(row) => row
1452 .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_postgres_index())
1453 .map_err(|e| sqlx_error_to_query_err(e).into())
1454 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1455 #[cfg(feature = "sqlx-sqlite")]
1456 QueryResultRow::SqlxSqlite(row) => row
1457 .try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_sqlite_index())
1458 .map_err(|e| sqlx_error_to_query_err(e).into())
1459 .and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
1460 #[cfg(feature = "rusqlite")]
1461 QueryResultRow::Rusqlite(row) => row
1462 .try_get::<Option<serde_json::Value>, _>(idx)?
1463 .ok_or_else(|| err_null_idx_col(idx))
1464 .and_then(|json| {
1465 serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1466 }),
1467 #[cfg(feature = "mock")]
1468 QueryResultRow::Mock(row) => row
1469 .try_get::<serde_json::Value, I>(idx)
1470 .map_err(|e| {
1471 debug_print!("{:#?}", e.to_string());
1472 err_null_idx_col(idx)
1473 })
1474 .and_then(|json| {
1475 serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1476 }),
1477 #[cfg(feature = "proxy")]
1478 QueryResultRow::Proxy(row) => row
1479 .try_get::<serde_json::Value, I>(idx)
1480 .map_err(|e| {
1481 debug_print!("{:#?}", e.to_string());
1482 err_null_idx_col(idx)
1483 })
1484 .and_then(|json| {
1485 serde_json::from_value(json).map_err(|e| crate::error::json_err(e).into())
1486 }),
1487 #[allow(unreachable_patterns)]
1488 _ => unreachable!(),
1489 }
1490 }
1491
1492 fn from_json_vec(value: serde_json::Value) -> Result<Vec<Self>, TryGetError> {
1494 match value {
1495 serde_json::Value::Array(values) => {
1496 let mut res = Vec::new();
1497 for item in values {
1498 res.push(serde_json::from_value(item).map_err(crate::error::json_err)?);
1499 }
1500 Ok(res)
1501 }
1502 _ => Err(TryGetError::DbErr(DbErr::Json(
1503 "Value is not an Array".to_owned(),
1504 ))),
1505 }
1506 }
1507}
1508
1509#[cfg(feature = "with-json")]
1510impl<T> TryGetable for T
1511where
1512 T: TryGetableFromJson,
1513{
1514 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
1515 T::try_get_from_json(res, index)
1516 }
1517}
1518
1519#[cfg(feature = "with-json")]
1520impl<T> TryGetableArray for T
1521where
1522 T: TryGetableFromJson,
1523{
1524 fn try_get_by<I: ColIdx>(res: &QueryResult, index: I) -> Result<Vec<T>, TryGetError> {
1525 T::from_json_vec(serde_json::Value::try_get_by(res, index)?)
1526 }
1527}
1528
1529pub trait TryFromU64: Sized {
1532 fn try_from_u64(n: u64) -> Result<Self, DbErr>;
1534}
1535
1536macro_rules! try_from_u64_err {
1537 ( $type: ty ) => {
1538 impl TryFromU64 for $type {
1539 fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1540 Err(DbErr::ConvertFromU64(stringify!($type)))
1541 }
1542 }
1543 };
1544
1545 ( $($gen_type: ident),* ) => {
1546 impl<$( $gen_type, )*> TryFromU64 for ($( $gen_type, )*)
1547 where
1548 $( $gen_type: TryFromU64, )*
1549 {
1550 fn try_from_u64(_: u64) -> Result<Self, DbErr> {
1551 Err(DbErr::ConvertFromU64(stringify!($($gen_type,)*)))
1552 }
1553 }
1554 };
1555}
1556
1557#[rustfmt::skip]
1558mod try_from_u64_err {
1559 use super::*;
1560
1561 try_from_u64_err!(T0, T1);
1562 try_from_u64_err!(T0, T1, T2);
1563 try_from_u64_err!(T0, T1, T2, T3);
1564 try_from_u64_err!(T0, T1, T2, T3, T4);
1565 try_from_u64_err!(T0, T1, T2, T3, T4, T5);
1566 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6);
1567 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7);
1568 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
1569 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
1570 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
1571 try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
1572}
1573
1574macro_rules! try_from_u64_numeric {
1575 ( $type: ty ) => {
1576 impl TryFromU64 for $type {
1577 fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1578 use std::convert::TryInto;
1579 n.try_into().map_err(|e| DbErr::TryIntoErr {
1580 from: stringify!(u64),
1581 into: stringify!($type),
1582 source: Arc::new(e),
1583 })
1584 }
1585 }
1586 };
1587}
1588
1589try_from_u64_numeric!(i8);
1590try_from_u64_numeric!(i16);
1591try_from_u64_numeric!(i32);
1592try_from_u64_numeric!(i64);
1593try_from_u64_numeric!(u8);
1594try_from_u64_numeric!(u16);
1595try_from_u64_numeric!(u32);
1596try_from_u64_numeric!(u64);
1597
1598macro_rules! try_from_u64_string {
1599 ( $type: ty ) => {
1600 impl TryFromU64 for $type {
1601 fn try_from_u64(n: u64) -> Result<Self, DbErr> {
1602 Ok(n.to_string())
1603 }
1604 }
1605 };
1606}
1607
1608try_from_u64_string!(String);
1609
1610try_from_u64_err!(bool);
1611try_from_u64_err!(f32);
1612try_from_u64_err!(f64);
1613try_from_u64_err!(Vec<u8>);
1614
1615#[cfg(feature = "with-json")]
1616try_from_u64_err!(serde_json::Value);
1617
1618#[cfg(feature = "with-chrono")]
1619try_from_u64_err!(chrono::NaiveDate);
1620
1621#[cfg(feature = "with-chrono")]
1622try_from_u64_err!(chrono::NaiveTime);
1623
1624#[cfg(feature = "with-chrono")]
1625try_from_u64_err!(chrono::NaiveDateTime);
1626
1627#[cfg(feature = "with-chrono")]
1628try_from_u64_err!(chrono::DateTime<chrono::FixedOffset>);
1629
1630#[cfg(feature = "with-chrono")]
1631try_from_u64_err!(chrono::DateTime<chrono::Utc>);
1632
1633#[cfg(feature = "with-chrono")]
1634try_from_u64_err!(chrono::DateTime<chrono::Local>);
1635
1636#[cfg(feature = "with-time")]
1637try_from_u64_err!(time::Date);
1638
1639#[cfg(feature = "with-time")]
1640try_from_u64_err!(time::Time);
1641
1642#[cfg(feature = "with-time")]
1643try_from_u64_err!(time::PrimitiveDateTime);
1644
1645#[cfg(feature = "with-time")]
1646try_from_u64_err!(time::OffsetDateTime);
1647
1648#[cfg(feature = "with-rust_decimal")]
1649try_from_u64_err!(rust_decimal::Decimal);
1650
1651#[cfg(feature = "with-uuid")]
1652try_from_u64_err!(uuid::Uuid);
1653
1654#[cfg(feature = "with-ipnetwork")]
1655try_from_u64_err!(ipnetwork::IpNetwork);
1656
1657#[cfg(feature = "with-mac_address")]
1658try_from_u64_err!(mac_address::MacAddress);
1659
1660#[cfg(test)]
1661mod tests {
1662 use super::*;
1663 use crate::RuntimeErr;
1664 use sea_query::Value;
1665 use std::collections::BTreeMap;
1666
1667 #[test]
1668 fn from_try_get_error() {
1669 let try_get_error = TryGetError::DbErr(DbErr::Query(RuntimeErr::Internal(
1671 "expected error message".to_owned(),
1672 )));
1673 assert_eq!(
1674 DbErr::from(try_get_error),
1675 DbErr::Query(RuntimeErr::Internal("expected error message".to_owned()))
1676 );
1677
1678 let try_get_error = TryGetError::Null("column".to_owned());
1680 let expected = "A null value was encountered while decoding column".to_owned();
1681 assert_eq!(DbErr::from(try_get_error), DbErr::Type(expected));
1682 }
1683
1684 #[test]
1685 fn build_with_query() {
1686 use sea_orm::{DbBackend, Statement};
1687 use sea_query::{
1688 ColumnRef, CommonTableExpression, Cycle, Expr, ExprTrait, JoinType, SelectStatement,
1689 UnionType, WithClause,
1690 };
1691
1692 let base_query = SelectStatement::new()
1693 .column("id")
1694 .expr(1i32)
1695 .column("next")
1696 .column("value")
1697 .from("table")
1698 .to_owned();
1699
1700 let cte_referencing = SelectStatement::new()
1701 .column("id")
1702 .expr(Expr::col("depth").add(1i32))
1703 .column("next")
1704 .column("value")
1705 .from("table")
1706 .join(
1707 JoinType::InnerJoin,
1708 "cte_traversal",
1709 Expr::col(("cte_traversal", "next")).equals(("table", "id")),
1710 )
1711 .to_owned();
1712
1713 let common_table_expression = CommonTableExpression::new()
1714 .query(
1715 base_query
1716 .clone()
1717 .union(UnionType::All, cte_referencing)
1718 .to_owned(),
1719 )
1720 .columns(["id", "depth", "next", "value"])
1721 .table_name("cte_traversal")
1722 .to_owned();
1723
1724 let select = SelectStatement::new()
1725 .column(ColumnRef::Asterisk(None))
1726 .from("cte_traversal")
1727 .to_owned();
1728
1729 let with_clause = WithClause::new()
1730 .recursive(true)
1731 .cte(common_table_expression)
1732 .cycle(Cycle::new_from_expr_set_using(
1733 Expr::column("id"),
1734 "looped",
1735 "traversal_path",
1736 ))
1737 .to_owned();
1738
1739 let with_query = select.with(with_clause).to_owned();
1740
1741 assert_eq!(
1742 DbBackend::MySql.build(&with_query),
1743 Statement::from_sql_and_values(
1744 DbBackend::MySql,
1745 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`",
1746 [1.into(), 1.into()]
1747 )
1748 );
1749 }
1750
1751 #[test]
1752 fn column_names_from_query_result() {
1753 let mut values = BTreeMap::new();
1754 values.insert("id".to_string(), Value::Int(Some(1)));
1755 values.insert("name".to_string(), Value::String(Some("Abc".to_owned())));
1756 let query_result = QueryResult {
1757 row: QueryResultRow::Mock(crate::MockRow { values }),
1758 };
1759 assert_eq!(
1760 query_result.column_names(),
1761 vec!["id".to_owned(), "name".to_owned()]
1762 );
1763 }
1764}