validation builder additions

This commit is contained in:
Mitchell Marino 2024-06-10 12:14:14 -05:00
parent bf04957370
commit e7fd8ec7e1

View File

@ -1,4 +1,4 @@
use crate::controls::ValidationFn;
use crate::{controls::ValidationFn, FormToolData};
use std::fmt::Display;
/// A helper builder that allows you to specify a validation function
@ -8,23 +8,25 @@ use std::fmt::Display;
/// closures, but for simple validation function this builder can be helpful
///
/// Validations are run in the order that they are called in the builder.
pub struct ValidationBuilder<T: 'static> {
pub struct ValidationBuilder<FD: FormToolData, T: 'static> {
/// The name of the field, for error messages.
name: String,
/// The getter function for the field to validate.
field_fn: Box<dyn Fn(&FD) -> &T + 'static>,
/// The functions to be called when validating.
functions: Vec<Box<dyn Fn(&str, &T) -> Result<(), String> + 'static>>,
}
impl<T: 'static> Default for ValidationBuilder<T> {
fn default() -> Self {
impl<FD: FormToolData, T: 'static> ValidationBuilder<FD, T> {
/// Creates a new empty [`ValidationBuilder`] on the given field.
pub fn for_field(field_fn: impl Fn(&FD) -> &T + 'static) -> Self {
ValidationBuilder {
name: String::from("Field"),
field_fn: Box::new(field_fn),
functions: Vec::new(),
}
}
}
impl<T: 'static> ValidationBuilder<T> {
/// The name of the field that is being validated.
///
/// This is the name that will be used for error messages.
@ -33,9 +35,19 @@ impl<T: 'static> ValidationBuilder<T> {
self
}
/// Adds a custom validation function.
///
/// The function should take the value as an argument and return
/// a [`Result<(), String>`], just like any other validation function.
pub fn custom(mut self, f: impl ValidationFn<T>) -> Self {
self.functions.push(Box::new(move |_name, value| f(value)));
self
}
/// Builds the action validation function.
pub fn build(self) -> impl ValidationFn<T> {
move |value| {
pub fn build(self) -> impl ValidationFn<FD> {
move |form_data| {
let value = (self.field_fn)(form_data);
for f in self.functions.iter() {
match f(self.name.as_str(), value) {
Ok(()) => {}
@ -47,7 +59,7 @@ impl<T: 'static> ValidationBuilder<T> {
}
}
impl ValidationBuilder<String> {
impl<FD: FormToolData> ValidationBuilder<FD, String> {
/// Requires the field to not be empty.
pub fn required(mut self) -> Self {
self.functions.push(Box::new(move |name, value| {
@ -75,7 +87,7 @@ impl ValidationBuilder<String> {
/// Requires the field's length to be less than or equal to `min_len`.
pub fn max_len(mut self, max_len: usize) -> Self {
self.functions.push(Box::new(move |name, value| {
if value.len() < max_len {
if value.len() > max_len {
Err(format!("{} must be <= {} characters", name, max_len))
} else {
Ok(())
@ -85,7 +97,7 @@ impl ValidationBuilder<String> {
}
}
impl<T: PartialOrd<T> + Display + 'static> ValidationBuilder<T> {
impl<FD: FormToolData, T: PartialOrd<T> + Display + 'static> ValidationBuilder<FD, T> {
/// Requires the value to be at least `min_value` according to
/// `PartialOrd`.
pub fn min_value(mut self, min_value: T) -> Self {
@ -113,7 +125,7 @@ impl<T: PartialOrd<T> + Display + 'static> ValidationBuilder<T> {
}
}
impl<T: PartialEq<T> + Display + 'static> ValidationBuilder<T> {
impl<FD: FormToolData, T: PartialEq<T> + Display + 'static> ValidationBuilder<FD, T> {
/// Requires the field to be in the provided whitelist.
pub fn whitelist(mut self, whitelist: Vec<T>) -> Self {
self.functions.push(Box::new(move |name, value| {