Files
mq/services/enhanced_validation.go
2025-09-18 18:26:35 +05:45

282 lines
7.4 KiB
Go

package services
import (
"context"
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/oarkflow/mq/dag"
)
// Enhanced validation implementation
type enhancedValidation struct {
config *ValidationServiceConfig
base Validation
}
// NewEnhancedValidation creates a new enhanced validation service
func NewEnhancedValidation(config *ValidationServiceConfig) (EnhancedValidation, error) {
// Create base validation (assuming ValidationInstance is available)
if ValidationInstance == nil {
return nil, fmt.Errorf("base validation instance not available")
}
return &enhancedValidation{
config: config,
base: ValidationInstance,
}, nil
}
// Make implements the base Validation interface
func (ev *enhancedValidation) Make(ctx *fiber.Ctx, data any, rules map[string]string, options ...Option) (Validator, error) {
return ev.base.Make(ctx, data, rules, options...)
}
// AddRules implements the base Validation interface
func (ev *enhancedValidation) AddRules(rules []Rule) error {
return ev.base.AddRules(rules)
}
// Rules implements the base Validation interface
func (ev *enhancedValidation) Rules() []Rule {
return ev.base.Rules()
}
// ValidateWorkflowInput validates input using workflow validation rules
func (ev *enhancedValidation) ValidateWorkflowInput(ctx context.Context, input map[string]any, rules []*dag.WorkflowValidationRule) (ValidationResult, error) {
result := ValidationResult{
Valid: true,
Errors: make(map[string]string),
Data: input,
}
for _, rule := range rules {
if err := ev.validateField(input, rule, &result); err != nil {
return result, err
}
}
return result, nil
}
// CreateValidationProcessor creates a validator processor from rules
func (ev *enhancedValidation) CreateValidationProcessor(rules []*dag.WorkflowValidationRule) (*dag.ValidatorProcessor, error) {
config := &dag.WorkflowNodeConfig{
ValidationType: "custom",
ValidationRules: make([]dag.WorkflowValidationRule, len(rules)),
}
// Convert pointer slice to value slice
for i, rule := range rules {
config.ValidationRules[i] = *rule
}
// Create processor factory and get validator processor
factory := dag.NewProcessorFactory()
processor, err := factory.CreateProcessor("validator", config)
if err != nil {
return nil, fmt.Errorf("failed to create validator processor: %w", err)
}
// Type assert to ValidatorProcessor
validatorProcessor, ok := processor.(*dag.ValidatorProcessor)
if !ok {
return nil, fmt.Errorf("processor is not a ValidatorProcessor")
}
return validatorProcessor, nil
}
// Helper method to validate individual fields
func (ev *enhancedValidation) validateField(input map[string]any, rule *dag.WorkflowValidationRule, result *ValidationResult) error {
value, exists := input[rule.Field]
// Check required fields
if rule.Required && (!exists || value == nil || value == "") {
result.Valid = false
result.Errors[rule.Field] = rule.Message
if result.Errors[rule.Field] == "" {
result.Errors[rule.Field] = fmt.Sprintf("Field %s is required", rule.Field)
}
return nil
}
// Skip validation if field doesn't exist and is not required
if !exists {
return nil
}
// Validate based on type
switch rule.Type {
case "string":
if err := ev.validateString(value, rule, result); err != nil {
return err
}
case "number":
if err := ev.validateNumber(value, rule, result); err != nil {
return err
}
case "email":
if err := ev.validateEmail(value, rule, result); err != nil {
return err
}
case "bool":
if err := ev.validateBool(value, rule, result); err != nil {
return err
}
default:
// Custom validation type
if err := ev.validateCustom(value, rule, result); err != nil {
return err
}
}
return nil
}
func (ev *enhancedValidation) validateString(value any, rule *dag.WorkflowValidationRule, result *ValidationResult) error {
str, ok := value.(string)
if !ok {
result.Valid = false
result.Errors[rule.Field] = fmt.Sprintf("Field %s must be a string", rule.Field)
return nil
}
// Check length constraints
if rule.MinLength > 0 && len(str) < rule.MinLength {
result.Valid = false
result.Errors[rule.Field] = fmt.Sprintf("Field %s must be at least %d characters", rule.Field, rule.MinLength)
return nil
}
if rule.MaxLength > 0 && len(str) > rule.MaxLength {
result.Valid = false
result.Errors[rule.Field] = fmt.Sprintf("Field %s must be at most %d characters", rule.Field, rule.MaxLength)
return nil
}
// Check pattern
if rule.Pattern != "" {
// Simple pattern matching - in practice, you'd use regex
// This is a placeholder implementation
if rule.Pattern == "^[a-zA-Z\\s]+$" && !isAlphaSpace(str) {
result.Valid = false
result.Errors[rule.Field] = rule.Message
if result.Errors[rule.Field] == "" {
result.Errors[rule.Field] = fmt.Sprintf("Field %s contains invalid characters", rule.Field)
}
return nil
}
}
return nil
}
func (ev *enhancedValidation) validateNumber(value any, rule *dag.WorkflowValidationRule, result *ValidationResult) error {
var num float64
var ok bool
switch v := value.(type) {
case float64:
num = v
ok = true
case int:
num = float64(v)
ok = true
case int64:
num = float64(v)
ok = true
default:
ok = false
}
if !ok {
result.Valid = false
result.Errors[rule.Field] = fmt.Sprintf("Field %s must be a number", rule.Field)
return nil
}
// Check range constraints
if rule.Min != nil && num < *rule.Min {
result.Valid = false
result.Errors[rule.Field] = fmt.Sprintf("Field %s must be at least %f", rule.Field, *rule.Min)
return nil
}
if rule.Max != nil && num > *rule.Max {
result.Valid = false
result.Errors[rule.Field] = fmt.Sprintf("Field %s must be at most %f", rule.Field, *rule.Max)
return nil
}
return nil
}
func (ev *enhancedValidation) validateEmail(value any, rule *dag.WorkflowValidationRule, result *ValidationResult) error {
email, ok := value.(string)
if !ok {
result.Valid = false
result.Errors[rule.Field] = fmt.Sprintf("Field %s must be a string", rule.Field)
return nil
}
// Simple email validation - in practice, you'd use a proper email validator
if !isValidEmail(email) {
result.Valid = false
result.Errors[rule.Field] = rule.Message
if result.Errors[rule.Field] == "" {
result.Errors[rule.Field] = fmt.Sprintf("Field %s must be a valid email", rule.Field)
}
return nil
}
return nil
}
func (ev *enhancedValidation) validateBool(value any, rule *dag.WorkflowValidationRule, result *ValidationResult) error {
_, ok := value.(bool)
if !ok {
result.Valid = false
result.Errors[rule.Field] = fmt.Sprintf("Field %s must be a boolean", rule.Field)
return nil
}
return nil
}
func (ev *enhancedValidation) validateCustom(value any, rule *dag.WorkflowValidationRule, result *ValidationResult) error {
// Custom validation logic - implement based on your needs
// For now, just accept any value for custom types
return nil
}
// Helper functions for validation
func isAlphaSpace(s string) bool {
for _, r := range s {
if !((r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || r == ' ') {
return false
}
}
return true
}
func isValidEmail(email string) bool {
// Very basic email validation - in practice, use a proper email validator
return len(email) > 3 &&
len(email) < 255 &&
contains(email, "@") &&
contains(email, ".") &&
email[0] != '@' &&
email[len(email)-1] != '@'
}
func contains(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}