use serde::{Deserialize, Serialize};
use crate::error::{FraiseQLError, ValidationFieldError};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphQLValidationError {
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub extensions: Option<ValidationErrorExtensions>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationErrorExtensions {
pub code: String,
pub rule_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub field_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphQLValidationResponse {
pub errors: Vec<GraphQLValidationError>,
pub error_count: usize,
}
impl GraphQLValidationResponse {
#[must_use]
pub const fn new() -> Self {
Self {
errors: Vec::new(),
error_count: 0,
}
}
pub fn add_field_error(
&mut self,
field_error: ValidationFieldError,
context: Option<serde_json::Value>,
) {
let path = Self::parse_path(&field_error.field);
let extensions = ValidationErrorExtensions {
code: "VALIDATION_FAILED".to_string(),
rule_type: field_error.rule_type,
field_path: Some(field_error.field.clone()),
context,
};
self.errors.push(GraphQLValidationError {
message: format!("Validation failed: {}", field_error.message),
path: Some(path),
extensions: Some(extensions),
});
self.error_count += 1;
}
pub fn add_errors(&mut self, errors: Vec<ValidationFieldError>) {
for error in errors {
self.add_field_error(error, None);
}
}
#[must_use]
pub fn from_error(error: &FraiseQLError) -> Option<Self> {
if let FraiseQLError::Validation { message, path } = error {
let mut response = Self::new();
response.errors.push(GraphQLValidationError {
message: message.clone(),
path: path.as_ref().map(|p| Self::parse_path(p)),
extensions: Some(ValidationErrorExtensions {
code: "VALIDATION_FAILED".to_string(),
rule_type: "unknown".to_string(),
field_path: path.clone(),
context: None,
}),
});
response.error_count = 1;
Some(response)
} else {
None
}
}
pub(crate) fn parse_path(path: &str) -> Vec<String> {
path.split('.').map(|s| s.to_string()).collect()
}
#[must_use]
pub const fn has_errors(&self) -> bool {
!self.errors.is_empty()
}
#[must_use]
pub fn to_graphql_errors(&self) -> serde_json::Value {
serde_json::json!({
"errors": self.errors,
"error_count": self.error_count
})
}
}
impl Default for GraphQLValidationResponse {
fn default() -> Self {
Self::new()
}
}