1use crate::error::EFResult;
7use async_trait::async_trait;
8use std::fmt;
9
10#[derive(Debug, Clone, PartialEq)]
20pub enum DbValue {
21 Null,
22 Bool(bool),
23 I16(i16),
24 I32(i32),
25 I64(i64),
26 F32(f32),
27 F64(f64),
28 String(String),
29 Bytes(Vec<u8>),
30 #[cfg(feature = "chrono")]
32 DateTime(chrono::DateTime<chrono::Utc>),
33 #[cfg(feature = "chrono")]
35 NaiveDateTime(chrono::NaiveDateTime),
36 #[cfg(feature = "chrono")]
38 NaiveDate(chrono::NaiveDate),
39 #[cfg(feature = "uuid")]
41 Uuid(uuid::Uuid),
42 #[cfg(feature = "decimal")]
46 Decimal(rust_decimal::Decimal),
47}
48
49impl fmt::Display for DbValue {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 match self {
52 DbValue::Null => write!(f, "NULL"),
53 DbValue::Bool(v) => write!(f, "{}", if *v { "TRUE" } else { "FALSE" }),
54 DbValue::I16(v) => write!(f, "{}", v),
55 DbValue::I32(v) => write!(f, "{}", v),
56 DbValue::I64(v) => write!(f, "{}", v),
57 DbValue::F32(v) => write!(f, "{}", v),
58 DbValue::F64(v) => write!(f, "{}", v),
59 DbValue::String(v) => write!(f, "'{}'", v.replace('\'', "''")),
60 DbValue::Bytes(v) => write!(f, "{}", hex::encode(v)),
61 #[cfg(feature = "chrono")]
62 DbValue::DateTime(v) => write!(f, "'{}'", v.to_rfc3339()),
63 #[cfg(feature = "chrono")]
64 DbValue::NaiveDateTime(v) => write!(f, "'{}'", v),
65 #[cfg(feature = "chrono")]
66 DbValue::NaiveDate(v) => write!(f, "'{}'", v),
67 #[cfg(feature = "uuid")]
68 DbValue::Uuid(v) => write!(f, "'{}'", v),
69 #[cfg(feature = "decimal")]
70 DbValue::Decimal(v) => write!(f, "'{}'", v),
71 }
72 }
73}
74
75mod hex {
76 pub fn encode(bytes: &[u8]) -> String {
77 bytes.iter().map(|b| format!("{:02x}", b)).collect()
78 }
79}
80
81impl From<i32> for DbValue {
82 fn from(v: i32) -> Self {
83 DbValue::I32(v)
84 }
85}
86impl From<&i32> for DbValue {
87 fn from(v: &i32) -> Self {
88 DbValue::I32(*v)
89 }
90}
91impl From<i64> for DbValue {
92 fn from(v: i64) -> Self {
93 DbValue::I64(v)
94 }
95}
96impl From<&i64> for DbValue {
97 fn from(v: &i64) -> Self {
98 DbValue::I64(*v)
99 }
100}
101impl From<String> for DbValue {
102 fn from(v: String) -> Self {
103 DbValue::String(v)
104 }
105}
106impl From<&str> for DbValue {
107 fn from(v: &str) -> Self {
108 DbValue::String(v.to_string())
109 }
110}
111impl From<bool> for DbValue {
112 fn from(v: bool) -> Self {
113 DbValue::Bool(v)
114 }
115}
116impl From<f64> for DbValue {
117 fn from(v: f64) -> Self {
118 DbValue::F64(v)
119 }
120}
121impl From<f32> for DbValue {
122 fn from(v: f32) -> Self {
123 DbValue::F32(v)
124 }
125}
126impl From<i16> for DbValue {
127 fn from(v: i16) -> Self {
128 DbValue::I16(v)
129 }
130}
131impl From<Vec<u8>> for DbValue {
132 fn from(v: Vec<u8>) -> Self {
133 DbValue::Bytes(v)
134 }
135}
136
137#[cfg(feature = "chrono")]
145impl From<chrono::DateTime<chrono::Utc>> for DbValue {
146 fn from(dt: chrono::DateTime<chrono::Utc>) -> Self {
147 DbValue::DateTime(dt)
148 }
149}
150
151#[cfg(feature = "chrono")]
152impl From<chrono::NaiveDateTime> for DbValue {
153 fn from(ndt: chrono::NaiveDateTime) -> Self {
154 DbValue::NaiveDateTime(ndt)
155 }
156}
157
158#[cfg(feature = "chrono")]
159impl From<chrono::NaiveDate> for DbValue {
160 fn from(nd: chrono::NaiveDate) -> Self {
161 DbValue::NaiveDate(nd)
162 }
163}
164
165#[cfg(feature = "uuid")]
166impl From<uuid::Uuid> for DbValue {
167 fn from(u: uuid::Uuid) -> Self {
168 DbValue::Uuid(u)
169 }
170}
171
172#[cfg(feature = "decimal")]
173impl From<rust_decimal::Decimal> for DbValue {
174 fn from(d: rust_decimal::Decimal) -> Self {
175 DbValue::Decimal(d)
176 }
177}
178impl<T> From<Option<T>> for DbValue
179where
180 T: Into<DbValue>,
181{
182 fn from(v: Option<T>) -> Self {
183 match v {
184 Some(val) => val.into(),
185 None => DbValue::Null,
186 }
187 }
188}
189
190#[derive(Debug, Clone, PartialEq)]
196pub struct DbValueConvertError {
197 pub source: DbValue,
199 pub target_type: &'static str,
201}
202
203impl fmt::Display for DbValueConvertError {
204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205 write!(
206 f,
207 "cannot convert {:?} to {}",
208 self.source, self.target_type
209 )
210 }
211}
212
213impl std::error::Error for DbValueConvertError {}
214
215impl From<DbValueConvertError> for crate::error::EFError {
216 fn from(e: DbValueConvertError) -> Self {
217 crate::error::EFError::type_conversion(e.to_string())
218 }
219}
220
221impl TryFrom<DbValue> for i32 {
222 type Error = DbValueConvertError;
223 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
224 match v {
225 DbValue::I32(n) => Ok(n),
226 DbValue::I16(n) => Ok(n as i32),
227 DbValue::I64(n) => n.try_into().map_err(|_| DbValueConvertError {
228 source: DbValue::I64(n),
229 target_type: "i32",
230 }),
231 DbValue::String(s) => s.parse().map_err(|_| DbValueConvertError {
232 source: DbValue::String(s),
233 target_type: "i32",
234 }),
235 other => Err(DbValueConvertError {
236 source: other,
237 target_type: "i32",
238 }),
239 }
240 }
241}
242
243impl TryFrom<DbValue> for i64 {
244 type Error = DbValueConvertError;
245 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
246 match v {
247 DbValue::I64(n) => Ok(n),
248 DbValue::I32(n) => Ok(n as i64),
249 DbValue::I16(n) => Ok(n as i64),
250 DbValue::String(s) => s.parse().map_err(|_| DbValueConvertError {
251 source: DbValue::String(s),
252 target_type: "i64",
253 }),
254 other => Err(DbValueConvertError {
255 source: other,
256 target_type: "i64",
257 }),
258 }
259 }
260}
261
262impl TryFrom<DbValue> for f64 {
263 type Error = DbValueConvertError;
264 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
265 match v {
266 DbValue::F64(x) => Ok(x),
267 DbValue::F32(x) => Ok(x as f64),
268 DbValue::I32(n) => Ok(n as f64),
269 DbValue::I64(n) => Ok(n as f64),
270 DbValue::I16(n) => Ok(n as f64),
271 DbValue::String(s) => s.parse().map_err(|_| DbValueConvertError {
272 source: DbValue::String(s),
273 target_type: "f64",
274 }),
275 other => Err(DbValueConvertError {
276 source: other,
277 target_type: "f64",
278 }),
279 }
280 }
281}
282
283impl TryFrom<DbValue> for f32 {
284 type Error = DbValueConvertError;
285 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
286 match v {
287 DbValue::F32(x) => Ok(x),
288 DbValue::F64(x) => Ok(x as f32),
289 DbValue::I32(n) => Ok(n as f32),
290 DbValue::I64(n) => Ok(n as f32),
291 DbValue::I16(n) => Ok(n as f32),
292 DbValue::String(s) => s.parse().map_err(|_| DbValueConvertError {
293 source: DbValue::String(s),
294 target_type: "f32",
295 }),
296 other => Err(DbValueConvertError {
297 source: other,
298 target_type: "f32",
299 }),
300 }
301 }
302}
303
304impl TryFrom<DbValue> for String {
305 type Error = DbValueConvertError;
306 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
307 match v {
308 DbValue::String(s) => Ok(s),
309 DbValue::Bool(b) => Ok(b.to_string()),
310 DbValue::I16(n) => Ok(n.to_string()),
311 DbValue::I32(n) => Ok(n.to_string()),
312 DbValue::I64(n) => Ok(n.to_string()),
313 DbValue::F32(x) => Ok(x.to_string()),
314 DbValue::F64(x) => Ok(x.to_string()),
315 #[cfg(feature = "chrono")]
316 DbValue::DateTime(dt) => Ok(dt.to_rfc3339()),
317 #[cfg(feature = "chrono")]
318 DbValue::NaiveDateTime(ndt) => Ok(ndt.to_string()),
319 #[cfg(feature = "chrono")]
320 DbValue::NaiveDate(nd) => Ok(nd.to_string()),
321 #[cfg(feature = "uuid")]
322 DbValue::Uuid(u) => Ok(u.to_string()),
323 #[cfg(feature = "decimal")]
324 DbValue::Decimal(d) => Ok(d.to_string()),
325 other => Err(DbValueConvertError {
326 source: other,
327 target_type: "String",
328 }),
329 }
330 }
331}
332
333impl TryFrom<DbValue> for bool {
334 type Error = DbValueConvertError;
335 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
336 match v {
337 DbValue::Bool(b) => Ok(b),
338 DbValue::I64(n) => Ok(n != 0),
339 DbValue::I32(n) => Ok(n != 0),
340 DbValue::I16(n) => Ok(n != 0),
341 DbValue::String(s) => {
342 let lower = s.to_ascii_lowercase();
343 match lower.as_str() {
344 "true" | "t" | "1" => Ok(true),
345 "false" | "f" | "0" => Ok(false),
346 _ => Err(DbValueConvertError {
347 source: DbValue::String(s),
348 target_type: "bool",
349 }),
350 }
351 }
352 other => Err(DbValueConvertError {
353 source: other,
354 target_type: "bool",
355 }),
356 }
357 }
358}
359
360impl TryFrom<DbValue> for Vec<u8> {
361 type Error = DbValueConvertError;
362 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
363 match v {
364 DbValue::Bytes(b) => Ok(b),
365 other => Err(DbValueConvertError {
366 source: other,
367 target_type: "Vec<u8>",
368 }),
369 }
370 }
371}
372
373impl TryFrom<DbValue> for i16 {
374 type Error = DbValueConvertError;
375 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
376 match v {
377 DbValue::I16(n) => Ok(n),
378 DbValue::I32(n) => n.try_into().map_err(|_| DbValueConvertError {
379 source: DbValue::I32(n),
380 target_type: "i16",
381 }),
382 DbValue::I64(n) => n.try_into().map_err(|_| DbValueConvertError {
383 source: DbValue::I64(n),
384 target_type: "i16",
385 }),
386 DbValue::String(s) => s.parse().map_err(|_| DbValueConvertError {
387 source: DbValue::String(s),
388 target_type: "i16",
389 }),
390 other => Err(DbValueConvertError {
391 source: other,
392 target_type: "i16",
393 }),
394 }
395 }
396}
397
398impl TryFrom<DbValue> for i8 {
399 type Error = DbValueConvertError;
400 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
401 match v {
402 DbValue::I16(n) => n.try_into().map_err(|_| DbValueConvertError {
403 source: DbValue::I16(n),
404 target_type: "i8",
405 }),
406 DbValue::I32(n) => n.try_into().map_err(|_| DbValueConvertError {
407 source: DbValue::I32(n),
408 target_type: "i8",
409 }),
410 DbValue::I64(n) => n.try_into().map_err(|_| DbValueConvertError {
411 source: DbValue::I64(n),
412 target_type: "i8",
413 }),
414 DbValue::String(s) => s.parse().map_err(|_| DbValueConvertError {
415 source: DbValue::String(s),
416 target_type: "i8",
417 }),
418 other => Err(DbValueConvertError {
419 source: other,
420 target_type: "i8",
421 }),
422 }
423 }
424}
425
426impl TryFrom<DbValue> for u32 {
427 type Error = DbValueConvertError;
428 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
429 match v {
430 DbValue::I16(n) => (n as i32).try_into().map_err(|_| DbValueConvertError {
431 source: DbValue::I16(n),
432 target_type: "u32",
433 }),
434 DbValue::I32(n) => n.try_into().map_err(|_| DbValueConvertError {
435 source: DbValue::I32(n),
436 target_type: "u32",
437 }),
438 DbValue::I64(n) => n.try_into().map_err(|_| DbValueConvertError {
439 source: DbValue::I64(n),
440 target_type: "u32",
441 }),
442 DbValue::String(s) => s.parse().map_err(|_| DbValueConvertError {
443 source: DbValue::String(s),
444 target_type: "u32",
445 }),
446 other => Err(DbValueConvertError {
447 source: other,
448 target_type: "u32",
449 }),
450 }
451 }
452}
453
454impl TryFrom<DbValue> for u64 {
455 type Error = DbValueConvertError;
456 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
457 match v {
458 DbValue::I16(n) => (n as i64).try_into().map_err(|_| DbValueConvertError {
459 source: DbValue::I16(n),
460 target_type: "u64",
461 }),
462 DbValue::I32(n) => (n as i64).try_into().map_err(|_| DbValueConvertError {
463 source: DbValue::I32(n),
464 target_type: "u64",
465 }),
466 DbValue::I64(n) => n.try_into().map_err(|_| DbValueConvertError {
467 source: DbValue::I64(n),
468 target_type: "u64",
469 }),
470 DbValue::String(s) => s.parse().map_err(|_| DbValueConvertError {
471 source: DbValue::String(s),
472 target_type: "u64",
473 }),
474 other => Err(DbValueConvertError {
475 source: other,
476 target_type: "u64",
477 }),
478 }
479 }
480}
481
482#[cfg(feature = "chrono")]
485impl TryFrom<DbValue> for chrono::DateTime<chrono::Utc> {
486 type Error = DbValueConvertError;
487 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
488 match v {
489 DbValue::DateTime(dt) => Ok(dt),
490 DbValue::String(s) => chrono::DateTime::parse_from_rfc3339(&s)
491 .map(|dt| dt.with_timezone(&chrono::Utc))
492 .map_err(|_| DbValueConvertError {
493 source: DbValue::String(s),
494 target_type: "DateTime<Utc>",
495 }),
496 other => Err(DbValueConvertError {
497 source: other,
498 target_type: "DateTime<Utc>",
499 }),
500 }
501 }
502}
503
504#[cfg(feature = "chrono")]
505impl TryFrom<DbValue> for chrono::NaiveDateTime {
506 type Error = DbValueConvertError;
507 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
508 match v {
509 DbValue::NaiveDateTime(ndt) => Ok(ndt),
510 DbValue::String(s) => {
511 chrono::NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S")
512 .or_else(|_| {
513 chrono::NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S")
515 })
516 .map_err(|_| DbValueConvertError {
517 source: DbValue::String(s),
518 target_type: "NaiveDateTime",
519 })
520 }
521 other => Err(DbValueConvertError {
522 source: other,
523 target_type: "NaiveDateTime",
524 }),
525 }
526 }
527}
528
529#[cfg(feature = "chrono")]
530impl TryFrom<DbValue> for chrono::NaiveDate {
531 type Error = DbValueConvertError;
532 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
533 match v {
534 DbValue::NaiveDate(nd) => Ok(nd),
535 DbValue::String(s) => {
536 chrono::NaiveDate::parse_from_str(&s, "%Y-%m-%d").map_err(|_| DbValueConvertError {
537 source: DbValue::String(s),
538 target_type: "NaiveDate",
539 })
540 }
541 other => Err(DbValueConvertError {
542 source: other,
543 target_type: "NaiveDate",
544 }),
545 }
546 }
547}
548
549#[cfg(feature = "uuid")]
550impl TryFrom<DbValue> for uuid::Uuid {
551 type Error = DbValueConvertError;
552 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
553 match v {
554 DbValue::Uuid(u) => Ok(u),
555 DbValue::String(s) => uuid::Uuid::parse_str(&s).map_err(|_| DbValueConvertError {
556 source: DbValue::String(s),
557 target_type: "Uuid",
558 }),
559 other => Err(DbValueConvertError {
560 source: other,
561 target_type: "Uuid",
562 }),
563 }
564 }
565}
566
567#[cfg(feature = "decimal")]
568impl TryFrom<DbValue> for rust_decimal::Decimal {
569 type Error = DbValueConvertError;
570 fn try_from(v: DbValue) -> Result<Self, Self::Error> {
571 match v {
572 DbValue::Decimal(d) => Ok(d),
573 DbValue::String(s) => s.parse().map_err(|_| DbValueConvertError {
574 source: DbValue::String(s),
575 target_type: "Decimal",
576 }),
577 DbValue::I32(n) => Ok(rust_decimal::Decimal::from(n)),
578 DbValue::I64(n) => Ok(rust_decimal::Decimal::from(n)),
579 other => Err(DbValueConvertError {
580 source: other,
581 target_type: "Decimal",
582 }),
583 }
584 }
585}
586
587pub trait ISqlGenerator: Send + Sync {
589 fn select(&self, table: &str, columns: &[&str]) -> String;
591 fn insert(&self, table: &str, columns: &[&str], returning: bool) -> String;
593 fn insert_batch(&self, table: &str, columns: &[&str], row_count: usize) -> String {
597 let _ = (table, columns, row_count);
598 String::new()
599 }
600 fn update(&self, table: &str, set_columns: &[&str], where_clause: &str) -> String;
602 fn delete(&self, table: &str, where_clause: &str) -> String;
604 fn create_table(&self, table: &str, columns: &[(String, String)]) -> String;
606 fn drop_table(&self, table: &str) -> String;
608 fn pagination(&self, skip: Option<usize>, take: Option<usize>) -> String;
610 fn parameter_placeholder(&self, index: usize) -> String;
612 fn quote_identifier(&self, identifier: &str) -> String;
614 fn auto_increment_syntax(&self) -> &'static str;
616}
617
618#[derive(Debug, Clone, Copy, PartialEq, Eq)]
620pub enum IsolationLevel {
621 ReadUncommitted,
622 ReadCommitted,
623 RepeatableRead,
624 Serializable,
625}
626
627#[async_trait]
629pub trait IAsyncConnection: Send + Sync {
630 async fn execute(&mut self, sql: &str, params: &[DbValue]) -> EFResult<u64>;
632 async fn query(&mut self, sql: &str, params: &[DbValue]) -> EFResult<Vec<Vec<DbValue>>>;
634 async fn begin_transaction(&mut self) -> EFResult<()>;
636 async fn commit_transaction(&mut self) -> EFResult<()>;
638 async fn rollback_transaction(&mut self) -> EFResult<()>;
640 async fn create_savepoint(&mut self, name: &str) -> EFResult<()>;
642 async fn release_savepoint(&mut self, name: &str) -> EFResult<()>;
644 async fn rollback_to_savepoint(&mut self, name: &str) -> EFResult<()>;
646 async fn set_transaction_isolation(&mut self, level: IsolationLevel) -> EFResult<()>;
649
650 #[cfg(feature = "tracing")]
656 fn set_slow_query_threshold(&mut self, _threshold: std::time::Duration) {}
657}
658
659#[async_trait]
662pub trait IDatabaseProvider: Send + Sync {
663 fn sql_generator(&self) -> &'static dyn ISqlGenerator;
668
669 async fn get_connection(&self) -> EFResult<Box<dyn IAsyncConnection>>;
671
672 async fn execute_migration_command(&self, sql: &str) -> EFResult<()>;
674
675 fn name(&self) -> &str;
677
678 fn migration_dialect(&self) -> crate::migration::MigrationDialect;
680
681 #[cfg(feature = "tracing")]
687 fn set_slow_query_threshold(&self, _threshold: std::time::Duration) {}
688}