-
Notifications
You must be signed in to change notification settings - Fork 1.6k
feat:新增数组字段 --story=128495448 字段类型: 数组 #8591
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
elizabevil
wants to merge
1
commit into
TencentBlueKing:v3.14.x
Choose a base branch
from
elizabevil:v3.14.x-feat-array
base: v3.14.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| /* | ||
| * Tencent is pleased to support the open source community by making 蓝鲸 available. | ||
| * Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved. | ||
| * Licensed under the MIT License (the "License"); you may not use this file except | ||
| * in compliance with the License. You may obtain a copy of the License at | ||
| * http://opensource.org/licenses/MIT | ||
| * Unless required by applicable law or agreed to in writing, software distributed under | ||
| * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, | ||
| * either express or implied. See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package metadata | ||
|
|
||
| import ( | ||
| "configcenter/src/common/util" | ||
| "encoding/json" | ||
| "fmt" | ||
elizabevil marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "math" | ||
|
|
||
| "github.com/tidwall/gjson" | ||
| "go.mongodb.org/mongo-driver/bson" | ||
| ) | ||
|
|
||
| // ArrayOption len cap ,option is basic type 's option | ||
| type ArrayOption[T any] struct { | ||
elizabevil marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Len int `bson:"len" json:"len"` | ||
| Cap int `bson:"cap" json:"cap"` | ||
| Option T `bson:"option" json:"option"` | ||
| } | ||
|
|
||
| // Valid ArrayOption | ||
| func (a *ArrayOption[T]) Valid() error { | ||
| if a.Len < 0 || a.Len > a.Cap { | ||
| return fmt.Errorf("invalid array option,len:%d cap:%d", a.Len, a.Cap) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // ParseArrayOption len cap ,option is basic type 's option | ||
| func ParseArrayOption[T any](option any, handle func(v any) (T, error)) (ArrayOption[T], error) { | ||
| if option == nil { | ||
| return ArrayOption[T]{Len: math.MaxInt, Cap: math.MaxInt}, nil | ||
| } | ||
|
|
||
| var result ArrayOption[T] | ||
|
|
||
| optMap := map[string]interface{}{ | ||
| "len": math.MaxInt, | ||
| "cap": math.MaxInt, | ||
| } | ||
| switch value := option.(type) { | ||
| case ArrayOption[T]: | ||
| return value, nil | ||
| case bson.M: | ||
| optMap = value | ||
| case map[string]interface{}: | ||
| optMap = value | ||
| default: | ||
| marshal, err := json.Marshal(option) | ||
| if err != nil { | ||
| return result, fmt.Errorf("invalid array option,type:%v,value:%v,err:%w", | ||
| option, option, err) | ||
| } | ||
|
|
||
| lenItem := gjson.GetBytes(marshal, "len") | ||
| capItem := gjson.GetBytes(marshal, "cap") | ||
| if !lenItem.Exists() || !capItem.Exists() { | ||
| return result, fmt.Errorf("invalid array option,type:%v,value:%v,err: not exist len or cap", option, option) | ||
| } | ||
| optMap["len"] = lenItem.Int() | ||
| optMap["cap"] = capItem.Int() | ||
| optMap["option"] = gjson.GetBytes(marshal, "option").Value() | ||
| } | ||
|
|
||
| lenn, lenOk := optMap["len"] | ||
| capp, capOk := optMap["cap"] | ||
| if !lenOk || !capOk { | ||
| return result, fmt.Errorf("invalid array option,type:%v,value:%v,err: not exist len or cap", option, option) | ||
| } | ||
|
|
||
| lenOpt, err := util.GetIntByInterface(lenn) | ||
| if err != nil { | ||
| return result, err | ||
| } | ||
| result.Len = lenOpt | ||
| capOpt, err := util.GetIntByInterface(capp) | ||
| if err != nil { | ||
| return result, err | ||
| } | ||
| result.Cap = capOpt | ||
|
|
||
| var defaultOption T | ||
| result.Option = defaultOption | ||
| if handle != nil { | ||
| t, err := handle(optMap["option"]) | ||
| if err != nil { | ||
| return ArrayOption[T]{}, err | ||
| } | ||
| result.Option = t | ||
| } | ||
| return result, result.Valid() | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| /* | ||
| * Tencent is pleased to support the open source community by making 蓝鲸 available. | ||
| * Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved. | ||
| * Licensed under the MIT License (the "License"); you may not use this file except | ||
| * in compliance with the License. You may obtain a copy of the License at | ||
| * http://opensource.org/licenses/MIT | ||
| * Unless required by applicable law or agreed to in writing, software distributed under | ||
| * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, | ||
| * either express or implied. See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package metadata | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
|
|
||
| "configcenter/src/common" | ||
| "configcenter/src/common/blog" | ||
| "configcenter/src/common/mapstr" | ||
| "configcenter/src/common/util" | ||
| "configcenter/src/common/valid/attribute/manager/register" | ||
| ) | ||
|
|
||
| func init() { | ||
| // Register the arrayBool attribute type | ||
| register.Register(arrayBool{}) | ||
| } | ||
|
|
||
| type arrayBool struct { | ||
| } | ||
|
|
||
| // Name returns the name of the arrayBool attribute. | ||
| func (a arrayBool) Name() string { | ||
| return "array_bool" | ||
| } | ||
|
|
||
| // DisplayName returns the display name for user. | ||
| func (a arrayBool) DisplayName() string { | ||
| return "布尔数组" | ||
| } | ||
|
|
||
| // RealType returns the db type of the arrayBool attribute. | ||
| // Flattened array uses LongChar as storage type | ||
| func (a arrayBool) RealType() string { | ||
| return common.FieldTypeLongChar | ||
| } | ||
|
|
||
| // Info returns the tips for user. | ||
| func (a arrayBool) Info() string { | ||
| return "布尔值的扁平化数组字段,存储多个true/false值" | ||
| } | ||
|
|
||
| // Validate validates the arrayBool attribute value | ||
| func (a arrayBool) Validate(ctx context.Context, objID string, propertyType string, required bool, | ||
| option, value interface{}) error { | ||
|
|
||
| rid := util.ExtractRequestIDFromContext(ctx) | ||
|
|
||
| if value == nil { | ||
| if required { | ||
| blog.Errorf("array_bool attribute %s.%s value is required but got nil, rid: %s", | ||
| objID, propertyType, rid) | ||
| return fmt.Errorf("array_bool attribute %s.%s value is required but got nil", | ||
| objID, propertyType) | ||
| } | ||
| return nil | ||
| } | ||
| opts, err := ParseArrayOption[any](option, nil) | ||
| if err != nil { | ||
| blog.Errorf("array_bool parse option failed: %v, rid: %s", err, rid) | ||
| return fmt.Errorf("array_bool invalid option: %v", err) | ||
| } | ||
|
|
||
| // Validate that value is a slice of any | ||
| boolArray, ok := util.ConvertAnyToSlice(value) | ||
| if !ok { | ||
| blog.Errorf("array_bool attribute %s.%s value must be []interface{}, got %T, rid: %s", | ||
| objID, propertyType, value, rid) | ||
| return fmt.Errorf("array_bool attribute %s.%s value must be []interface{}, got %T", | ||
| objID, propertyType, value) | ||
| } | ||
| if opts.Cap < len(boolArray) { | ||
| return fmt.Errorf("array_bool invalid cap %d, rid: %s", opts.Cap, rid) | ||
| } | ||
| // Validate each item in the array is a boolean | ||
| for i, item := range boolArray { | ||
| if _, ok := item.(bool); !ok { | ||
| blog.Errorf("array_bool attribute %s.%s array item [%d] type %T is not bool, rid: %s", | ||
| objID, propertyType, i, item, rid) | ||
| return fmt.Errorf("array_bool attribute %s.%s array item [%v] type %T is not bool", | ||
| objID, propertyType, item, item) | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // FillLostValue fills the lost value with default value | ||
| func (a arrayBool) FillLostValue(ctx context.Context, valData mapstr.MapStr, propertyId string, | ||
| defaultValue, option interface{}) error { | ||
|
|
||
| rid := util.ExtractRequestIDFromContext(ctx) | ||
|
|
||
| valData[propertyId] = nil | ||
| if defaultValue == nil { | ||
| return nil | ||
| } | ||
|
|
||
| // Validate default value | ||
| defaultArray, ok := util.ConvertAnyToSlice(defaultValue) | ||
| if !ok { | ||
| blog.Errorf("array_bool default value must be []interface{}, got %T, rid: %s", defaultValue, rid) | ||
| return fmt.Errorf("array_bool default value must be []interface{}, got %T", defaultValue) | ||
| } | ||
|
|
||
| // Validate each item in default array | ||
| for i, item := range defaultArray { | ||
| if _, ok := item.(bool); !ok { | ||
| blog.Errorf("array_bool default value array item [%d] type %T is not bool, rid: %s", i, item, rid) | ||
| return fmt.Errorf("array_bool default value array item [%d] type %T is not bool", i, item) | ||
| } | ||
| } | ||
|
|
||
| valData[propertyId] = defaultArray | ||
| return nil | ||
| } | ||
|
|
||
| // ValidateOption validates the option field | ||
| func (a arrayBool) ValidateOption(ctx context.Context, option interface{}, defaultVal interface{}) error { | ||
|
|
||
| rid := util.ExtractRequestIDFromContext(ctx) | ||
|
|
||
| _, err := ParseArrayOption[any](option, nil) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if defaultVal == nil { | ||
| return nil | ||
| } | ||
|
|
||
| // Validate default value | ||
| defaultArray, ok := util.ConvertAnyToSlice(defaultVal) | ||
| if !ok { | ||
| blog.Errorf("array_bool default value must be []interface{}, got %T, rid: %s", defaultVal, rid) | ||
| return fmt.Errorf("array_bool default value must be []interface{}, got %T", defaultVal) | ||
| } | ||
|
|
||
| // Validate each item in default array | ||
| for i, item := range defaultArray { | ||
| if _, ok := item.(bool); !ok { | ||
| blog.Errorf("array_bool default value array item [%d] type %T is not bool, rid: %s", i, item, rid) | ||
| return fmt.Errorf("array_bool default value array item [%d] type %T is not bool", i, item) | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| var _ register.AttributeTypeI = &arrayBool{} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.