1use std::fmt;
41use std::ops::Deref;
42
43pub use vld;
48
49pub struct Validated<S, T> {
80 inner: T,
81 _schema: std::marker::PhantomData<S>,
82}
83
84impl<S, T> Validated<S, T>
85where
86 S: vld::schema::VldParse,
87 T: serde::Serialize,
88{
89 pub fn new(value: T) -> Result<Self, VldDieselError> {
91 let json = serde_json::to_value(&value)
92 .map_err(|e| VldDieselError::Serialization(e.to_string()))?;
93 S::vld_parse_value(&json).map_err(VldDieselError::Validation)?;
94 Ok(Self {
95 inner: value,
96 _schema: std::marker::PhantomData,
97 })
98 }
99
100 pub fn inner(&self) -> &T {
102 &self.inner
103 }
104
105 pub fn into_inner(self) -> T {
107 self.inner
108 }
109}
110
111impl<S, T> Deref for Validated<S, T> {
112 type Target = T;
113 fn deref(&self) -> &T {
114 &self.inner
115 }
116}
117
118impl<S, T: fmt::Debug> fmt::Debug for Validated<S, T> {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 f.debug_struct("Validated")
121 .field("inner", &self.inner)
122 .finish()
123 }
124}
125
126impl<S, T: Clone> Clone for Validated<S, T> {
127 fn clone(&self) -> Self {
128 Self {
129 inner: self.inner.clone(),
130 _schema: std::marker::PhantomData,
131 }
132 }
133}
134
135pub fn validate_insert<S, T>(value: &T) -> Result<(), VldDieselError>
162where
163 S: vld::schema::VldParse,
164 T: serde::Serialize,
165{
166 let json =
167 serde_json::to_value(value).map_err(|e| VldDieselError::Serialization(e.to_string()))?;
168 S::vld_parse_value(&json).map_err(VldDieselError::Validation)?;
169 Ok(())
170}
171
172pub fn validate_update<S, T>(value: &T) -> Result<(), VldDieselError>
174where
175 S: vld::schema::VldParse,
176 T: serde::Serialize,
177{
178 validate_insert::<S, T>(value)
179}
180
181pub fn validate_row<S, T>(value: &T) -> Result<(), VldDieselError>
186where
187 S: vld::schema::VldParse,
188 T: serde::Serialize,
189{
190 validate_insert::<S, T>(value)
191}
192
193pub struct VldText<S> {
222 value: String,
223 _schema: std::marker::PhantomData<S>,
224}
225
226impl<S> Clone for VldText<S> {
227 fn clone(&self) -> Self {
228 Self {
229 value: self.value.clone(),
230 _schema: std::marker::PhantomData,
231 }
232 }
233}
234
235impl<S> PartialEq for VldText<S> {
236 fn eq(&self, other: &Self) -> bool {
237 self.value == other.value
238 }
239}
240impl<S> Eq for VldText<S> {}
241
242impl<S> PartialOrd for VldText<S> {
243 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
244 Some(self.cmp(other))
245 }
246}
247impl<S> Ord for VldText<S> {
248 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
249 self.value.cmp(&other.value)
250 }
251}
252
253impl<S> std::hash::Hash for VldText<S> {
254 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
255 self.value.hash(state);
256 }
257}
258
259impl<S: vld::schema::VldParse> VldText<S> {
260 pub fn new(input: impl Into<String>) -> Result<Self, VldDieselError> {
264 let s = input.into();
265 let json = serde_json::json!({ "value": s });
266 S::vld_parse_value(&json).map_err(VldDieselError::Validation)?;
267 Ok(Self {
268 value: s,
269 _schema: std::marker::PhantomData,
270 })
271 }
272
273 pub fn new_unchecked(input: impl Into<String>) -> Self {
275 Self {
276 value: input.into(),
277 _schema: std::marker::PhantomData,
278 }
279 }
280
281 pub fn as_str(&self) -> &str {
283 &self.value
284 }
285
286 pub fn into_inner(self) -> String {
288 self.value
289 }
290}
291
292impl<S> Deref for VldText<S> {
293 type Target = str;
294 fn deref(&self) -> &str {
295 &self.value
296 }
297}
298
299impl<S> AsRef<str> for VldText<S> {
300 fn as_ref(&self) -> &str {
301 &self.value
302 }
303}
304
305impl<S> fmt::Debug for VldText<S> {
306 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307 write!(f, "VldText({:?})", self.value)
308 }
309}
310
311impl<S> fmt::Display for VldText<S> {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313 f.write_str(&self.value)
314 }
315}
316
317impl<S> serde::Serialize for VldText<S> {
318 fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
319 self.value.serialize(serializer)
320 }
321}
322
323impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldText<S> {
324 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
325 let s = String::deserialize(deserializer)?;
326 VldText::<S>::new(&s).map_err(serde::de::Error::custom)
327 }
328}
329
330impl<S, DB> diesel::serialize::ToSql<diesel::sql_types::Text, DB> for VldText<S>
334where
335 DB: diesel::backend::Backend,
336 str: diesel::serialize::ToSql<diesel::sql_types::Text, DB>,
337{
338 fn to_sql<'b>(
339 &'b self,
340 out: &mut diesel::serialize::Output<'b, '_, DB>,
341 ) -> diesel::serialize::Result {
342 <str as diesel::serialize::ToSql<diesel::sql_types::Text, DB>>::to_sql(&self.value, out)
343 }
344}
345
346impl<S: vld::schema::VldParse, DB> diesel::deserialize::FromSql<diesel::sql_types::Text, DB>
347 for VldText<S>
348where
349 DB: diesel::backend::Backend,
350 String: diesel::deserialize::FromSql<diesel::sql_types::Text, DB>,
351{
352 fn from_sql(
353 bytes: <DB as diesel::backend::Backend>::RawValue<'_>,
354 ) -> diesel::deserialize::Result<Self> {
355 let s =
356 <String as diesel::deserialize::FromSql<diesel::sql_types::Text, DB>>::from_sql(bytes)?;
357 Ok(Self::new_unchecked(s))
358 }
359}
360
361pub struct VldInt<S> {
387 value: i64,
388 _schema: std::marker::PhantomData<S>,
389}
390
391impl<S> Clone for VldInt<S> {
392 fn clone(&self) -> Self {
393 *self
394 }
395}
396impl<S> Copy for VldInt<S> {}
397
398impl<S> PartialEq for VldInt<S> {
399 fn eq(&self, other: &Self) -> bool {
400 self.value == other.value
401 }
402}
403impl<S> Eq for VldInt<S> {}
404
405impl<S> PartialOrd for VldInt<S> {
406 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
407 Some(self.cmp(other))
408 }
409}
410impl<S> Ord for VldInt<S> {
411 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
412 self.value.cmp(&other.value)
413 }
414}
415
416impl<S> std::hash::Hash for VldInt<S> {
417 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
418 self.value.hash(state);
419 }
420}
421
422impl<S: vld::schema::VldParse> VldInt<S> {
423 pub fn new(input: i64) -> Result<Self, VldDieselError> {
425 let json = serde_json::json!({ "value": input });
426 S::vld_parse_value(&json).map_err(VldDieselError::Validation)?;
427 Ok(Self {
428 value: input,
429 _schema: std::marker::PhantomData,
430 })
431 }
432
433 pub fn new_unchecked(input: i64) -> Self {
435 Self {
436 value: input,
437 _schema: std::marker::PhantomData,
438 }
439 }
440
441 pub fn get(&self) -> i64 {
443 self.value
444 }
445}
446
447impl<S> Deref for VldInt<S> {
448 type Target = i64;
449 fn deref(&self) -> &i64 {
450 &self.value
451 }
452}
453
454impl<S> fmt::Debug for VldInt<S> {
455 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
456 write!(f, "VldInt({})", self.value)
457 }
458}
459
460impl<S> fmt::Display for VldInt<S> {
461 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
462 write!(f, "{}", self.value)
463 }
464}
465
466impl<S> serde::Serialize for VldInt<S> {
467 fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
468 self.value.serialize(serializer)
469 }
470}
471
472impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldInt<S> {
473 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
474 let v = i64::deserialize(deserializer)?;
475 VldInt::<S>::new(v).map_err(serde::de::Error::custom)
476 }
477}
478
479impl<S, DB> diesel::serialize::ToSql<diesel::sql_types::BigInt, DB> for VldInt<S>
482where
483 DB: diesel::backend::Backend,
484 i64: diesel::serialize::ToSql<diesel::sql_types::BigInt, DB>,
485{
486 fn to_sql<'b>(
487 &'b self,
488 out: &mut diesel::serialize::Output<'b, '_, DB>,
489 ) -> diesel::serialize::Result {
490 <i64 as diesel::serialize::ToSql<diesel::sql_types::BigInt, DB>>::to_sql(&self.value, out)
491 }
492}
493
494impl<S: vld::schema::VldParse, DB> diesel::deserialize::FromSql<diesel::sql_types::BigInt, DB>
495 for VldInt<S>
496where
497 DB: diesel::backend::Backend,
498 i64: diesel::deserialize::FromSql<diesel::sql_types::BigInt, DB>,
499{
500 fn from_sql(
501 bytes: <DB as diesel::backend::Backend>::RawValue<'_>,
502 ) -> diesel::deserialize::Result<Self> {
503 let v =
504 <i64 as diesel::deserialize::FromSql<diesel::sql_types::BigInt, DB>>::from_sql(bytes)?;
505 Ok(Self::new_unchecked(v))
506 }
507}
508
509impl<S: vld::schema::VldParse, DB> diesel::deserialize::FromSql<diesel::sql_types::Integer, DB>
512 for VldInt<S>
513where
514 DB: diesel::backend::Backend,
515 i32: diesel::deserialize::FromSql<diesel::sql_types::Integer, DB>,
516{
517 fn from_sql(
518 bytes: <DB as diesel::backend::Backend>::RawValue<'_>,
519 ) -> diesel::deserialize::Result<Self> {
520 let v =
521 <i32 as diesel::deserialize::FromSql<diesel::sql_types::Integer, DB>>::from_sql(bytes)?;
522 Ok(Self::new_unchecked(v as i64))
523 }
524}
525
526#[derive(Debug, Clone)]
532pub enum VldDieselError {
533 Validation(vld::error::VldError),
535 Serialization(String),
537}
538
539impl fmt::Display for VldDieselError {
540 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541 match self {
542 VldDieselError::Validation(e) => write!(f, "Validation error: {}", e),
543 VldDieselError::Serialization(e) => write!(f, "Serialization error: {}", e),
544 }
545 }
546}
547
548impl std::error::Error for VldDieselError {
549 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
550 match self {
551 VldDieselError::Validation(e) => Some(e),
552 VldDieselError::Serialization(_) => None,
553 }
554 }
555}
556
557impl From<vld::error::VldError> for VldDieselError {
558 fn from(e: vld::error::VldError) -> Self {
559 VldDieselError::Validation(e)
560 }
561}
562
563pub mod prelude {
568 pub use crate::{
569 validate_insert, validate_row, validate_update, Validated, VldDieselError, VldInt, VldText,
570 };
571 pub use vld::prelude::*;
572}