github.com/blend/go-sdk@v1.20220411.3/validate/any.go (about)

     1  /*
     2  
     3  Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package validate
     9  
    10  import (
    11  	"reflect"
    12  
    13  	"github.com/blend/go-sdk/ex"
    14  )
    15  
    16  // Basic errors
    17  const (
    18  	ErrZero       ex.Class = "object should be its default value or unset"
    19  	ErrNotZero    ex.Class = "object should not be its default value or unset"
    20  	ErrRequired   ex.Class = "field is required"
    21  	ErrForbidden  ex.Class = "field is forbidden"
    22  	ErrEmpty      ex.Class = "object should be empty"
    23  	ErrNotEmpty   ex.Class = "object should not be empty"
    24  	ErrLen        ex.Class = "object should have a given length"
    25  	ErrNil        ex.Class = "object should be nil"
    26  	ErrNotNil     ex.Class = "object should not be nil"
    27  	ErrEquals     ex.Class = "objects should be equal"
    28  	ErrNotEquals  ex.Class = "objects should not be equal"
    29  	ErrAllowed    ex.Class = "objects should be one of a given set of allowed values"
    30  	ErrDisallowed ex.Class = "objects should not be one of a given set of disallowed values"
    31  )
    32  
    33  // Any returns a new AnyRefValidators.
    34  // AnyRef can be used to validate any type, but will be more limited
    35  // than using type specific validators.
    36  func Any(obj interface{}) AnyValidators {
    37  	return AnyValidators{Obj: obj}
    38  }
    39  
    40  // AnyValidators are validators for the empty interface{}.
    41  type AnyValidators struct {
    42  	Obj interface{}
    43  }
    44  
    45  // Forbidden mirrors Zero but uses a specific error.
    46  // This is useful if you want to have more aggressive failure cases.
    47  func (a AnyValidators) Forbidden() Validator {
    48  	return func() error {
    49  		if err := a.Zero()(); err != nil {
    50  			return Error(ErrForbidden, a.Obj)
    51  		}
    52  		return nil
    53  	}
    54  }
    55  
    56  // Required mirrors NotZero but uses a specific error.
    57  // This is useful if you want to have more aggressive failure cases.
    58  func (a AnyValidators) Required() Validator {
    59  	return func() error {
    60  		if err := a.NotZero()(); err != nil {
    61  			return Error(ErrRequired, a.Obj)
    62  		}
    63  		return nil
    64  	}
    65  }
    66  
    67  // Zero returns a validator that asserts an object is it's zero value.
    68  // This nil for pointers, slices, maps, channels.
    69  // And whatever equality passes for everything else with it's initialized value.
    70  // Note: this method uses reflect.Zero, there are faster .Zero evaluators
    71  // for the relevant numeric types.
    72  func (a AnyValidators) Zero() Validator {
    73  	return func() error {
    74  		if a.Obj == nil {
    75  			return nil
    76  		}
    77  
    78  		zero := reflect.Zero(reflect.TypeOf(a.Obj)).Interface()
    79  		if verr := a.Equals(zero)(); verr == nil {
    80  			return nil
    81  		}
    82  		return Error(ErrZero, a.Obj)
    83  	}
    84  }
    85  
    86  // NotZero returns a validator that a given field is set.
    87  // It will return an error if the field is unset.
    88  // Note: this method uses reflect.Zero, there are faster .NotZero evaluators
    89  // for the relevant numeric types.
    90  func (a AnyValidators) NotZero() Validator {
    91  	return func() error {
    92  		if err := a.Zero()(); err == nil {
    93  			return Error(ErrNotZero, a.Obj)
    94  		}
    95  		return nil
    96  	}
    97  }
    98  
    99  // Empty returns if a slice, map or channel is empty.
   100  // It will error if the object is not a slice, map or channel.
   101  func (a AnyValidators) Empty() Validator {
   102  	return func() error {
   103  		objLen, err := GetLength(a.Obj)
   104  		if err != nil {
   105  			return err
   106  		}
   107  		if objLen == 0 {
   108  			return nil
   109  		}
   110  		return Error(ErrEmpty, a.Obj)
   111  	}
   112  }
   113  
   114  // NotEmpty returns if a slice, map or channel is not empty.
   115  // It will error if the object is not a slice, map or channel.
   116  func (a AnyValidators) NotEmpty() Validator {
   117  	return func() error {
   118  		objLen, err := GetLength(a.Obj)
   119  		if err != nil {
   120  			return err
   121  		}
   122  		if objLen > 0 {
   123  			return nil
   124  		}
   125  		return Error(ErrNotEmpty, a.Obj)
   126  	}
   127  }
   128  
   129  // Len validates the length is a given value.
   130  func (a AnyValidators) Len(length int) Validator {
   131  	return func() error {
   132  		objLen, err := GetLength(a.Obj)
   133  		if err != nil {
   134  			return err
   135  		}
   136  		if objLen == length {
   137  			return nil
   138  		}
   139  		return Error(ErrLen, a.Obj)
   140  	}
   141  }
   142  
   143  // Nil validates the object is nil.
   144  func (a AnyValidators) Nil() Validator {
   145  	return func() error {
   146  		if IsNil(a.Obj) {
   147  			return nil
   148  		}
   149  		return Error(ErrNil, a.Obj)
   150  	}
   151  }
   152  
   153  // NotNil validates the object is not nil.
   154  // It also validates that the object is not an unset pointer.
   155  func (a AnyValidators) NotNil() Validator {
   156  	return func() error {
   157  		if verr := a.Nil()(); verr != nil {
   158  			return nil
   159  		}
   160  		return Error(ErrNotNil, a.Obj)
   161  	}
   162  }
   163  
   164  // Equals validates an object equals another object.
   165  func (a AnyValidators) Equals(expected interface{}) Validator {
   166  	return func() error {
   167  		actual := a.Obj
   168  
   169  		if IsNil(expected) && IsNil(actual) {
   170  			return nil
   171  		}
   172  		if (IsNil(expected) && !IsNil(actual)) || (!IsNil(expected) && IsNil(actual)) {
   173  			return Error(ErrEquals, a.Obj)
   174  		}
   175  
   176  		actualType := reflect.TypeOf(actual)
   177  		if actualType == nil {
   178  			return Error(ErrEquals, a.Obj)
   179  		}
   180  		expectedValue := reflect.ValueOf(expected)
   181  		if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
   182  			if !reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) {
   183  				return Error(ErrEquals, a.Obj)
   184  			}
   185  		}
   186  
   187  		if !reflect.DeepEqual(expected, actual) {
   188  			return Error(ErrEquals, a.Obj)
   189  		}
   190  		return nil
   191  	}
   192  }
   193  
   194  // NotEquals validates an object does not equal another object.
   195  func (a AnyValidators) NotEquals(expected interface{}) Validator {
   196  	return func() error {
   197  		if verr := a.Equals(expected)(); verr != nil {
   198  			return nil
   199  		}
   200  		return Error(ErrNotEquals, a.Obj)
   201  	}
   202  }
   203  
   204  // Allow validates a field is one of a given set of allowed values.
   205  func (a AnyValidators) Allow(values ...interface{}) Validator {
   206  	return func() error {
   207  		for _, expected := range values {
   208  			if verr := a.Equals(expected)(); verr == nil {
   209  				return nil
   210  			}
   211  		}
   212  		return Error(ErrAllowed, a.Obj)
   213  	}
   214  }
   215  
   216  // Disallow validates a field is one of a given set of allowed values.
   217  func (a AnyValidators) Disallow(values ...interface{}) Validator {
   218  	return func() error {
   219  		for _, expected := range values {
   220  			if verr := a.Equals(expected)(); verr == nil {
   221  				return Error(ErrDisallowed, a.Obj)
   222  			}
   223  		}
   224  		return nil
   225  	}
   226  }