Skip to main content

vld_integration_common/
lib.rs

1//! # vld-integration-common — shared helpers for `vld` integration crates
2//!
3//! **Internal crate** with no stable API of its own: depend on the
4//! integration crate you need (`vld-dioxus`, `vld-leptos`, `vld-tauri`,
5//! `vld-clap`, `vld-sqlx`, `vld-diesel`, `vld-sea`, `vld-surrealdb`), which
6//! re-exports what it uses from here.
7//!
8//! - [`format_path`] / [`flatten_issues`] — clean issue paths (`user.email`,
9//!   `items[0].name`, no leading dot);
10//! - [`form`] — `VldServerError`, `FieldError`, `check_field`,
11//!   [`validate_args!`] (re-exported by `vld-dioxus` / `vld-leptos`);
12//! - [`db`] — hidden macros that generate each database crate's error type,
13//!   `Validated<S, T>` and the `VldText` / `VldInt` / `VldFloat` / `VldBool`
14//!   column wrappers inside that crate (so it can implement its own database
15//!   traits without orphan-rule conflicts).
16//!
17//! Guide: <https://s00d.github.io/vld/integrations/shared/integration-common>
18#![warn(missing_docs)]
19
20use vld::error::{PathSegment, VldError};
21
22pub mod db;
23pub mod form;
24
25/// Format a validation path as a clean dotted path: `user.email`, `items[0].name`.
26///
27/// No leading dot; an empty path gives an empty string.
28///
29/// ```
30/// use vld::error::PathSegment;
31/// let p = [PathSegment::Field("items".into()), PathSegment::Index(0), PathSegment::Field("name".into())];
32/// assert_eq!(vld_integration_common::format_path(&p), "items[0].name");
33/// ```
34pub fn format_path(path: &[PathSegment]) -> String {
35    let mut out = String::new();
36    for seg in path {
37        match seg {
38            PathSegment::Field(name) => {
39                if !out.is_empty() {
40                    out.push('.');
41                }
42                out.push_str(name);
43            }
44            PathSegment::Index(idx) => {
45                out.push('[');
46                out.push_str(&idx.to_string());
47                out.push(']');
48            }
49        }
50    }
51    out
52}
53
54/// Flatten a [`VldError`] into `(path, message)` pairs using [`format_path`].
55pub fn flatten_issues(err: &VldError) -> Vec<(String, String)> {
56    err.issues
57        .iter()
58        .map(|i| (format_path(&i.path), i.message.clone()))
59        .collect()
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn format_path_has_no_leading_dot() {
68        let p = vec![
69            PathSegment::Field("user".into()),
70            PathSegment::Field("email".into()),
71        ];
72        assert_eq!(format_path(&p), "user.email");
73        assert_eq!(format_path(&[PathSegment::Index(2)]), "[2]");
74        assert_eq!(format_path(&[]), "");
75    }
76}