Skip to main content

vld_surrealdb/
lib.rs

1//! # vld-surrealdb — SurrealDB integration for the `vld` validation library
2//!
3//! Validate JSON documents **before** sending to SurrealDB and **after** receiving.
4//!
5//! Zero dependency on `surrealdb` crate — works purely through `serde`, so it's
6//! compatible with any SurrealDB SDK version (2.x, 3.x, etc.).
7//!
8//! ## Quick Start
9//!
10//! ```rust
11//! use vld_surrealdb::prelude::*;
12//!
13//! vld::schema! {
14//!     #[derive(Debug)]
15//!     pub struct PersonSchema {
16//!         pub name: String  => vld::string().min(1).max(100),
17//!         pub email: String => vld::string().email(),
18//!         pub age: i64      => vld::number().int().min(0).max(150),
19//!     }
20//! }
21//!
22//! #[derive(serde::Serialize)]
23//! struct Person { name: String, email: String, age: i64 }
24//!
25//! let person = Person {
26//!     name: "Alice".into(),
27//!     email: "alice@example.com".into(),
28//!     age: 30,
29//! };
30//!
31//! // Validate before db.create("person").content(person)
32//! validate_content::<PersonSchema, _>(&person).unwrap();
33//! ```
34
35use std::fmt;
36use std::ops::Deref;
37
38pub use vld;
39
40// ========================= Error type ========================================
41
42/// Error returned by `vld-surrealdb` operations.
43#[derive(Debug, Clone)]
44pub enum VldSurrealError {
45    /// Schema validation failed.
46    Validation(vld::error::VldError),
47    /// Failed to serialize the value to JSON for validation.
48    Serialization(String),
49}
50
51impl fmt::Display for VldSurrealError {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        match self {
54            VldSurrealError::Validation(e) => write!(f, "Validation error: {}", e),
55            VldSurrealError::Serialization(e) => write!(f, "Serialization error: {}", e),
56        }
57    }
58}
59
60impl std::error::Error for VldSurrealError {
61    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
62        match self {
63            VldSurrealError::Validation(e) => Some(e),
64            VldSurrealError::Serialization(_) => None,
65        }
66    }
67}
68
69impl From<vld::error::VldError> for VldSurrealError {
70    fn from(e: vld::error::VldError) -> Self {
71        VldSurrealError::Validation(e)
72    }
73}
74
75/// Structured error with field-level details, serializable as JSON.
76///
77/// Useful for returning validation errors from SurrealDB server functions
78/// or custom endpoints.
79#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
80pub struct FieldError {
81    pub field: String,
82    pub message: String,
83}
84
85/// Serializable validation error for API responses.
86///
87/// Converts from [`VldSurrealError`] and can be sent over the wire.
88#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
89pub struct VldSurrealResponse {
90    pub error: String,
91    pub fields: Vec<FieldError>,
92}
93
94impl VldSurrealResponse {
95    /// Create from a validation error.
96    pub fn from_vld_error(e: &vld::error::VldError) -> Self {
97        let fields = e
98            .issues
99            .iter()
100            .map(|issue: &vld::error::ValidationIssue| FieldError {
101                field: issue
102                    .path
103                    .iter()
104                    .map(|p| p.to_string())
105                    .collect::<Vec<_>>()
106                    .join("."),
107                message: issue.message.clone(),
108            })
109            .collect();
110
111        Self {
112            error: "Validation failed".to_string(),
113            fields,
114        }
115    }
116
117    /// Create from a [`VldSurrealError`].
118    pub fn from_error(e: &VldSurrealError) -> Self {
119        match e {
120            VldSurrealError::Validation(ve) => Self::from_vld_error(ve),
121            VldSurrealError::Serialization(msg) => Self {
122                error: "Serialization error".to_string(),
123                fields: vec![FieldError {
124                    field: String::new(),
125                    message: msg.clone(),
126                }],
127            },
128        }
129    }
130
131    /// Convert to a JSON value.
132    pub fn to_json(&self) -> serde_json::Value {
133        serde_json::to_value(self).unwrap_or_default()
134    }
135}
136
137// ========================= Validated<S, T> ===================================
138
139/// A wrapper that proves its inner value has been validated against schema `S`.
140///
141/// Implements `Serialize` so it can be passed directly to SurrealDB operations.
142///
143/// # Example
144///
145/// ```
146/// use vld::prelude::*;
147///
148/// vld::schema! {
149///     #[derive(Debug)]
150///     pub struct NameSchema {
151///         pub name: String => vld::string().min(1).max(50),
152///     }
153/// }
154///
155/// #[derive(serde::Serialize)]
156/// struct Row { name: String }
157///
158/// let row = Row { name: "Alice".into() };
159/// let v = vld_surrealdb::Validated::<NameSchema, _>::new(row).unwrap();
160/// assert_eq!(v.inner().name, "Alice");
161/// ```
162pub struct Validated<S, T> {
163    inner: T,
164    _schema: std::marker::PhantomData<S>,
165}
166
167impl<S, T> Validated<S, T>
168where
169    S: vld::schema::VldParse,
170    T: serde::Serialize,
171{
172    /// Validate `value` against schema `S` and wrap it on success.
173    pub fn new(value: T) -> Result<Self, VldSurrealError> {
174        let json = serde_json::to_value(&value)
175            .map_err(|e| VldSurrealError::Serialization(e.to_string()))?;
176        S::vld_parse_value(&json).map_err(VldSurrealError::Validation)?;
177        Ok(Self {
178            inner: value,
179            _schema: std::marker::PhantomData,
180        })
181    }
182
183    /// Get a reference to the validated inner value.
184    pub fn inner(&self) -> &T {
185        &self.inner
186    }
187
188    /// Consume and return the inner value.
189    pub fn into_inner(self) -> T {
190        self.inner
191    }
192}
193
194impl<S, T> Deref for Validated<S, T> {
195    type Target = T;
196    fn deref(&self) -> &T {
197        &self.inner
198    }
199}
200
201impl<S, T: fmt::Debug> fmt::Debug for Validated<S, T> {
202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203        f.debug_struct("Validated")
204            .field("inner", &self.inner)
205            .finish()
206    }
207}
208
209impl<S, T: Clone> Clone for Validated<S, T> {
210    fn clone(&self) -> Self {
211        Self {
212            inner: self.inner.clone(),
213            _schema: std::marker::PhantomData,
214        }
215    }
216}
217
218impl<S, T: serde::Serialize> serde::Serialize for Validated<S, T> {
219    fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
220        self.inner.serialize(serializer)
221    }
222}
223
224// ========================= Standalone helpers ================================
225
226/// Validate a value against schema `S` before create/insert/update.
227///
228/// Use before `db.create("table").content(value)` or `db.insert("table").content(value)`.
229///
230/// ```
231/// use vld::prelude::*;
232///
233/// vld::schema! {
234///     #[derive(Debug)]
235///     pub struct ItemSchema {
236///         pub name: String => vld::string().min(1),
237///         pub qty: i64 => vld::number().int().min(0),
238///     }
239/// }
240///
241/// #[derive(serde::Serialize)]
242/// struct Item { name: String, qty: i64 }
243///
244/// let item = Item { name: "Widget".into(), qty: 5 };
245/// vld_surrealdb::validate_content::<ItemSchema, _>(&item).unwrap();
246/// ```
247pub fn validate_content<S, T>(value: &T) -> Result<(), VldSurrealError>
248where
249    S: vld::schema::VldParse,
250    T: serde::Serialize,
251{
252    let json =
253        serde_json::to_value(value).map_err(|e| VldSurrealError::Serialization(e.to_string()))?;
254    S::vld_parse_value(&json).map_err(VldSurrealError::Validation)?;
255    Ok(())
256}
257
258/// Validate raw JSON value against schema `S`.
259///
260/// Useful for validating SurrealQL query results or raw JSON payloads.
261///
262/// ```
263/// use vld::prelude::*;
264///
265/// vld::schema! {
266///     #[derive(Debug)]
267///     pub struct NameSchema {
268///         pub name: String => vld::string().min(1),
269///     }
270/// }
271///
272/// let json = serde_json::json!({"name": "Alice"});
273/// vld_surrealdb::validate_json::<NameSchema>(&json).unwrap();
274/// ```
275pub fn validate_json<S>(value: &serde_json::Value) -> Result<(), VldSurrealError>
276where
277    S: vld::schema::VldParse,
278{
279    S::vld_parse_value(value).map_err(VldSurrealError::Validation)?;
280    Ok(())
281}
282
283/// Validate a record loaded from SurrealDB against schema `S`.
284///
285/// Use after `db.select("table")` to enforce invariants on stored data.
286pub fn validate_record<S, T>(value: &T) -> Result<(), VldSurrealError>
287where
288    S: vld::schema::VldParse,
289    T: serde::Serialize,
290{
291    validate_content::<S, T>(value)
292}
293
294/// Validate a batch of records against schema `S`.
295///
296/// Returns the index and error of the first invalid record.
297///
298/// ```
299/// use vld::prelude::*;
300///
301/// vld::schema! {
302///     #[derive(Debug)]
303///     pub struct NameSchema {
304///         pub name: String => vld::string().min(1),
305///     }
306/// }
307///
308/// #[derive(serde::Serialize)]
309/// struct Row { name: String }
310///
311/// let rows = vec![
312///     Row { name: "Alice".into() },
313///     Row { name: "Bob".into() },
314/// ];
315/// assert!(vld_surrealdb::validate_records::<NameSchema, _>(&rows).is_ok());
316/// ```
317pub fn validate_records<S, T>(rows: &[T]) -> Result<(), (usize, VldSurrealError)>
318where
319    S: vld::schema::VldParse,
320    T: serde::Serialize,
321{
322    for (i, row) in rows.iter().enumerate() {
323        validate_record::<S, T>(row).map_err(|e| (i, e))?;
324    }
325    Ok(())
326}
327
328/// Validate a single field value against a vld schema instance.
329///
330/// Useful for validating individual fields in SurrealDB `MERGE` operations.
331///
332/// ```
333/// use vld::prelude::*;
334///
335/// let schema = vld::string().min(1).max(100);
336/// let val = serde_json::json!("Bob");
337/// assert!(vld_surrealdb::validate_value(&schema, &val).is_ok());
338///
339/// let bad = serde_json::json!("");
340/// assert!(vld_surrealdb::validate_value(&schema, &bad).is_err());
341/// ```
342pub fn validate_value<S: vld::schema::VldSchema>(
343    schema: &S,
344    value: &serde_json::Value,
345) -> Result<(), VldSurrealError> {
346    schema
347        .parse_value(value)
348        .map(|_| ())
349        .map_err(VldSurrealError::Validation)
350}
351
352// ========================= VldText<S> ========================================
353
354/// A validated text field for SurrealDB documents.
355///
356/// Wraps a `String` and validates on construction and deserialization.
357/// The schema must have a field named `value`.
358///
359/// ```
360/// use vld::prelude::*;
361///
362/// vld::schema! {
363///     #[derive(Debug)]
364///     pub struct EmailField {
365///         pub value: String => vld::string().email(),
366///     }
367/// }
368///
369/// let email = vld_surrealdb::VldText::<EmailField>::new("user@example.com").unwrap();
370/// assert_eq!(email.as_str(), "user@example.com");
371/// ```
372pub struct VldText<S> {
373    value: String,
374    _schema: std::marker::PhantomData<S>,
375}
376
377impl<S> Clone for VldText<S> {
378    fn clone(&self) -> Self {
379        Self {
380            value: self.value.clone(),
381            _schema: std::marker::PhantomData,
382        }
383    }
384}
385
386impl<S> PartialEq for VldText<S> {
387    fn eq(&self, other: &Self) -> bool {
388        self.value == other.value
389    }
390}
391impl<S> Eq for VldText<S> {}
392
393impl<S: vld::schema::VldParse> VldText<S> {
394    pub fn new(input: impl Into<String>) -> Result<Self, VldSurrealError> {
395        let s = input.into();
396        let json = serde_json::json!({ "value": s });
397        S::vld_parse_value(&json).map_err(VldSurrealError::Validation)?;
398        Ok(Self {
399            value: s,
400            _schema: std::marker::PhantomData,
401        })
402    }
403
404    pub fn new_unchecked(input: impl Into<String>) -> Self {
405        Self {
406            value: input.into(),
407            _schema: std::marker::PhantomData,
408        }
409    }
410
411    pub fn as_str(&self) -> &str {
412        &self.value
413    }
414
415    pub fn into_inner(self) -> String {
416        self.value
417    }
418}
419
420impl<S> Deref for VldText<S> {
421    type Target = str;
422    fn deref(&self) -> &str {
423        &self.value
424    }
425}
426
427impl<S> AsRef<str> for VldText<S> {
428    fn as_ref(&self) -> &str {
429        &self.value
430    }
431}
432
433impl<S> fmt::Debug for VldText<S> {
434    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435        write!(f, "VldText({:?})", self.value)
436    }
437}
438
439impl<S> fmt::Display for VldText<S> {
440    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
441        f.write_str(&self.value)
442    }
443}
444
445impl<S> serde::Serialize for VldText<S> {
446    fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
447        self.value.serialize(serializer)
448    }
449}
450
451impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldText<S> {
452    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
453        let s = String::deserialize(deserializer)?;
454        VldText::<S>::new(&s).map_err(serde::de::Error::custom)
455    }
456}
457
458// ========================= VldInt<S> =========================================
459
460/// A validated integer field for SurrealDB documents.
461///
462/// Wraps an `i64` and validates on construction and deserialization.
463/// The schema must have a field named `value`.
464///
465/// ```
466/// use vld::prelude::*;
467///
468/// vld::schema! {
469///     #[derive(Debug)]
470///     pub struct AgeField {
471///         pub value: i64 => vld::number().int().min(0).max(150),
472///     }
473/// }
474///
475/// let age = vld_surrealdb::VldInt::<AgeField>::new(25).unwrap();
476/// assert_eq!(*age, 25);
477/// assert!(vld_surrealdb::VldInt::<AgeField>::new(-1).is_err());
478/// ```
479pub struct VldInt<S> {
480    value: i64,
481    _schema: std::marker::PhantomData<S>,
482}
483
484impl<S> Clone for VldInt<S> {
485    fn clone(&self) -> Self {
486        *self
487    }
488}
489impl<S> Copy for VldInt<S> {}
490
491impl<S> PartialEq for VldInt<S> {
492    fn eq(&self, other: &Self) -> bool {
493        self.value == other.value
494    }
495}
496impl<S> Eq for VldInt<S> {}
497
498impl<S: vld::schema::VldParse> VldInt<S> {
499    pub fn new(input: i64) -> Result<Self, VldSurrealError> {
500        let json = serde_json::json!({ "value": input });
501        S::vld_parse_value(&json).map_err(VldSurrealError::Validation)?;
502        Ok(Self {
503            value: input,
504            _schema: std::marker::PhantomData,
505        })
506    }
507
508    pub fn new_unchecked(input: i64) -> Self {
509        Self {
510            value: input,
511            _schema: std::marker::PhantomData,
512        }
513    }
514
515    pub fn get(&self) -> i64 {
516        self.value
517    }
518}
519
520impl<S> Deref for VldInt<S> {
521    type Target = i64;
522    fn deref(&self) -> &i64 {
523        &self.value
524    }
525}
526
527impl<S> fmt::Debug for VldInt<S> {
528    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529        write!(f, "VldInt({})", self.value)
530    }
531}
532
533impl<S> fmt::Display for VldInt<S> {
534    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
535        write!(f, "{}", self.value)
536    }
537}
538
539impl<S> serde::Serialize for VldInt<S> {
540    fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
541        self.value.serialize(serializer)
542    }
543}
544
545impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldInt<S> {
546    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
547        let v = i64::deserialize(deserializer)?;
548        VldInt::<S>::new(v).map_err(serde::de::Error::custom)
549    }
550}
551
552// ========================= VldFloat<S> =======================================
553
554/// A validated float field for SurrealDB documents.
555///
556/// Wraps an `f64` and validates on construction and deserialization.
557/// The schema must have a field named `value`.
558///
559/// ```
560/// use vld::prelude::*;
561///
562/// vld::schema! {
563///     #[derive(Debug)]
564///     pub struct PriceField {
565///         pub value: f64 => vld::number().min(0.0),
566///     }
567/// }
568///
569/// let price = vld_surrealdb::VldFloat::<PriceField>::new(9.99).unwrap();
570/// assert!((*price - 9.99).abs() < f64::EPSILON);
571/// ```
572pub struct VldFloat<S> {
573    value: f64,
574    _schema: std::marker::PhantomData<S>,
575}
576
577impl<S> Clone for VldFloat<S> {
578    fn clone(&self) -> Self {
579        *self
580    }
581}
582impl<S> Copy for VldFloat<S> {}
583
584impl<S> PartialEq for VldFloat<S> {
585    fn eq(&self, other: &Self) -> bool {
586        self.value == other.value
587    }
588}
589
590impl<S: vld::schema::VldParse> VldFloat<S> {
591    pub fn new(input: f64) -> Result<Self, VldSurrealError> {
592        let json = serde_json::json!({ "value": input });
593        S::vld_parse_value(&json).map_err(VldSurrealError::Validation)?;
594        Ok(Self {
595            value: input,
596            _schema: std::marker::PhantomData,
597        })
598    }
599
600    pub fn new_unchecked(input: f64) -> Self {
601        Self {
602            value: input,
603            _schema: std::marker::PhantomData,
604        }
605    }
606
607    pub fn get(&self) -> f64 {
608        self.value
609    }
610}
611
612impl<S> Deref for VldFloat<S> {
613    type Target = f64;
614    fn deref(&self) -> &f64 {
615        &self.value
616    }
617}
618
619impl<S> fmt::Debug for VldFloat<S> {
620    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
621        write!(f, "VldFloat({})", self.value)
622    }
623}
624
625impl<S> fmt::Display for VldFloat<S> {
626    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
627        write!(f, "{}", self.value)
628    }
629}
630
631impl<S> serde::Serialize for VldFloat<S> {
632    fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
633        self.value.serialize(serializer)
634    }
635}
636
637impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldFloat<S> {
638    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
639        let v = f64::deserialize(deserializer)?;
640        VldFloat::<S>::new(v).map_err(serde::de::Error::custom)
641    }
642}
643
644// ========================= VldBool<S> ========================================
645
646/// A validated boolean field for SurrealDB documents.
647///
648/// The schema must have a field named `value`.
649///
650/// ```
651/// use vld::prelude::*;
652///
653/// vld::schema! {
654///     #[derive(Debug)]
655///     pub struct ActiveField {
656///         pub value: bool => vld::boolean(),
657///     }
658/// }
659///
660/// let active = vld_surrealdb::VldBool::<ActiveField>::new(true).unwrap();
661/// assert_eq!(*active, true);
662/// ```
663pub struct VldBool<S> {
664    value: bool,
665    _schema: std::marker::PhantomData<S>,
666}
667
668impl<S> Clone for VldBool<S> {
669    fn clone(&self) -> Self {
670        *self
671    }
672}
673impl<S> Copy for VldBool<S> {}
674
675impl<S> PartialEq for VldBool<S> {
676    fn eq(&self, other: &Self) -> bool {
677        self.value == other.value
678    }
679}
680impl<S> Eq for VldBool<S> {}
681
682impl<S: vld::schema::VldParse> VldBool<S> {
683    pub fn new(input: bool) -> Result<Self, VldSurrealError> {
684        let json = serde_json::json!({ "value": input });
685        S::vld_parse_value(&json).map_err(VldSurrealError::Validation)?;
686        Ok(Self {
687            value: input,
688            _schema: std::marker::PhantomData,
689        })
690    }
691
692    pub fn new_unchecked(input: bool) -> Self {
693        Self {
694            value: input,
695            _schema: std::marker::PhantomData,
696        }
697    }
698
699    pub fn get(&self) -> bool {
700        self.value
701    }
702}
703
704impl<S> Deref for VldBool<S> {
705    type Target = bool;
706    fn deref(&self) -> &bool {
707        &self.value
708    }
709}
710
711impl<S> fmt::Debug for VldBool<S> {
712    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
713        write!(f, "VldBool({})", self.value)
714    }
715}
716
717impl<S> fmt::Display for VldBool<S> {
718    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
719        write!(f, "{}", self.value)
720    }
721}
722
723impl<S> serde::Serialize for VldBool<S> {
724    fn serialize<Ser: serde::Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
725        self.value.serialize(serializer)
726    }
727}
728
729impl<'de, S: vld::schema::VldParse> serde::Deserialize<'de> for VldBool<S> {
730    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
731        let v = bool::deserialize(deserializer)?;
732        VldBool::<S>::new(v).map_err(serde::de::Error::custom)
733    }
734}
735
736// ========================= Macro =============================================
737
738/// Validate multiple fields inline before a SurrealDB operation.
739///
740/// ```
741/// use vld::prelude::*;
742/// use vld_surrealdb::validate_fields;
743///
744/// let name = "Alice";
745/// let email = "alice@example.com";
746///
747/// let result = validate_fields! {
748///     name => vld::string().min(1).max(100),
749///     email => vld::string().email(),
750/// };
751/// assert!(result.is_ok());
752/// ```
753#[macro_export]
754macro_rules! validate_fields {
755    ($($field:ident => $schema:expr),* $(,)?) => {{
756        let mut __vld_errors: Vec<$crate::FieldError> = Vec::new();
757        $(
758            {
759                let __vld_val = ::serde_json::to_value(&$field).ok();
760                let __vld_schema = $schema;
761                if let Some(ref val) = __vld_val {
762                    use $crate::vld::schema::VldSchema;
763                    if let Err(_) = __vld_schema.validate(val) {
764                        let msg = format!("field '{}' failed validation", stringify!($field));
765                        __vld_errors.push($crate::FieldError {
766                            field: stringify!($field).to_string(),
767                            message: msg,
768                        });
769                    }
770                }
771            }
772        )*
773        if __vld_errors.is_empty() {
774            ::std::result::Result::Ok::<(), $crate::VldSurrealError>(())
775        } else {
776            let mut __vld_err = $crate::vld::error::VldError::new();
777            for fe in &__vld_errors {
778                __vld_err.issues.push($crate::vld::error::ValidationIssue {
779                    code: $crate::vld::error::IssueCode::Custom {
780                        code: fe.field.clone(),
781                    },
782                    message: fe.message.clone(),
783                    path: vec![
784                        $crate::vld::error::PathSegment::Field(fe.field.clone()),
785                    ],
786                    received: None,
787                });
788            }
789            ::std::result::Result::Err($crate::VldSurrealError::Validation(__vld_err))
790        }
791    }};
792}
793
794// ========================= Prelude ===========================================
795
796pub mod prelude {
797    pub use crate::{
798        validate_content, validate_fields, validate_json, validate_record, validate_records,
799        validate_value, FieldError, Validated, VldBool, VldFloat, VldInt, VldSurrealError,
800        VldSurrealResponse, VldText,
801    };
802    pub use vld::prelude::*;
803}