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