Databases
Validate Insertable structs before insert and use validated column types in Diesel models and filters.

vld-diesel validates a value against a vld schema before Diesel writes it, and provides column wrappers that derive AsExpression / FromSqlRow, so they work in #[derive(Insertable, Queryable)] structs and in .filter(col.eq(wrapper)).

Install

Cargo.toml
[dependencies]
vld = "0.5"
vld-diesel = "0.5"  # SQLite backend by default
diesel = { version = "2", features = ["sqlite"] }

Features

FeatureDefaultEffect
sqliteyesDiesel SQLite backend
postgresDiesel Postgres backend
mysqlDiesel MySQL backend

Backends are additive. MSRV: 1.85 (see MSRV).

Example

use diesel::prelude::*;
use vld_diesel::prelude::*;

vld::schema! {
    #[derive(Debug)]
    pub struct NewUserSchema {
        pub name: String  => vld::string().min(1).max(100),
        pub email: String => vld::string().email(),
        pub age: i64      => vld::number().int().min(0).max(150),
    }
}

diesel::table! {
    users (id) {
        id -> Integer,
        name -> Text,
        email -> Text,
        age -> BigInt,
    }
}

#[derive(Debug, Insertable, serde::Serialize)]
#[diesel(table_name = users)]
struct NewUser { name: String, email: String, age: i64 }

fn insert(conn: &mut SqliteConnection) -> Result<(), Box<dyn std::error::Error>> {
    let user = NewUser { name: "Bob".into(), email: "bob@example.com".into(), age: 25 };
    let validated = Validated::<NewUserSchema, _>::new(user)?;
    diesel::insert_into(users::table)
        .values(validated.inner())
        .execute(conn)?;
    Ok(())
}

API

  • validate_insert::<S, T>(&value) — serialize value to JSON and validate it against schema type S.
  • validate_row::<S, T>(&row) — the same check for a loaded row.
  • Validated<S, T> — Validated::new(value) validates and wraps; inner(), into_inner(), Deref, transparent Serialize.
  • VldText<S> (Text), VldInt<S> (BigInt, Integer), VldFloat<S> (Double, Float), VldBool<S> (Bool) — column wrappers with ToSql / FromSql; new() validates, new_unchecked() does not.
  • VldDieselError — Validation(VldError) or Serialization(String).
  • prelude — all of the above plus vld::prelude::*.

Gotchas

  • Column schemas need a value field: a wrapper validates {"value": v} against S.
  • FromSql does not re-validate: loaded values are wrapped with new_unchecked. Use validate_row to re-check.
  • VldInt on an Integer column and VldFloat on a Float column narrow on write (per backend) and fail instead of truncating when the value does not fit i32 / f32. Reading Float widens through the decimal form (0.1 stays 0.1).
  • Validated<S, T> stores the original T: schema transforms and defaults are not applied to it.