55 "os"
66 "reflect"
77 "regexp"
8+ "strconv"
89
910 "github.com/saltyorg/sb-go/internal/logging"
1011
@@ -227,6 +228,19 @@ func (s *Schema) validateFieldWithTypeFlexibility(value any, rule *SchemaRule, p
227228 "password" : "validate_password_strength" ,
228229 }
229230
231+ switch rule .Type {
232+ case "number" :
233+ logging .DebugBool (verboseMode , "Running built-in number validator for field '%s'" , path )
234+ if err := validateNumberValue (value ); err != nil {
235+ return fmt .Errorf ("field '%s': %w" , path , err )
236+ }
237+ case "float" :
238+ logging .DebugBool (verboseMode , "Running built-in float validator for field '%s'" , path )
239+ if err := validateFloatValue (value ); err != nil {
240+ return fmt .Errorf ("field '%s': %w" , path , err )
241+ }
242+ }
243+
230244 if validatorName , isBuiltIn := builtInValidators [rule .Type ]; isBuiltIn {
231245 logging .DebugBool (verboseMode , "Running built-in %s validator for field '%s'" , rule .Type , path )
232246 if validator , exists := customValidators [validatorName ]; exists {
@@ -447,6 +461,9 @@ func (s *Schema) validateType(value any, rule *SchemaRule, path string) error {
447461 if rule .Type == "number" {
448462 // "number" type accepts strings and integers, but NOT floats (for whole numbers with flexibility)
449463 if valueType == "string" || valueType == "integer" {
464+ if err := validateNumberValue (value ); err != nil {
465+ return fmt .Errorf ("field '%s': %w" , path , err )
466+ }
450467 logging .DebugBool (verboseMode , "validateType - number field accepts string/integer, allowing %s" , valueType )
451468 return nil
452469 }
@@ -463,6 +480,9 @@ func (s *Schema) validateType(value any, rule *SchemaRule, path string) error {
463480 if rule .Type == "float" {
464481 // "float" type accepts strings and actual floats, but not integers (to be explicit about decimals)
465482 if valueType == "string" || valueType == "float" {
483+ if err := validateFloatValue (value ); err != nil {
484+ return fmt .Errorf ("field '%s': %w" , path , err )
485+ }
466486 logging .DebugBool (verboseMode , "validateType - float field accepts string/float, allowing %s" , valueType )
467487 return nil
468488 }
@@ -661,3 +681,39 @@ func isEmptyValue(value any) bool {
661681
662682 return false
663683}
684+
685+ func validateNumberValue (value any ) error {
686+ switch v := value .(type ) {
687+ case string :
688+ if _ , err := strconv .Atoi (v ); err != nil {
689+ return fmt .Errorf ("must be a whole number (integer), got: %s" , v )
690+ }
691+ return nil
692+ case int , int8 , int16 , int32 , int64 :
693+ return nil
694+ case uint , uint8 , uint16 , uint32 , uint64 :
695+ return nil
696+ case float32 , float64 :
697+ return fmt .Errorf ("must be a whole number (integer), got: %v" , v )
698+ default :
699+ return fmt .Errorf ("must be a whole number (integer), got: %T" , value )
700+ }
701+ }
702+
703+ func validateFloatValue (value any ) error {
704+ switch v := value .(type ) {
705+ case string :
706+ if _ , err := strconv .ParseFloat (v , 64 ); err != nil {
707+ return fmt .Errorf ("must be a float, got: %s" , v )
708+ }
709+ return nil
710+ case float32 , float64 :
711+ return nil
712+ case int , int8 , int16 , int32 , int64 :
713+ return fmt .Errorf ("must be a float, got: %v" , v )
714+ case uint , uint8 , uint16 , uint32 , uint64 :
715+ return fmt .Errorf ("must be a float, got: %v" , v )
716+ default :
717+ return fmt .Errorf ("must be a float, got: %T" , value )
718+ }
719+ }
0 commit comments