-
Notifications
You must be signed in to change notification settings - Fork 11.2k
Feats: use the types of gjson,the error expection,the invert and the key missing process of the condition #1605
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,9 +9,11 @@ import ( | |
| ) | ||
|
|
||
| type ConditionOperation struct { | ||
| Path string `json:"path"` // JSON路径 | ||
| Mode string `json:"mode"` // full, prefix, suffix, contains | ||
| Value string `json:"value"` // 匹配的值 | ||
| Path string `json:"path"` // JSON路径 | ||
| Mode string `json:"mode"` // full, prefix, suffix, contains, gt, gte, lt, lte | ||
| Value interface{} `json:"value"` // 匹配的值 | ||
| Invert bool `json:"invert"` // 反选功能,true表示取反结果 | ||
| PassMissingKey bool `json:"pass_missing_key"` // 未获取到json key时的行为 | ||
| } | ||
|
|
||
| type ParamOperation struct { | ||
|
|
@@ -34,11 +36,7 @@ func ApplyParamOverride(jsonData []byte, paramOverride map[string]interface{}) ( | |
| if operations, ok := tryParseOperations(paramOverride); ok { | ||
| // 使用新方法 | ||
| result, err := applyOperations(string(jsonData), operations) | ||
| if err != nil { | ||
| // 新方法失败,回退到旧方法 | ||
| return applyOperationsLegacy(jsonData, paramOverride) | ||
| } | ||
| return []byte(result), nil | ||
| return []byte(result), err | ||
| } | ||
|
|
||
| // 直接使用旧方法 | ||
|
|
@@ -95,9 +93,15 @@ func tryParseOperations(paramOverride map[string]interface{}) ([]ParamOperation, | |
| if mode, ok := condMap["mode"].(string); ok { | ||
| condition.Mode = mode | ||
| } | ||
| if value, ok := condMap["value"].(string); ok { | ||
| if value, ok := condMap["value"]; ok { | ||
| condition.Value = value | ||
| } | ||
| if invert, ok := condMap["invert"].(bool); ok { | ||
| condition.Invert = invert | ||
| } | ||
| if passMissingKey, ok := condMap["pass_missing_key"].(bool); ok { | ||
| condition.PassMissingKey = passMissingKey | ||
| } | ||
| operation.Conditions = append(operation.Conditions, condition) | ||
| } | ||
| } | ||
|
|
@@ -116,52 +120,131 @@ func tryParseOperations(paramOverride map[string]interface{}) ([]ParamOperation, | |
| return nil, false | ||
| } | ||
|
|
||
| func checkConditions(jsonStr string, conditions []ConditionOperation, logic string) bool { | ||
| func checkConditions(jsonStr string, conditions []ConditionOperation, logic string) (bool, error) { | ||
| if len(conditions) == 0 { | ||
| return true // 没有条件,直接通过 | ||
| return true, nil // 没有条件,直接通过 | ||
| } | ||
| results := make([]bool, len(conditions)) | ||
|
|
||
| for i, condition := range conditions { | ||
| results[i] = checkSingleCondition(jsonStr, condition) | ||
| result, err := checkSingleCondition(jsonStr, condition) | ||
| if err != nil { | ||
| return false, err | ||
| } | ||
| results[i] = result | ||
| } | ||
|
|
||
| if strings.ToUpper(logic) == "AND" { | ||
| for _, result := range results { | ||
| if !result { | ||
| return false | ||
| return false, nil | ||
| } | ||
| } | ||
| return true | ||
| return true, nil | ||
| } else { | ||
| for _, result := range results { | ||
| if result { | ||
| return true | ||
| return true, nil | ||
| } | ||
| } | ||
| return false | ||
| return false, nil | ||
| } | ||
| } | ||
|
|
||
| func checkSingleCondition(jsonStr string, condition ConditionOperation) bool { | ||
| func checkSingleCondition(jsonStr string, condition ConditionOperation) (bool, error) { | ||
| value := gjson.Get(jsonStr, condition.Path) | ||
| if !value.Exists() { | ||
| return false | ||
| if condition.PassMissingKey { | ||
| return true, nil | ||
| } | ||
| return false, nil | ||
| } | ||
|
|
||
| valueStr := value.String() | ||
| targetStr := condition.Value | ||
| // 利用gjson的类型解析 | ||
| targetBytes, err := json.Marshal(condition.Value) | ||
| if err != nil { | ||
| return false, fmt.Errorf("failed to marshal condition value: %v", err) | ||
| } | ||
| targetValue := gjson.ParseBytes(targetBytes) | ||
|
|
||
| result, err := compareGjsonValues(value, targetValue, strings.ToLower(condition.Mode)) | ||
| if err != nil { | ||
| return false, fmt.Errorf("comparison failed for path %s: %v", condition.Path, err) | ||
| } | ||
|
|
||
| if condition.Invert { | ||
| result = !result | ||
| } | ||
| return result, nil | ||
| } | ||
|
|
||
| switch strings.ToLower(condition.Mode) { | ||
| // compareGjsonValues 直接比较两个gjson.Result,支持所有比较模式 | ||
| func compareGjsonValues(jsonValue, targetValue gjson.Result, mode string) (bool, error) { | ||
| switch mode { | ||
| case "full": | ||
| return valueStr == targetStr | ||
| return compareEqual(jsonValue, targetValue) | ||
| case "prefix": | ||
| return strings.HasPrefix(valueStr, targetStr) | ||
| return strings.HasPrefix(jsonValue.String(), targetValue.String()), nil | ||
| case "suffix": | ||
| return strings.HasSuffix(valueStr, targetStr) | ||
| return strings.HasSuffix(jsonValue.String(), targetValue.String()), nil | ||
| case "contains": | ||
| return strings.Contains(valueStr, targetStr) | ||
| return strings.Contains(jsonValue.String(), targetValue.String()), nil | ||
| case "gt": | ||
| return compareNumeric(jsonValue, targetValue, "gt") | ||
| case "gte": | ||
| return compareNumeric(jsonValue, targetValue, "gte") | ||
| case "lt": | ||
| return compareNumeric(jsonValue, targetValue, "lt") | ||
| case "lte": | ||
| return compareNumeric(jsonValue, targetValue, "lte") | ||
| default: | ||
| return valueStr == targetStr // 默认精准匹配 | ||
| return false, fmt.Errorf("unsupported comparison mode: %s", mode) | ||
| } | ||
| } | ||
|
|
||
| func compareEqual(jsonValue, targetValue gjson.Result) (bool, error) { | ||
| // 对布尔值特殊处理 | ||
| if (jsonValue.Type == gjson.True || jsonValue.Type == gjson.False) && | ||
| (targetValue.Type == gjson.True || targetValue.Type == gjson.False) { | ||
| return jsonValue.Bool() == targetValue.Bool(), nil | ||
| } | ||
|
|
||
| // 如果类型不同,报错 | ||
| if jsonValue.Type != targetValue.Type { | ||
| return false, fmt.Errorf("compare for different types, got %v and %v", jsonValue.Type, targetValue.Type) | ||
| } | ||
|
|
||
| switch jsonValue.Type { | ||
| case gjson.True, gjson.False: | ||
| return jsonValue.Bool() == targetValue.Bool(), nil | ||
| case gjson.Number: | ||
| return jsonValue.Num == targetValue.Num, nil | ||
| case gjson.String: | ||
| return jsonValue.String() == targetValue.String(), nil | ||
| default: | ||
| return jsonValue.String() == targetValue.String(), nil | ||
| } | ||
| } | ||
|
Comment on lines
+204
to
+226
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Array/object equality via string comparison is order-dependent; use deep structural equality. Using String() for JSON types makes equality sensitive to key order and whitespace. This can cause false negatives for semantically equal objects. Apply this diff: func compareEqual(jsonValue, targetValue gjson.Result) (bool, error) {
@@
// 如果类型不同,报错
if jsonValue.Type != targetValue.Type {
return false, fmt.Errorf("compare for different types, got %v and %v", jsonValue.Type, targetValue.Type)
}
switch jsonValue.Type {
case gjson.True, gjson.False:
return jsonValue.Bool() == targetValue.Bool(), nil
case gjson.Number:
return jsonValue.Num == targetValue.Num, nil
case gjson.String:
return jsonValue.String() == targetValue.String(), nil
+ case gjson.JSON:
+ // 对数组/对象进行结构化比较(与键顺序无关)
+ var left, right interface{}
+ if err := json.Unmarshal([]byte(jsonValue.Raw), &left); err != nil {
+ return false, err
+ }
+ if err := json.Unmarshal([]byte(targetValue.Raw), &right); err != nil {
+ return false, err
+ }
+ return reflect.DeepEqual(left, right), nil
default:
return jsonValue.String() == targetValue.String(), nil
}
}And add the missing import: import "reflect"🤖 Prompt for AI Agents |
||
|
|
||
| func compareNumeric(jsonValue, targetValue gjson.Result, operator string) (bool, error) { | ||
| // 只有数字类型才支持数值比较 | ||
| if jsonValue.Type != gjson.Number || targetValue.Type != gjson.Number { | ||
| return false, fmt.Errorf("numeric comparison requires both values to be numbers, got %v and %v", jsonValue.Type, targetValue.Type) | ||
| } | ||
|
|
||
| jsonNum := jsonValue.Num | ||
| targetNum := targetValue.Num | ||
|
|
||
| switch operator { | ||
| case "gt": | ||
| return jsonNum > targetNum, nil | ||
| case "gte": | ||
| return jsonNum >= targetNum, nil | ||
| case "lt": | ||
| return jsonNum < targetNum, nil | ||
| case "lte": | ||
| return jsonNum <= targetNum, nil | ||
| default: | ||
| return false, fmt.Errorf("unsupported numeric operator: %s", operator) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -184,11 +267,14 @@ func applyOperations(jsonStr string, operations []ParamOperation) (string, error | |
| result := jsonStr | ||
| for _, op := range operations { | ||
| // 检查条件是否满足 | ||
| if !checkConditions(result, op.Conditions, op.Logic) { | ||
| ok, err := checkConditions(result, op.Conditions, op.Logic) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| if !ok { | ||
| continue // 条件不满足,跳过当前操作 | ||
| } | ||
|
|
||
| var err error | ||
| switch op.Mode { | ||
| case "delete": | ||
| result, err = sjson.Delete(result, op.Path) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invert is not applied when the key is missing.
If the key is missing and PassMissingKey is true, the function returns early and skips Invert, which makes invert semantics inconsistent across branches.
Apply this diff to unify result computation and always apply invert:
func checkSingleCondition(jsonStr string, condition ConditionOperation) (bool, error) { - value := gjson.Get(jsonStr, condition.Path) - if !value.Exists() { - if condition.PassMissingKey { - return true, nil - } - return false, nil - } - - // 利用gjson的类型解析 - targetBytes, err := json.Marshal(condition.Value) - if err != nil { - return false, fmt.Errorf("failed to marshal condition value: %v", err) - } - targetValue := gjson.ParseBytes(targetBytes) - - result, err := compareGjsonValues(value, targetValue, strings.ToLower(condition.Mode)) - if err != nil { - return false, fmt.Errorf("comparison failed for path %s: %v", condition.Path, err) - } - - if condition.Invert { - result = !result - } - return result, nil + value := gjson.Get(jsonStr, condition.Path) + mode := strings.ToLower(condition.Mode) + if mode == "" { + mode = "full" + } + + var result bool + if !value.Exists() { + result = condition.PassMissingKey + } else { + // 利用gjson的类型解析 + targetBytes, err := json.Marshal(condition.Value) + if err != nil { + return false, fmt.Errorf("failed to marshal condition value: %v", err) + } + targetValue := gjson.ParseBytes(targetBytes) + + r, err := compareGjsonValues(value, targetValue, mode) + if err != nil { + return false, fmt.Errorf("comparison failed for path %s: %v", condition.Path, err) + } + result = r + } + + if condition.Invert { + result = !result + } + return result, nil }🤖 Prompt for AI Agents