@@ -205,8 +205,11 @@ func (attribute *Attribute) Validate(ctx context.Context, data interface{}, key
205205 // TODO what validation should do on these types
206206 rawError = attribute .validTable (ctx , data , key )
207207 default :
208+ if _ , ok := common .IsFieldTypeArray (attribute .PropertyType ); ok {
209+ rawError = attribute .validArray (ctx , data , key )
210+ break
211+ }
208212 // notice: 注意default 这里的实现逻辑, 用break 做了执行流程的终止。 pr 建议,降低圈复杂度
209-
210213 validator , exists := attrValidatorMap [fieldType ]
211214 if exists {
212215 rawError = validator (ctx , data , key )
@@ -231,6 +234,7 @@ func (attribute *Attribute) Validate(ctx context.Context, data interface{}, key
231234 }
232235 // 如果出现了问题,并且报错原内容为propertyID,则替换为propertyName。
233236 if rawError .ErrCode != 0 {
237+ blog .Errorf ("attribute validate failed,rawError:%v" , rawError )
234238 if key == attribute .PropertyID || key == common .BKPropertyValueField {
235239 rawError .Args = []interface {}{attribute .PropertyName }
236240 }
@@ -922,6 +926,161 @@ func (attribute *Attribute) validList(ctx context.Context, val interface{}, key
922926 }
923927}
924928
929+ func validArrayItem [T any ](ty string , data any ) ([]T , error ) {
930+ raw , ok := data .([]any )
931+ if ! ok {
932+ return nil , fmt .Errorf ("not []any" )
933+ }
934+ if len (raw ) == 0 {
935+ return make ([]T , 0 ), nil
936+ }
937+
938+ result := make ([]T , 0 , len (raw ))
939+
940+ for _ , v := range raw {
941+ var (
942+ resultItem any
943+ err error
944+ )
945+ switch ty {
946+ case common .FieldTypeBool :
947+ if resultItem , ok = v .(bool ); ! ok {
948+ err = fmt .Errorf ("array item type %T is not %v" , ty , common .FieldTypeBool )
949+ }
950+ case common .FieldTypeSingleChar , common .FieldTypeLongChar :
951+ if resultItem , ok = v .(string ); ! ok {
952+ err = fmt .Errorf ("array item type %T is not %v" , ty , common .FieldTypeSingleChar )
953+ }
954+ case common .FieldTypeInt :
955+ resultItem , err = util .GetInt64ByInterface (v )
956+ case common .FieldTypeFloat :
957+ resultItem , err = util .GetFloat64ByInterface (v )
958+ case common .FieldTypeDate :
959+ if ! util .IsDate (v ) {
960+ err = fmt .Errorf ("array item type %T is not %v" , ty , common .FieldTypeDate )
961+ }
962+ case common .FieldTypeTime :
963+ if _ , ok := util .IsTime (v ); ! ok {
964+ err = fmt .Errorf ("array item type %T is not %v" , ty , common .FieldTypeTime )
965+ }
966+ default :
967+ return nil , fmt .Errorf ("array item type %T is not support" , ty )
968+ }
969+ if err != nil {
970+ blog .Errorf ("array item type %T is not valid ,err:%v" , ty , err )
971+ return nil , err
972+ }
973+ item , ok := resultItem .(T )
974+ if ! ok {
975+ return nil , fmt .Errorf ("item type %T is not %T" , result , ty )
976+ }
977+ result = append (result , item )
978+ }
979+
980+ return result , nil
981+ }
982+
983+ func (attribute * Attribute ) validArray (ctx context.Context , val interface {}, key string ) errors.RawErrorInfo {
984+ rid := util .ExtractRequestUserFromContext (ctx )
985+ errorInfo := errors.RawErrorInfo {
986+ ErrCode : common .CCErrCommParamsInvalid ,
987+ Args : []interface {}{key },
988+ }
989+ if val == nil {
990+ if attribute .IsRequired {
991+ blog .Error ("params can not be null, array field key: %s, rid: %s" , key , rid )
992+ errorInfo .ErrCode = common .CCErrCommParamsNeedSet
993+ return errorInfo
994+ }
995+ return errors.RawErrorInfo {}
996+ }
997+ arrayOpt , err := ParseArrayOption (attribute .Option )
998+ if err != nil {
999+ errorInfo .Args = []interface {}{err }
1000+ return errorInfo
1001+ }
1002+
1003+ itemType , _ := common .IsFieldTypeArray (attribute .PropertyType )
1004+ switch itemType {
1005+ case common .FieldTypeBool , common .FieldTypeTime , common .FieldTypeDate :
1006+ _ , err := validArrayItem [any ](itemType , val )
1007+ if err != nil {
1008+ errorInfo .Args = []any {arrayOpt .CharOption , err }
1009+ return errorInfo
1010+ }
1011+ case common .FieldTypeSingleChar :
1012+ return attribute .validArrayString (itemType , val , key , rid , arrayOpt )
1013+ case common .FieldTypeInt :
1014+ result , err := validArrayItem [int64 ](itemType , val )
1015+ if err != nil {
1016+ blog .Errorf ("array params %s not valid,value:%v,option:%#v,err:%v, rid: %s" , key , val , arrayOpt .IntOption , err , rid )
1017+ errorInfo .Args = []any {arrayOpt .IntOption , err }
1018+ return errorInfo
1019+ }
1020+ for _ , v := range result {
1021+ if arrayOpt .IntOption .Min > v || arrayOpt .IntOption .Max < v {
1022+ errorInfo .Args = []any {arrayOpt .IntOption , "array item(int) option valid" }
1023+ return errorInfo
1024+ }
1025+ }
1026+
1027+ case common .FieldTypeFloat :
1028+ result , err := validArrayItem [float64 ](itemType , val )
1029+ if err != nil {
1030+ blog .Errorf ("array params %s not valid,value:%v,option:%#v,err:%v, rid: %s" , key , val ,
1031+ arrayOpt .FloatOption , err , rid )
1032+ errorInfo .Args = []any {arrayOpt .FloatOption , err }
1033+ return errorInfo
1034+ }
1035+ for _ , v := range result {
1036+ if arrayOpt .FloatOption .Min > v || arrayOpt .FloatOption .Max < v {
1037+ errorInfo .Args = []any {arrayOpt .FloatOption , "array item(float) option valid" }
1038+ return errorInfo
1039+ }
1040+ }
1041+ default :
1042+ blog .Errorf ("array item not support type:%v %v %v" , key , val , rid )
1043+ errorInfo .Args = []any {attribute .Option , fmt .Errorf ("array item not support" )}
1044+ return errorInfo
1045+ }
1046+
1047+ return errors.RawErrorInfo {}
1048+ }
1049+
1050+ func (attribute * Attribute ) validArrayString (itemType string , val interface {}, key string ,
1051+ rid string , arrayOpt ArrayOption ) errors.RawErrorInfo {
1052+
1053+ errorInfo := errors.RawErrorInfo {
1054+ ErrCode : common .CCErrCommParamsInvalid ,
1055+ Args : []interface {}{key },
1056+ }
1057+ value , err := validArrayItem [string ](itemType , val )
1058+ if err != nil {
1059+ blog .Errorf ("array params %s not valid,value: %v, option:%#v,err:%v,rid: %s" , key , val , attribute .Option , err , rid )
1060+ errorInfo .Args = []any {attribute .Option , err }
1061+ return errorInfo
1062+ }
1063+ strReg , err := regexp .Compile (arrayOpt .CharOption )
1064+ if err != nil {
1065+ blog .Errorf (`regexp "%s" invalid, err: %v, rid: %s` , arrayOpt , err , rid )
1066+ errorInfo .Args = []interface {}{arrayOpt }
1067+ return errorInfo
1068+ }
1069+ for _ , v := range value {
1070+ if len (v ) > common .FieldTypeSingleLenChar {
1071+ blog .Errorf ("params over length %d, rid: %s" , common .FieldTypeSingleLenChar , rid )
1072+ errorInfo .ErrCode = common .CCErrCommOverLimit
1073+ return errorInfo
1074+ }
1075+ if ! strReg .MatchString (v ) {
1076+ blog .Errorf (`params "%s" not match regexp "%s", rid: %s` , val , arrayOpt , rid )
1077+ errorInfo .ErrCode = common .CCErrFieldRegValidFailed
1078+ return errorInfo
1079+ }
1080+ }
1081+ return errors.RawErrorInfo {}
1082+ }
1083+
9251084// validOrganization valid object attribute that is organization type
9261085func (attribute * Attribute ) validOrganization (ctx context.Context , val interface {}, key string ) errors.RawErrorInfo {
9271086 rid := util .ExtractRequestIDFromContext (ctx )
@@ -1573,12 +1732,42 @@ func ParseListOption(option interface{}) (ListOption, error) {
15731732 return valueList , nil
15741733}
15751734
1735+ // ArrayOption list option
1736+ type ArrayOption struct {
1737+ BoolOption string `json:"bool" bson:"bool"`
1738+ CharOption string `json:"char" bson:"char"`
1739+ IntOption IntOption `json:"int" bson:"int"`
1740+ FloatOption FloatOption `json:"float" bson:"float"`
1741+ DateOption string `json:"date" bson:"date"`
1742+ TimeOption string `json:"time" bson:"time"`
1743+ }
1744+
1745+ // ParseArrayOption parse 'array' type option
1746+ func ParseArrayOption (option interface {}) (ArrayOption , error ) {
1747+ if option == nil {
1748+ return ArrayOption {}, fmt .Errorf ("array type field option is null" )
1749+ }
1750+ if value , ok := option .(ArrayOption ); ok {
1751+ return value , nil
1752+ }
1753+ var result ArrayOption
1754+ marshal , err := json .Marshal (option )
1755+ if err != nil {
1756+ return result , err
1757+ }
1758+ err = json .Unmarshal (marshal , & result )
1759+ if err != nil {
1760+ return result , fmt .Errorf ("array option %+v type %T is invalid,err:%v" , option , result , err )
1761+ }
1762+ return result , nil
1763+ }
1764+
15761765// PrettyValue TODO
1766+ // NOCC:golint/fnsize(字段类型与其校验规则较多)
15771767func (attribute Attribute ) PrettyValue (ctx context.Context , val interface {}) (string , error ) {
15781768 if val == nil {
15791769 return "" , nil
15801770 }
1581-
15821771 fieldType := attribute .PropertyType
15831772 switch fieldType {
15841773 case common .FieldTypeSingleChar , common .FieldTypeLongChar :
@@ -1674,6 +1863,9 @@ func (attribute Attribute) PrettyValue(ctx context.Context, val interface{}) (st
16741863 }
16751864 return "" , fmt .Errorf ("invalid value for list, value: %s, options: %+v" , strVal , listOption )
16761865 default :
1866+ if _ , ok := common .IsFieldTypeArray (fieldType ); ok {
1867+ return fmt .Sprintf ("%v" , val ), nil
1868+ }
16771869 blog .V (3 ).Infof ("unexpected property type: %s" , fieldType )
16781870 return fmt .Sprintf ("%#v" , val ), nil
16791871 }
0 commit comments