1use std::fmt;
28use std::ops::Deref;
29
30pub use vld;
31
32#[derive(Debug, Clone)]
36pub enum VldSqlxError {
37 Validation(vld::error::VldError),
39 Serialization(String),
41}
42
43impl fmt::Display for VldSqlxError {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 match self {
46 VldSqlxError::Validation(e) => write!(f, "Validation error: {}", e),
47 VldSqlxError::Serialization(e) => write!(f, "Serialization error: {}", e),
48 }
49 }
50}
51
52impl std::error::Error for VldSqlxError {
53 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
54 match self {
55 VldSqlxError::Validation(e) => Some(e),
56 VldSqlxError::Serialization(_) => None,
57 }
58 }
59}
60
61impl From<vld::error::VldError> for VldSqlxError {
62 fn from(e: vld::error::VldError) -> Self {
63 VldSqlxError::Validation(e)
64 }
65}
66
67impl From<VldSqlxError> for sqlx::Error {
68 fn from(e: VldSqlxError) -> Self {
69 sqlx::Error::Protocol(e.to_string())
70 }
71}
72
73pub struct Validated<S, T> {
100 inner: T,
101 _schema: std::marker::PhantomData<S>,
102}
103
104impl<S, T> Validated<S, T>
105where
106 S: vld::schema::VldParse,
107 T: serde::Serialize,
108{
109 pub fn new(value: T) -> Result<Self, VldSqlxError> {
111 let json = serde_json::to_value(&value)
112 .map_err(|e| VldSqlxError::Serialization(e.to_string()))?;
113 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
114 Ok(Self {
115 inner: value,
116 _schema: std::marker::PhantomData,
117 })
118 }
119
120 pub fn inner(&self) -> &T {
122 &self.inner
123 }
124
125 pub fn into_inner(self) -> T {
127 self.inner
128 }
129}
130
131impl<S, T> Deref for Validated<S, T> {
132 type Target = T;
133 fn deref(&self) -> &T {
134 &self.inner
135 }
136}
137
138impl<S, T: fmt::Debug> fmt::Debug for Validated<S, T> {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 f.debug_struct("Validated")
141 .field("inner", &self.inner)
142 .finish()
143 }
144}
145
146impl<S, T: Clone> Clone for Validated<S, T> {
147 fn clone(&self) -> Self {
148 Self {
149 inner: self.inner.clone(),
150 _schema: std::marker::PhantomData,
151 }
152 }
153}
154
155pub fn validate_insert<S, T>(value: &T) -> Result<(), VldSqlxError>
177where
178 S: vld::schema::VldParse,
179 T: serde::Serialize,
180{
181 let json =
182 serde_json::to_value(value).map_err(|e| VldSqlxError::Serialization(e.to_string()))?;
183 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
184 Ok(())
185}
186
187pub fn validate_update<S, T>(value: &T) -> Result<(), VldSqlxError>
189where
190 S: vld::schema::VldParse,
191 T: serde::Serialize,
192{
193 validate_insert::<S, T>(value)
194}
195
196pub fn validate_row<S, T>(value: &T) -> Result<(), VldSqlxError>
201where
202 S: vld::schema::VldParse,
203 T: serde::Serialize,
204{
205 validate_insert::<S, T>(value)
206}
207
208pub fn validate_rows<S, T>(rows: &[T]) -> Result<(), (usize, VldSqlxError)>
232where
233 S: vld::schema::VldParse,
234 T: serde::Serialize,
235{
236 for (i, row) in rows.iter().enumerate() {
237 validate_row::<S, T>(row).map_err(|e| (i, e))?;
238 }
239 Ok(())
240}
241
242pub struct VldText<S> {
268 value: String,
269 _schema: std::marker::PhantomData<S>,
270}
271
272impl<S> Clone for VldText<S> {
273 fn clone(&self) -> Self {
274 Self {
275 value: self.value.clone(),
276 _schema: std::marker::PhantomData,
277 }
278 }
279}
280
281impl<S> PartialEq for VldText<S> {
282 fn eq(&self, other: &Self) -> bool {
283 self.value == other.value
284 }
285}
286impl<S> Eq for VldText<S> {}
287
288impl<S> PartialOrd for VldText<S> {
289 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
290 Some(self.cmp(other))
291 }
292}
293impl<S> Ord for VldText<S> {
294 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
295 self.value.cmp(&other.value)
296 }
297}
298
299impl<S> std::hash::Hash for VldText<S> {
300 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
301 self.value.hash(state);
302 }
303}
304
305impl<S: vld::schema::VldParse> VldText<S> {
306 pub fn new(input: impl Into<String>) -> Result<Self, VldSqlxError> {
310 let s = input.into();
311 let json = serde_json::json!({ "value": s });
312 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
313 Ok(Self {
314 value: s,
315 _schema: std::marker::PhantomData,
316 })
317 }
318
319 pub fn new_unchecked(input: impl Into<String>) -> Self {
321 Self {
322 value: input.into(),
323 _schema: std::marker::PhantomData,
324 }
325 }
326
327 pub fn as_str(&self) -> &str {
329 &self.value
330 }
331
332 pub fn into_inner(self) -> String {
334 self.value
335 }
336}
337
338impl<S> Deref for VldText<S> {
339 type Target = str;
340 fn deref(&self) -> &str {
341 &self.value
342 }
343}
344
345impl<S> AsRef<str> for VldText<S> {
346 fn as_ref(&self) -> &str {
347 &self.value
348 }
349}
350
351impl<S> fmt::Debug for VldText<S> {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 write!(f, "VldText({:?})", self.value)
354 }
355}
356
357impl<S> fmt::Display for VldText<S> {
358 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359 f.write_str(&self.value)
360 }
361}
362
363impl<S> serde::Serialize for VldText<S> {
364 fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
365 self.value.serialize(serializer)
366 }
367}
368
369impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldText<S> {
370 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
371 let s = String::deserialize(deserializer)?;
372 VldText::<S>::new(&s).map_err(serde::de::Error::custom)
373 }
374}
375
376impl<S, DB: sqlx::Database> sqlx::Type<DB> for VldText<S>
378where
379 String: sqlx::Type<DB>,
380{
381 fn type_info() -> DB::TypeInfo {
382 <String as sqlx::Type<DB>>::type_info()
383 }
384
385 fn compatible(ty: &DB::TypeInfo) -> bool {
386 <String as sqlx::Type<DB>>::compatible(ty)
387 }
388}
389
390impl<'q, S, DB: sqlx::Database> sqlx::Encode<'q, DB> for VldText<S>
392where
393 String: sqlx::Encode<'q, DB>,
394{
395 fn encode_by_ref(
396 &self,
397 buf: &mut <DB as sqlx::Database>::ArgumentBuffer<'q>,
398 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
399 self.value.encode_by_ref(buf)
400 }
401}
402
403impl<'r, S: vld::schema::VldParse, DB: sqlx::Database> sqlx::Decode<'r, DB> for VldText<S>
405where
406 String: sqlx::Decode<'r, DB>,
407{
408 fn decode(
409 value: <DB as sqlx::Database>::ValueRef<'r>,
410 ) -> Result<Self, sqlx::error::BoxDynError> {
411 let s = <String as sqlx::Decode<'r, DB>>::decode(value)?;
412 Ok(Self::new_unchecked(s))
413 }
414}
415
416pub struct VldInt<S> {
442 value: i64,
443 _schema: std::marker::PhantomData<S>,
444}
445
446impl<S> Clone for VldInt<S> {
447 fn clone(&self) -> Self {
448 *self
449 }
450}
451impl<S> Copy for VldInt<S> {}
452
453impl<S> PartialEq for VldInt<S> {
454 fn eq(&self, other: &Self) -> bool {
455 self.value == other.value
456 }
457}
458impl<S> Eq for VldInt<S> {}
459
460impl<S> PartialOrd for VldInt<S> {
461 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
462 Some(self.cmp(other))
463 }
464}
465impl<S> Ord for VldInt<S> {
466 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
467 self.value.cmp(&other.value)
468 }
469}
470
471impl<S> std::hash::Hash for VldInt<S> {
472 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
473 self.value.hash(state);
474 }
475}
476
477impl<S: vld::schema::VldParse> VldInt<S> {
478 pub fn new(input: i64) -> Result<Self, VldSqlxError> {
480 let json = serde_json::json!({ "value": input });
481 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
482 Ok(Self {
483 value: input,
484 _schema: std::marker::PhantomData,
485 })
486 }
487
488 pub fn new_unchecked(input: i64) -> Self {
490 Self {
491 value: input,
492 _schema: std::marker::PhantomData,
493 }
494 }
495
496 pub fn get(&self) -> i64 {
498 self.value
499 }
500}
501
502impl<S> Deref for VldInt<S> {
503 type Target = i64;
504 fn deref(&self) -> &i64 {
505 &self.value
506 }
507}
508
509impl<S> fmt::Debug for VldInt<S> {
510 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
511 write!(f, "VldInt({})", self.value)
512 }
513}
514
515impl<S> fmt::Display for VldInt<S> {
516 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
517 write!(f, "{}", self.value)
518 }
519}
520
521impl<S> serde::Serialize for VldInt<S> {
522 fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
523 self.value.serialize(serializer)
524 }
525}
526
527impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldInt<S> {
528 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
529 let v = i64::deserialize(deserializer)?;
530 VldInt::<S>::new(v).map_err(serde::de::Error::custom)
531 }
532}
533
534impl<S, DB: sqlx::Database> sqlx::Type<DB> for VldInt<S>
536where
537 i64: sqlx::Type<DB>,
538{
539 fn type_info() -> DB::TypeInfo {
540 <i64 as sqlx::Type<DB>>::type_info()
541 }
542
543 fn compatible(ty: &DB::TypeInfo) -> bool {
544 <i64 as sqlx::Type<DB>>::compatible(ty)
545 }
546}
547
548impl<'q, S, DB: sqlx::Database> sqlx::Encode<'q, DB> for VldInt<S>
550where
551 i64: sqlx::Encode<'q, DB>,
552{
553 fn encode_by_ref(
554 &self,
555 buf: &mut <DB as sqlx::Database>::ArgumentBuffer<'q>,
556 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
557 self.value.encode_by_ref(buf)
558 }
559}
560
561impl<'r, S: vld::schema::VldParse, DB: sqlx::Database> sqlx::Decode<'r, DB> for VldInt<S>
563where
564 i64: sqlx::Decode<'r, DB>,
565{
566 fn decode(
567 value: <DB as sqlx::Database>::ValueRef<'r>,
568 ) -> Result<Self, sqlx::error::BoxDynError> {
569 let v = <i64 as sqlx::Decode<'r, DB>>::decode(value)?;
570 Ok(Self::new_unchecked(v))
571 }
572}
573
574pub struct VldBool<S> {
597 value: bool,
598 _schema: std::marker::PhantomData<S>,
599}
600
601impl<S> Clone for VldBool<S> {
602 fn clone(&self) -> Self {
603 *self
604 }
605}
606impl<S> Copy for VldBool<S> {}
607
608impl<S> PartialEq for VldBool<S> {
609 fn eq(&self, other: &Self) -> bool {
610 self.value == other.value
611 }
612}
613impl<S> Eq for VldBool<S> {}
614
615impl<S: vld::schema::VldParse> VldBool<S> {
616 pub fn new(input: bool) -> Result<Self, VldSqlxError> {
618 let json = serde_json::json!({ "value": input });
619 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
620 Ok(Self {
621 value: input,
622 _schema: std::marker::PhantomData,
623 })
624 }
625
626 pub fn new_unchecked(input: bool) -> Self {
628 Self {
629 value: input,
630 _schema: std::marker::PhantomData,
631 }
632 }
633
634 pub fn get(&self) -> bool {
636 self.value
637 }
638}
639
640impl<S> Deref for VldBool<S> {
641 type Target = bool;
642 fn deref(&self) -> &bool {
643 &self.value
644 }
645}
646
647impl<S> fmt::Debug for VldBool<S> {
648 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
649 write!(f, "VldBool({})", self.value)
650 }
651}
652
653impl<S> fmt::Display for VldBool<S> {
654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
655 write!(f, "{}", self.value)
656 }
657}
658
659impl<S> serde::Serialize for VldBool<S> {
660 fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
661 self.value.serialize(serializer)
662 }
663}
664
665impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldBool<S> {
666 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
667 let v = bool::deserialize(deserializer)?;
668 VldBool::<S>::new(v).map_err(serde::de::Error::custom)
669 }
670}
671
672impl<S, DB: sqlx::Database> sqlx::Type<DB> for VldBool<S>
674where
675 bool: sqlx::Type<DB>,
676{
677 fn type_info() -> DB::TypeInfo {
678 <bool as sqlx::Type<DB>>::type_info()
679 }
680
681 fn compatible(ty: &DB::TypeInfo) -> bool {
682 <bool as sqlx::Type<DB>>::compatible(ty)
683 }
684}
685
686impl<'q, S, DB: sqlx::Database> sqlx::Encode<'q, DB> for VldBool<S>
687where
688 bool: sqlx::Encode<'q, DB>,
689{
690 fn encode_by_ref(
691 &self,
692 buf: &mut <DB as sqlx::Database>::ArgumentBuffer<'q>,
693 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
694 self.value.encode_by_ref(buf)
695 }
696}
697
698impl<'r, S: vld::schema::VldParse, DB: sqlx::Database> sqlx::Decode<'r, DB> for VldBool<S>
699where
700 bool: sqlx::Decode<'r, DB>,
701{
702 fn decode(
703 value: <DB as sqlx::Database>::ValueRef<'r>,
704 ) -> Result<Self, sqlx::error::BoxDynError> {
705 let v = <bool as sqlx::Decode<'r, DB>>::decode(value)?;
706 Ok(Self::new_unchecked(v))
707 }
708}
709
710pub struct VldFloat<S> {
733 value: f64,
734 _schema: std::marker::PhantomData<S>,
735}
736
737impl<S> Clone for VldFloat<S> {
738 fn clone(&self) -> Self {
739 *self
740 }
741}
742impl<S> Copy for VldFloat<S> {}
743
744impl<S> PartialEq for VldFloat<S> {
745 fn eq(&self, other: &Self) -> bool {
746 self.value == other.value
747 }
748}
749
750impl<S: vld::schema::VldParse> VldFloat<S> {
751 pub fn new(input: f64) -> Result<Self, VldSqlxError> {
753 let json = serde_json::json!({ "value": input });
754 S::vld_parse_value(&json).map_err(VldSqlxError::Validation)?;
755 Ok(Self {
756 value: input,
757 _schema: std::marker::PhantomData,
758 })
759 }
760
761 pub fn new_unchecked(input: f64) -> Self {
763 Self {
764 value: input,
765 _schema: std::marker::PhantomData,
766 }
767 }
768
769 pub fn get(&self) -> f64 {
771 self.value
772 }
773}
774
775impl<S> Deref for VldFloat<S> {
776 type Target = f64;
777 fn deref(&self) -> &f64 {
778 &self.value
779 }
780}
781
782impl<S> fmt::Debug for VldFloat<S> {
783 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
784 write!(f, "VldFloat({})", self.value)
785 }
786}
787
788impl<S> fmt::Display for VldFloat<S> {
789 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
790 write!(f, "{}", self.value)
791 }
792}
793
794impl<S> serde::Serialize for VldFloat<S> {
795 fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
796 self.value.serialize(serializer)
797 }
798}
799
800impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldFloat<S> {
801 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
802 let v = f64::deserialize(deserializer)?;
803 VldFloat::<S>::new(v).map_err(serde::de::Error::custom)
804 }
805}
806
807impl<S, DB: sqlx::Database> sqlx::Type<DB> for VldFloat<S>
809where
810 f64: sqlx::Type<DB>,
811{
812 fn type_info() -> DB::TypeInfo {
813 <f64 as sqlx::Type<DB>>::type_info()
814 }
815
816 fn compatible(ty: &DB::TypeInfo) -> bool {
817 <f64 as sqlx::Type<DB>>::compatible(ty)
818 }
819}
820
821impl<'q, S, DB: sqlx::Database> sqlx::Encode<'q, DB> for VldFloat<S>
822where
823 f64: sqlx::Encode<'q, DB>,
824{
825 fn encode_by_ref(
826 &self,
827 buf: &mut <DB as sqlx::Database>::ArgumentBuffer<'q>,
828 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
829 self.value.encode_by_ref(buf)
830 }
831}
832
833impl<'r, S: vld::schema::VldParse, DB: sqlx::Database> sqlx::Decode<'r, DB> for VldFloat<S>
834where
835 f64: sqlx::Decode<'r, DB>,
836{
837 fn decode(
838 value: <DB as sqlx::Database>::ValueRef<'r>,
839 ) -> Result<Self, sqlx::error::BoxDynError> {
840 let v = <f64 as sqlx::Decode<'r, DB>>::decode(value)?;
841 Ok(Self::new_unchecked(v))
842 }
843}
844
845pub mod prelude {
848 pub use crate::{
849 validate_insert, validate_row, validate_rows, validate_update, Validated, VldBool,
850 VldFloat, VldInt, VldSqlxError, VldText,
851 };
852 pub use vld::prelude::*;
853}