github.com/artisanhe/tools@v1.0.1-0.20210607022958-19a8fef2eb04/courier/swagger/gen/openapi_common.go (about)

     1  package gen
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"regexp"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/go-courier/oas"
    11  	"github.com/go-courier/ptr"
    12  )
    13  
    14  var (
    15  	rxValidate = regexp.MustCompile(`^@([^\[\(\{]+)([\[\(\{])([^\}^\]^\)]+)([\}\]\)])$`)
    16  )
    17  
    18  func BindValidateFromValidateTagString(schema *oas.Schema, validate string) {
    19  	commonValidations := getCommonValidations(validate)
    20  	bindSchemaWithValidations(schema, commonValidations)
    21  	schema.AddExtension(XTagValidate, validate)
    22  }
    23  
    24  func getCommonValidations(validateTag string) (commonValidations oas.SchemaValidation) {
    25  	var matched = rxValidate.FindAllStringSubmatch(validateTag, -1)
    26  
    27  	// "@int[1,2]", "int", "[", "1,2", "]"
    28  	if len(matched) > 0 && len(matched[0]) == 5 {
    29  		tpe := matched[0][1]
    30  		startBracket := matched[0][2]
    31  		endBracket := matched[0][4]
    32  		values := strings.Split(matched[0][3], ",")
    33  
    34  		if startBracket != "{" && endBracket != "}" {
    35  			switch tpe {
    36  			case "byte", "int", "int8", "int16", "int32", "int64", "rune", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "float32", "float64":
    37  				if len(values) > 0 {
    38  					if val, err := strconv.ParseFloat(values[0], 64); err == nil {
    39  						commonValidations.Minimum = &val
    40  						commonValidations.ExclusiveMinimum = (startBracket == "(")
    41  					}
    42  				}
    43  				if len(values) > 1 {
    44  					if val, err := strconv.ParseFloat(values[1], 64); err == nil {
    45  						commonValidations.Maximum = &val
    46  						commonValidations.ExclusiveMaximum = (endBracket == ")")
    47  					}
    48  				}
    49  			case "string":
    50  				if len(values) > 0 {
    51  					if val, err := strconv.ParseInt(values[0], 10, 64); err == nil {
    52  						commonValidations.MinLength = ptr.Uint64(uint64(val))
    53  					}
    54  				}
    55  				if len(values) > 1 {
    56  					if val, err := strconv.ParseInt(values[1], 10, 64); err == nil {
    57  						commonValidations.MaxLength = ptr.Uint64(uint64(val))
    58  					}
    59  				}
    60  			}
    61  		} else {
    62  			enums := make([]interface{}, 0)
    63  
    64  			for _, value := range values {
    65  				if tpe != "string" {
    66  					if val, err := strconv.ParseInt(value, 10, 64); err == nil {
    67  						enums = append(enums, val)
    68  					}
    69  				} else {
    70  					enums = append(enums, value)
    71  				}
    72  			}
    73  
    74  			commonValidations.Enum = enums
    75  		}
    76  	}
    77  
    78  	return
    79  }
    80  
    81  func bindSchemaWithValidations(schema *oas.Schema, schemaValidation oas.SchemaValidation) {
    82  	schema.SchemaValidation = schemaValidation
    83  
    84  	// for partial enum
    85  	if len(schema.Enum) != 0 && len(schemaValidation.Enum) != 0 {
    86  		var enums []interface{}
    87  
    88  		for _, enumValueOrIndex := range schemaValidation.Enum {
    89  			switch reflect.TypeOf(enumValueOrIndex).Name() {
    90  			case "string":
    91  				if enumContainsValue(schema.Enum, enumValueOrIndex) {
    92  					enums = append(enums, enumValueOrIndex)
    93  				} else if enumValueOrIndex != "" {
    94  					panic(fmt.Errorf("%s is not value of %s", enumValueOrIndex, schema.Enum))
    95  				}
    96  			default:
    97  				if idx, ok := enumValueOrIndex.(int); ok {
    98  					if schema.Enum[idx] != nil {
    99  						enums = append(enums, schema.Enum[idx])
   100  					} else if idx != 0 {
   101  						panic(fmt.Errorf("%s is out-range of  %s", enumValueOrIndex, schema.Enum))
   102  					}
   103  				}
   104  
   105  			}
   106  		}
   107  
   108  		schema.Enum = enums
   109  	}
   110  }
   111  
   112  func enumContainsValue(enum []interface{}, value interface{}) bool {
   113  	var isContains = false
   114  
   115  	for _, enumValue := range enum {
   116  		if enumValue == value {
   117  			isContains = true
   118  		}
   119  	}
   120  
   121  	return isContains
   122  }