length.go raw

   1  // Copyright 2016 Qiang Xue. All rights reserved.
   2  // Use of this source code is governed by a MIT-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package validation
   6  
   7  import (
   8  	"unicode/utf8"
   9  )
  10  
  11  var (
  12  	// ErrLengthTooLong is the error that returns in case of too long length.
  13  	ErrLengthTooLong = NewError("validation_length_too_long", "the length must be no more than {{.max}}")
  14  	// ErrLengthTooShort is the error that returns in case of too short length.
  15  	ErrLengthTooShort = NewError("validation_length_too_short", "the length must be no less than {{.min}}")
  16  	// ErrLengthInvalid is the error that returns in case of an invalid length.
  17  	ErrLengthInvalid = NewError("validation_length_invalid", "the length must be exactly {{.min}}")
  18  	// ErrLengthOutOfRange is the error that returns in case of out of range length.
  19  	ErrLengthOutOfRange = NewError("validation_length_out_of_range", "the length must be between {{.min}} and {{.max}}")
  20  	// ErrLengthEmptyRequired is the error that returns in case of non-empty value.
  21  	ErrLengthEmptyRequired = NewError("validation_length_empty_required", "the value must be empty")
  22  )
  23  
  24  // Length returns a validation rule that checks if a value's length is within the specified range.
  25  // If max is 0, it means there is no upper bound for the length.
  26  // This rule should only be used for validating strings, slices, maps, and arrays.
  27  // An empty value is considered valid. Use the Required rule to make sure a value is not empty.
  28  func Length(min, max int) LengthRule {
  29  	return LengthRule{min: min, max: max, err: buildLengthRuleError(min, max)}
  30  }
  31  
  32  // RuneLength returns a validation rule that checks if a string's rune length is within the specified range.
  33  // If max is 0, it means there is no upper bound for the length.
  34  // This rule should only be used for validating strings, slices, maps, and arrays.
  35  // An empty value is considered valid. Use the Required rule to make sure a value is not empty.
  36  // If the value being validated is not a string, the rule works the same as Length.
  37  func RuneLength(min, max int) LengthRule {
  38  	r := Length(min, max)
  39  	r.rune = true
  40  
  41  	return r
  42  }
  43  
  44  // LengthRule is a validation rule that checks if a value's length is within the specified range.
  45  type LengthRule struct {
  46  	err Error
  47  
  48  	min, max int
  49  	rune     bool
  50  }
  51  
  52  // Validate checks if the given value is valid or not.
  53  func (r LengthRule) Validate(value interface{}) error {
  54  	value, isNil := Indirect(value)
  55  	if isNil || IsEmpty(value) {
  56  		return nil
  57  	}
  58  
  59  	var (
  60  		l   int
  61  		err error
  62  	)
  63  	if s, ok := value.(string); ok && r.rune {
  64  		l = utf8.RuneCountInString(s)
  65  	} else if l, err = LengthOfValue(value); err != nil {
  66  		return err
  67  	}
  68  
  69  	if r.min > 0 && l < r.min || r.max > 0 && l > r.max || r.min == 0 && r.max == 0 && l > 0 {
  70  		return r.err
  71  	}
  72  
  73  	return nil
  74  }
  75  
  76  // Error sets the error message for the rule.
  77  func (r LengthRule) Error(message string) LengthRule {
  78  	r.err = r.err.SetMessage(message)
  79  	return r
  80  }
  81  
  82  // ErrorObject sets the error struct for the rule.
  83  func (r LengthRule) ErrorObject(err Error) LengthRule {
  84  	r.err = err
  85  	return r
  86  }
  87  
  88  func buildLengthRuleError(min, max int) (err Error) {
  89  	if min == 0 && max > 0 {
  90  		err = ErrLengthTooLong
  91  	} else if min > 0 && max == 0 {
  92  		err = ErrLengthTooShort
  93  	} else if min > 0 && max > 0 {
  94  		if min == max {
  95  			err = ErrLengthInvalid
  96  		} else {
  97  			err = ErrLengthOutOfRange
  98  		}
  99  	} else {
 100  		err = ErrLengthEmptyRequired
 101  	}
 102  
 103  	return err.SetParams(map[string]interface{}{"min": min, "max": max})
 104  }
 105