github.com/go-email-validator/go-email-validator@v0.0.0-20230409163946-b8b9e6a0552e/pkg/ev/validator_dep.go (about)

     1  package ev
     2  
     3  import (
     4  	"sync"
     5  )
     6  
     7  // DepValidatorName is name of validator with dependencies
     8  const DepValidatorName ValidatorName = "depValidator"
     9  
    10  // ValidatorMap alias for map[ValidatorName]Validator
    11  type ValidatorMap map[ValidatorName]Validator
    12  
    13  // NewDepsError creates DepsError
    14  func NewDepsError() error {
    15  	return &DepsError{}
    16  }
    17  
    18  // DepsError is DepValidatorName error
    19  type DepsError struct{}
    20  
    21  func (*DepsError) Error() string {
    22  	return "DepsError"
    23  }
    24  
    25  // NewDepValidator instantiates DepValidatorName validator
    26  func NewDepValidator(deps ValidatorMap) Validator {
    27  	return depValidator{deps: deps}
    28  }
    29  
    30  type depValidator struct {
    31  	AValidatorWithoutDeps
    32  	deps ValidatorMap
    33  }
    34  
    35  func (d depValidator) Validate(input Input, _ ...ValidationResult) ValidationResult {
    36  	var waiters, waitersMutex = make(map[ValidatorName][]*sync.WaitGroup), sync.RWMutex{}
    37  	var validationResultsByName, validationResultsMutex = make(map[ValidatorName]ValidationResult), sync.RWMutex{}
    38  	var isValid = true
    39  	var starter, finisher = sync.WaitGroup{}, sync.WaitGroup{}
    40  	starter.Add(1)
    41  	finisher.Add(len(d.deps))
    42  
    43  	for key, validator := range d.deps {
    44  		var depWaiter *sync.WaitGroup
    45  		var depWaiters []*sync.WaitGroup
    46  		var deps []ValidatorName
    47  		var ok bool
    48  
    49  		deps = validator.GetDeps()
    50  		if len(deps) > 0 {
    51  			depWaiter = &sync.WaitGroup{}
    52  			depWaiter.Add(len(deps))
    53  
    54  			for _, dep := range deps {
    55  				if depWaiters, ok = waiters[dep]; !ok {
    56  					depWaiters = make([]*sync.WaitGroup, 0)
    57  				}
    58  				waiters[dep] = append(depWaiters, depWaiter)
    59  			}
    60  		}
    61  
    62  		go func(key ValidatorName, validator Validator, depWaiter *sync.WaitGroup) {
    63  			var results []ValidationResult
    64  
    65  			// TODO add recover
    66  			starter.Wait()
    67  			if depWaiter != nil {
    68  				depWaiter.Wait()
    69  
    70  				results = make([]ValidationResult, len(deps))
    71  				validationResultsMutex.RLock()
    72  				for i, dep := range deps {
    73  					results[i] = validationResultsByName[dep]
    74  				}
    75  				validationResultsMutex.RUnlock()
    76  			}
    77  
    78  			var result = validator.Validate(input, results...)
    79  			validationResultsMutex.Lock()
    80  			validationResultsByName[key] = result
    81  			isValid = isValid && result.IsValid()
    82  			validationResultsMutex.Unlock()
    83  
    84  			waitersMutex.RLock()
    85  			if depWaiters, ok = waiters[key]; ok {
    86  				for _, depWaiter := range depWaiters {
    87  					depWaiter.Done()
    88  				}
    89  			}
    90  			waitersMutex.RUnlock()
    91  			finisher.Done()
    92  		}(key, validator, depWaiter)
    93  	}
    94  	starter.Done()
    95  	finisher.Wait()
    96  
    97  	return NewDepValidatorResult(isValid, validationResultsByName)
    98  }
    99  
   100  // DepResult is alias for results of nested validators
   101  type DepResult map[ValidatorName]ValidationResult
   102  
   103  // DepValidationResult is representation of DepValidatorName result
   104  type DepValidationResult interface {
   105  	ValidationResult
   106  	GetResults() DepResult
   107  }
   108  
   109  // NewDepValidatorResult returns DepValidatorName result
   110  func NewDepValidatorResult(isValid bool, results DepResult) ValidationResult {
   111  	return depValidationResult{
   112  		isValid: isValid,
   113  		results: results,
   114  	}
   115  }
   116  
   117  type depValidationResult struct {
   118  	isValid bool
   119  	results DepResult
   120  }
   121  
   122  func (d depValidationResult) GetResults() DepResult {
   123  	return d.results
   124  }
   125  
   126  func (d depValidationResult) IsValid() bool {
   127  	return d.isValid
   128  }
   129  
   130  func (d depValidationResult) Errors() (errors []error) {
   131  	for _, result := range d.GetResults() {
   132  		errors = append(errors, result.Errors()...)
   133  	}
   134  
   135  	return errors
   136  }
   137  
   138  func (d depValidationResult) HasErrors() bool {
   139  	for _, result := range d.GetResults() {
   140  		if result.HasErrors() {
   141  			return true
   142  		}
   143  	}
   144  
   145  	return false
   146  }
   147  
   148  func (d depValidationResult) Warnings() (warnings []error) {
   149  	for _, result := range d.GetResults() {
   150  		warnings = append(warnings, result.Warnings()...)
   151  	}
   152  
   153  	return warnings
   154  }
   155  
   156  func (d depValidationResult) HasWarnings() bool {
   157  	for _, result := range d.GetResults() {
   158  		if result.HasWarnings() {
   159  			return true
   160  		}
   161  	}
   162  
   163  	return false
   164  }
   165  
   166  func (d depValidationResult) ValidatorName() ValidatorName {
   167  	return DepValidatorName
   168  }