1use std::fmt;
28use std::ops::Deref;
29
30#[cfg(all(feature = "sqlx-0_8", feature = "sqlx-0_9"))]
31compile_error!("Enable exactly one SQLx version feature: `sqlx-0_8` or `sqlx-0_9`.");
32#[cfg(not(any(feature = "sqlx-0_8", feature = "sqlx-0_9")))]
33compile_error!("Enable one SQLx version feature: `sqlx-0_8` or `sqlx-0_9`.");
34
35#[cfg(feature = "sqlx-0_8")]
36use sqlx08 as sqlx;
37#[cfg(feature = "sqlx-0_9")]
38use sqlx09 as sqlx;
39
40pub use vld;
41
42#[cfg(feature = "sqlx-0_8")]
43type SqlxArgBuf<'q, DB> = <DB as sqlx::Database>::ArgumentBuffer<'q>;
44#[cfg(feature = "sqlx-0_9")]
45type SqlxArgBuf<'q, DB> = <DB as sqlx::Database>::ArgumentBuffer;
46
47#[derive(Debug, Clone)]
51pub enum VldSqlxError {
52 Validation(vld::error::VldError),
54 Serialization(String),
56}
57
58impl fmt::Display for VldSqlxError {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 match self {
61 VldSqlxError::Validation(e) => write!(f, "Validation error: {}", e),
62 VldSqlxError::Serialization(e) => write!(f, "Serialization error: {}", e),
63 }
64 }
65}
66
67impl std::error::Error for VldSqlxError {
68 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
69 match self {
70 VldSqlxError::Validation(e) => Some(e),
71 VldSqlxError::Serialization(_) => None,
72 }
73 }
74}
75
76impl From<vld::error::VldError> for VldSqlxError {
77 fn from(e: vld::error::VldError) -> Self {
78 VldSqlxError::Validation(e)
79 }
80}
81
82impl From<VldSqlxError> for sqlx::Error {
83 fn from(e: VldSqlxError) -> Self {
84 sqlx::Error::Protocol(e.to_string())
85 }
86}
87
88pub struct Validated<S, T> {
115 inner: T,
116 _schema: std::marker::PhantomData<S>,
117}
118
119impl<S, T> Validated<S, T>
120where
121 S: vld::schema::VldParse,
122 T: serde::Serialize,
123{
124 pub fn new(value: T) -> Result<Self, VldSqlxError> {
126 let json =
127 serde_json::to_value(&value).map_err(|e| VldSqlxError::Serialization(e.to_string()))?;
128 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
129 Ok(Self {
130 inner: value,
131 _schema: std::marker::PhantomData,
132 })
133 }
134
135 pub fn inner(&self) -> &T {
137 &self.inner
138 }
139
140 pub fn into_inner(self) -> T {
142 self.inner
143 }
144}
145
146impl<S, T> Deref for Validated<S, T> {
147 type Target = T;
148 fn deref(&self) -> &T {
149 &self.inner
150 }
151}
152
153impl<S, T: fmt::Debug> fmt::Debug for Validated<S, T> {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 f.debug_struct("Validated")
156 .field("inner", &self.inner)
157 .finish()
158 }
159}
160
161impl<S, T: Clone> Clone for Validated<S, T> {
162 fn clone(&self) -> Self {
163 Self {
164 inner: self.inner.clone(),
165 _schema: std::marker::PhantomData,
166 }
167 }
168}
169
170pub fn validate_insert<S, T>(value: &T) -> Result<(), VldSqlxError>
192where
193 S: vld::schema::VldParse,
194 T: serde::Serialize,
195{
196 let json =
197 serde_json::to_value(value).map_err(|e| VldSqlxError::Serialization(e.to_string()))?;
198 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
199 Ok(())
200}
201
202pub fn validate_update<S, T>(value: &T) -> Result<(), VldSqlxError>
204where
205 S: vld::schema::VldParse,
206 T: serde::Serialize,
207{
208 validate_insert::<S, T>(value)
209}
210
211pub fn validate_row<S, T>(value: &T) -> Result<(), VldSqlxError>
216where
217 S: vld::schema::VldParse,
218 T: serde::Serialize,
219{
220 validate_insert::<S, T>(value)
221}
222
223pub fn validate_rows<S, T>(rows: &[T]) -> Result<(), (usize, VldSqlxError)>
247where
248 S: vld::schema::VldParse,
249 T: serde::Serialize,
250{
251 for (i, row) in rows.iter().enumerate() {
252 validate_row::<S, T>(row).map_err(|e| (i, e))?;
253 }
254 Ok(())
255}
256
257pub struct VldText<S> {
283 value: String,
284 _schema: std::marker::PhantomData<S>,
285}
286
287impl<S> Clone for VldText<S> {
288 fn clone(&self) -> Self {
289 Self {
290 value: self.value.clone(),
291 _schema: std::marker::PhantomData,
292 }
293 }
294}
295
296impl<S> PartialEq for VldText<S> {
297 fn eq(&self, other: &Self) -> bool {
298 self.value == other.value
299 }
300}
301impl<S> Eq for VldText<S> {}
302
303impl<S> PartialOrd for VldText<S> {
304 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
305 Some(self.cmp(other))
306 }
307}
308impl<S> Ord for VldText<S> {
309 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
310 self.value.cmp(&other.value)
311 }
312}
313
314impl<S> std::hash::Hash for VldText<S> {
315 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
316 self.value.hash(state);
317 }
318}
319
320impl<S: vld::schema::VldParse> VldText<S> {
321 pub fn new(input: impl Into<String>) -> Result<Self, VldSqlxError> {
325 let s = input.into();
326 let json = serde_json::json!({ "value": s });
327 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
328 Ok(Self {
329 value: s,
330 _schema: std::marker::PhantomData,
331 })
332 }
333
334 pub fn new_unchecked(input: impl Into<String>) -> Self {
336 Self {
337 value: input.into(),
338 _schema: std::marker::PhantomData,
339 }
340 }
341
342 pub fn as_str(&self) -> &str {
344 &self.value
345 }
346
347 pub fn into_inner(self) -> String {
349 self.value
350 }
351}
352
353impl<S> Deref for VldText<S> {
354 type Target = str;
355 fn deref(&self) -> &str {
356 &self.value
357 }
358}
359
360impl<S> AsRef<str> for VldText<S> {
361 fn as_ref(&self) -> &str {
362 &self.value
363 }
364}
365
366impl<S> fmt::Debug for VldText<S> {
367 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368 write!(f, "VldText({:?})", self.value)
369 }
370}
371
372impl<S> fmt::Display for VldText<S> {
373 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374 f.write_str(&self.value)
375 }
376}
377
378impl<S> serde::Serialize for VldText<S> {
379 fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
380 self.value.serialize(serializer)
381 }
382}
383
384impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldText<S> {
385 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
386 let s = String::deserialize(deserializer)?;
387 VldText::<S>::new(&s).map_err(serde::de::Error::custom)
388 }
389}
390
391impl<S, DB: sqlx::Database> sqlx::Type<DB> for VldText<S>
393where
394 String: sqlx::Type<DB>,
395{
396 fn type_info() -> DB::TypeInfo {
397 <String as sqlx::Type<DB>>::type_info()
398 }
399
400 fn compatible(ty: &DB::TypeInfo) -> bool {
401 <String as sqlx::Type<DB>>::compatible(ty)
402 }
403}
404
405impl<'q, S, DB: sqlx::Database> sqlx::Encode<'q, DB> for VldText<S>
407where
408 String: sqlx::Encode<'q, DB>,
409{
410 fn encode_by_ref(
411 &self,
412 buf: &mut SqlxArgBuf<'q, DB>,
413 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
414 self.value.encode_by_ref(buf)
415 }
416}
417
418impl<'r, S: vld::schema::VldParse, DB: sqlx::Database> sqlx::Decode<'r, DB> for VldText<S>
420where
421 String: sqlx::Decode<'r, DB>,
422{
423 fn decode(
424 value: <DB as sqlx::Database>::ValueRef<'r>,
425 ) -> Result<Self, sqlx::error::BoxDynError> {
426 let s = <String as sqlx::Decode<'r, DB>>::decode(value)?;
427 Ok(Self::new_unchecked(s))
428 }
429}
430
431pub struct VldInt<S> {
457 value: i64,
458 _schema: std::marker::PhantomData<S>,
459}
460
461impl<S> Clone for VldInt<S> {
462 fn clone(&self) -> Self {
463 *self
464 }
465}
466impl<S> Copy for VldInt<S> {}
467
468impl<S> PartialEq for VldInt<S> {
469 fn eq(&self, other: &Self) -> bool {
470 self.value == other.value
471 }
472}
473impl<S> Eq for VldInt<S> {}
474
475impl<S> PartialOrd for VldInt<S> {
476 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
477 Some(self.cmp(other))
478 }
479}
480impl<S> Ord for VldInt<S> {
481 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
482 self.value.cmp(&other.value)
483 }
484}
485
486impl<S> std::hash::Hash for VldInt<S> {
487 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
488 self.value.hash(state);
489 }
490}
491
492impl<S: vld::schema::VldParse> VldInt<S> {
493 pub fn new(input: i64) -> Result<Self, VldSqlxError> {
495 let json = serde_json::json!({ "value": input });
496 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
497 Ok(Self {
498 value: input,
499 _schema: std::marker::PhantomData,
500 })
501 }
502
503 pub fn new_unchecked(input: i64) -> Self {
505 Self {
506 value: input,
507 _schema: std::marker::PhantomData,
508 }
509 }
510
511 pub fn get(&self) -> i64 {
513 self.value
514 }
515}
516
517impl<S> Deref for VldInt<S> {
518 type Target = i64;
519 fn deref(&self) -> &i64 {
520 &self.value
521 }
522}
523
524impl<S> fmt::Debug for VldInt<S> {
525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526 write!(f, "VldInt({})", self.value)
527 }
528}
529
530impl<S> fmt::Display for VldInt<S> {
531 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
532 write!(f, "{}", self.value)
533 }
534}
535
536impl<S> serde::Serialize for VldInt<S> {
537 fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
538 self.value.serialize(serializer)
539 }
540}
541
542impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldInt<S> {
543 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
544 let v = i64::deserialize(deserializer)?;
545 VldInt::<S>::new(v).map_err(serde::de::Error::custom)
546 }
547}
548
549impl<S, DB: sqlx::Database> sqlx::Type<DB> for VldInt<S>
551where
552 i64: sqlx::Type<DB>,
553{
554 fn type_info() -> DB::TypeInfo {
555 <i64 as sqlx::Type<DB>>::type_info()
556 }
557
558 fn compatible(ty: &DB::TypeInfo) -> bool {
559 <i64 as sqlx::Type<DB>>::compatible(ty)
560 }
561}
562
563impl<'q, S, DB: sqlx::Database> sqlx::Encode<'q, DB> for VldInt<S>
565where
566 i64: sqlx::Encode<'q, DB>,
567{
568 fn encode_by_ref(
569 &self,
570 buf: &mut SqlxArgBuf<'q, DB>,
571 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
572 self.value.encode_by_ref(buf)
573 }
574}
575
576impl<'r, S: vld::schema::VldParse, DB: sqlx::Database> sqlx::Decode<'r, DB> for VldInt<S>
578where
579 i64: sqlx::Decode<'r, DB>,
580{
581 fn decode(
582 value: <DB as sqlx::Database>::ValueRef<'r>,
583 ) -> Result<Self, sqlx::error::BoxDynError> {
584 let v = <i64 as sqlx::Decode<'r, DB>>::decode(value)?;
585 Ok(Self::new_unchecked(v))
586 }
587}
588
589pub struct VldBool<S> {
612 value: bool,
613 _schema: std::marker::PhantomData<S>,
614}
615
616impl<S> Clone for VldBool<S> {
617 fn clone(&self) -> Self {
618 *self
619 }
620}
621impl<S> Copy for VldBool<S> {}
622
623impl<S> PartialEq for VldBool<S> {
624 fn eq(&self, other: &Self) -> bool {
625 self.value == other.value
626 }
627}
628impl<S> Eq for VldBool<S> {}
629
630impl<S: vld::schema::VldParse> VldBool<S> {
631 pub fn new(input: bool) -> Result<Self, VldSqlxError> {
633 let json = serde_json::json!({ "value": input });
634 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
635 Ok(Self {
636 value: input,
637 _schema: std::marker::PhantomData,
638 })
639 }
640
641 pub fn new_unchecked(input: bool) -> Self {
643 Self {
644 value: input,
645 _schema: std::marker::PhantomData,
646 }
647 }
648
649 pub fn get(&self) -> bool {
651 self.value
652 }
653}
654
655impl<S> Deref for VldBool<S> {
656 type Target = bool;
657 fn deref(&self) -> &bool {
658 &self.value
659 }
660}
661
662impl<S> fmt::Debug for VldBool<S> {
663 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
664 write!(f, "VldBool({})", self.value)
665 }
666}
667
668impl<S> fmt::Display for VldBool<S> {
669 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
670 write!(f, "{}", self.value)
671 }
672}
673
674impl<S> serde::Serialize for VldBool<S> {
675 fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
676 self.value.serialize(serializer)
677 }
678}
679
680impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldBool<S> {
681 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
682 let v = bool::deserialize(deserializer)?;
683 VldBool::<S>::new(v).map_err(serde::de::Error::custom)
684 }
685}
686
687impl<S, DB: sqlx::Database> sqlx::Type<DB> for VldBool<S>
689where
690 bool: sqlx::Type<DB>,
691{
692 fn type_info() -> DB::TypeInfo {
693 <bool as sqlx::Type<DB>>::type_info()
694 }
695
696 fn compatible(ty: &DB::TypeInfo) -> bool {
697 <bool as sqlx::Type<DB>>::compatible(ty)
698 }
699}
700
701impl<'q, S, DB: sqlx::Database> sqlx::Encode<'q, DB> for VldBool<S>
702where
703 bool: sqlx::Encode<'q, DB>,
704{
705 fn encode_by_ref(
706 &self,
707 buf: &mut SqlxArgBuf<'q, DB>,
708 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
709 self.value.encode_by_ref(buf)
710 }
711}
712
713impl<'r, S: vld::schema::VldParse, DB: sqlx::Database> sqlx::Decode<'r, DB> for VldBool<S>
714where
715 bool: sqlx::Decode<'r, DB>,
716{
717 fn decode(
718 value: <DB as sqlx::Database>::ValueRef<'r>,
719 ) -> Result<Self, sqlx::error::BoxDynError> {
720 let v = <bool as sqlx::Decode<'r, DB>>::decode(value)?;
721 Ok(Self::new_unchecked(v))
722 }
723}
724
725pub struct VldFloat<S> {
748 value: f64,
749 _schema: std::marker::PhantomData<S>,
750}
751
752impl<S> Clone for VldFloat<S> {
753 fn clone(&self) -> Self {
754 *self
755 }
756}
757impl<S> Copy for VldFloat<S> {}
758
759impl<S> PartialEq for VldFloat<S> {
760 fn eq(&self, other: &Self) -> bool {
761 self.value == other.value
762 }
763}
764
765impl<S: vld::schema::VldParse> VldFloat<S> {
766 pub fn new(input: f64) -> Result<Self, VldSqlxError> {
768 let json = serde_json::json!({ "value": input });
769 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
770 Ok(Self {
771 value: input,
772 _schema: std::marker::PhantomData,
773 })
774 }
775
776 pub fn new_unchecked(input: f64) -> Self {
778 Self {
779 value: input,
780 _schema: std::marker::PhantomData,
781 }
782 }
783
784 pub fn get(&self) -> f64 {
786 self.value
787 }
788}
789
790impl<S> Deref for VldFloat<S> {
791 type Target = f64;
792 fn deref(&self) -> &f64 {
793 &self.value
794 }
795}
796
797impl<S> fmt::Debug for VldFloat<S> {
798 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
799 write!(f, "VldFloat({})", self.value)
800 }
801}
802
803impl<S> fmt::Display for VldFloat<S> {
804 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
805 write!(f, "{}", self.value)
806 }
807}
808
809impl<S> serde::Serialize for VldFloat<S> {
810 fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
811 self.value.serialize(serializer)
812 }
813}
814
815impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldFloat<S> {
816 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
817 let v = f64::deserialize(deserializer)?;
818 VldFloat::<S>::new(v).map_err(serde::de::Error::custom)
819 }
820}
821
822impl<S, DB: sqlx::Database> sqlx::Type<DB> for VldFloat<S>
824where
825 f64: sqlx::Type<DB>,
826{
827 fn type_info() -> DB::TypeInfo {
828 <f64 as sqlx::Type<DB>>::type_info()
829 }
830
831 fn compatible(ty: &DB::TypeInfo) -> bool {
832 <f64 as sqlx::Type<DB>>::compatible(ty)
833 }
834}
835
836impl<'q, S, DB: sqlx::Database> sqlx::Encode<'q, DB> for VldFloat<S>
837where
838 f64: sqlx::Encode<'q, DB>,
839{
840 fn encode_by_ref(
841 &self,
842 buf: &mut SqlxArgBuf<'q, DB>,
843 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
844 self.value.encode_by_ref(buf)
845 }
846}
847
848impl<'r, S: vld::schema::VldParse, DB: sqlx::Database> sqlx::Decode<'r, DB> for VldFloat<S>
849where
850 f64: sqlx::Decode<'r, DB>,
851{
852 fn decode(
853 value: <DB as sqlx::Database>::ValueRef<'r>,
854 ) -> Result<Self, sqlx::error::BoxDynError> {
855 let v = <f64 as sqlx::Decode<'r, DB>>::decode(value)?;
856 Ok(Self::new_unchecked(v))
857 }
858}
859
860pub mod prelude {
863 pub use crate::{
864 validate_insert, validate_row, validate_rows, validate_update, Validated, VldBool,
865 VldFloat, VldInt, VldSqlxError, VldText,
866 };
867 pub use vld::prelude::*;
868}