feat: add comfyui sdk
This commit is contained in:
276
cargos/comfyui-sdk/utils/validation.rs
Normal file
276
cargos/comfyui-sdk/utils/validation.rs
Normal file
@@ -0,0 +1,276 @@
|
||||
//! Parameter validation utilities
|
||||
|
||||
use std::collections::HashMap;
|
||||
use crate::types::{ParameterSchema, ParameterValues, ValidationResult, ValidationError, ParameterType};
|
||||
use regex::Regex;
|
||||
|
||||
/// Validates parameters against their schemas
|
||||
pub fn validate_parameters(
|
||||
parameters: &ParameterValues,
|
||||
schemas: &HashMap<String, ParameterSchema>,
|
||||
) -> ValidationResult {
|
||||
let mut errors = Vec::new();
|
||||
|
||||
// Check required parameters
|
||||
for (name, schema) in schemas {
|
||||
if schema.required.unwrap_or(false) {
|
||||
if !parameters.contains_key(name) {
|
||||
errors.push(ValidationError::new(
|
||||
name,
|
||||
"Required parameter is missing",
|
||||
));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate parameter if present
|
||||
if let Some(value) = parameters.get(name) {
|
||||
if let Err(error) = validate_parameter_value(name, value, schema) {
|
||||
errors.push(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for unknown parameters
|
||||
for name in parameters.keys() {
|
||||
if !schemas.contains_key(name) {
|
||||
errors.push(ValidationError::new(
|
||||
name,
|
||||
"Unknown parameter",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if errors.is_empty() {
|
||||
ValidationResult::success()
|
||||
} else {
|
||||
ValidationResult::failure(errors)
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates a single parameter value against its schema
|
||||
pub fn validate_parameter_value(
|
||||
name: &str,
|
||||
value: &serde_json::Value,
|
||||
schema: &ParameterSchema,
|
||||
) -> Result<(), ValidationError> {
|
||||
// Check type
|
||||
match (&schema.param_type, value) {
|
||||
(ParameterType::String, serde_json::Value::String(s)) => {
|
||||
validate_string_constraints(name, s, schema)?;
|
||||
}
|
||||
(ParameterType::Number, serde_json::Value::Number(n)) => {
|
||||
validate_number_constraints(name, n, schema)?;
|
||||
}
|
||||
(ParameterType::Boolean, serde_json::Value::Bool(_)) => {
|
||||
// Boolean values are always valid
|
||||
}
|
||||
(ParameterType::Array, serde_json::Value::Array(arr)) => {
|
||||
validate_array_constraints(name, arr, schema)?;
|
||||
}
|
||||
(ParameterType::Object, serde_json::Value::Object(_)) => {
|
||||
// Object validation could be more complex, but for now just check type
|
||||
}
|
||||
_ => {
|
||||
return Err(ValidationError::with_value(
|
||||
name,
|
||||
format!("Expected type {:?}, got {:?}", schema.param_type, get_value_type(value)),
|
||||
value.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Check enum constraints
|
||||
if let Some(enum_values) = &schema.r#enum {
|
||||
if !enum_values.contains(value) {
|
||||
return Err(ValidationError::with_value(
|
||||
name,
|
||||
format!("Value must be one of: {:?}", enum_values),
|
||||
value.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates string constraints
|
||||
fn validate_string_constraints(
|
||||
name: &str,
|
||||
value: &str,
|
||||
schema: &ParameterSchema,
|
||||
) -> Result<(), ValidationError> {
|
||||
// Check pattern
|
||||
if let Some(pattern) = &schema.pattern {
|
||||
let regex = Regex::new(pattern).map_err(|_| {
|
||||
ValidationError::new(name, "Invalid regex pattern in schema")
|
||||
})?;
|
||||
|
||||
if !regex.is_match(value) {
|
||||
return Err(ValidationError::with_value(
|
||||
name,
|
||||
format!("String does not match pattern: {}", pattern),
|
||||
serde_json::Value::String(value.to_string()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Check length constraints (using min/max as length bounds for strings)
|
||||
if let Some(min) = schema.min {
|
||||
if (value.len() as f64) < min {
|
||||
return Err(ValidationError::with_value(
|
||||
name,
|
||||
format!("String length must be at least {}", min),
|
||||
serde_json::Value::String(value.to_string()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(max) = schema.max {
|
||||
if (value.len() as f64) > max {
|
||||
return Err(ValidationError::with_value(
|
||||
name,
|
||||
format!("String length must be at most {}", max),
|
||||
serde_json::Value::String(value.to_string()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates number constraints
|
||||
fn validate_number_constraints(
|
||||
name: &str,
|
||||
value: &serde_json::Number,
|
||||
schema: &ParameterSchema,
|
||||
) -> Result<(), ValidationError> {
|
||||
let num_value = value.as_f64().unwrap_or(0.0);
|
||||
|
||||
if let Some(min) = schema.min {
|
||||
if num_value < min {
|
||||
return Err(ValidationError::with_value(
|
||||
name,
|
||||
format!("Number must be at least {}", min),
|
||||
serde_json::Value::Number(value.clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(max) = schema.max {
|
||||
if num_value > max {
|
||||
return Err(ValidationError::with_value(
|
||||
name,
|
||||
format!("Number must be at most {}", max),
|
||||
serde_json::Value::Number(value.clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates array constraints
|
||||
fn validate_array_constraints(
|
||||
name: &str,
|
||||
value: &[serde_json::Value],
|
||||
schema: &ParameterSchema,
|
||||
) -> Result<(), ValidationError> {
|
||||
// Check length constraints
|
||||
if let Some(min) = schema.min {
|
||||
if (value.len() as f64) < min {
|
||||
return Err(ValidationError::with_value(
|
||||
name,
|
||||
format!("Array length must be at least {}", min),
|
||||
serde_json::Value::Array(value.to_vec()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(max) = schema.max {
|
||||
if (value.len() as f64) > max {
|
||||
return Err(ValidationError::with_value(
|
||||
name,
|
||||
format!("Array length must be at most {}", max),
|
||||
serde_json::Value::Array(value.to_vec()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Validate items if schema is provided
|
||||
if let Some(items_schema) = &schema.items {
|
||||
for (index, item) in value.iter().enumerate() {
|
||||
let item_name = format!("{}[{}]", name, index);
|
||||
if let Err(error) = validate_parameter_value(&item_name, item, items_schema) {
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets the type of a JSON value
|
||||
fn get_value_type(value: &serde_json::Value) -> &'static str {
|
||||
match value {
|
||||
serde_json::Value::Null => "null",
|
||||
serde_json::Value::Bool(_) => "boolean",
|
||||
serde_json::Value::Number(_) => "number",
|
||||
serde_json::Value::String(_) => "string",
|
||||
serde_json::Value::Array(_) => "array",
|
||||
serde_json::Value::Object(_) => "object",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn test_validate_required_parameter() {
|
||||
let mut schemas = HashMap::new();
|
||||
schemas.insert("test".to_string(), ParameterSchema {
|
||||
param_type: ParameterType::String,
|
||||
required: Some(true),
|
||||
default: None,
|
||||
description: None,
|
||||
r#enum: None,
|
||||
min: None,
|
||||
max: None,
|
||||
pattern: None,
|
||||
items: None,
|
||||
properties: None,
|
||||
});
|
||||
|
||||
let parameters = HashMap::new();
|
||||
let result = validate_parameters(¶meters, &schemas);
|
||||
|
||||
assert!(!result.valid);
|
||||
assert_eq!(result.errors.len(), 1);
|
||||
assert_eq!(result.errors[0].path, "test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_string_parameter() {
|
||||
let mut schemas = HashMap::new();
|
||||
schemas.insert("test".to_string(), ParameterSchema {
|
||||
param_type: ParameterType::String,
|
||||
required: Some(true),
|
||||
default: None,
|
||||
description: None,
|
||||
r#enum: None,
|
||||
min: Some(3.0),
|
||||
max: Some(10.0),
|
||||
pattern: None,
|
||||
items: None,
|
||||
properties: None,
|
||||
});
|
||||
|
||||
let mut parameters = HashMap::new();
|
||||
parameters.insert("test".to_string(), json!("hello"));
|
||||
|
||||
let result = validate_parameters(¶meters, &schemas);
|
||||
assert!(result.valid);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user