-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feats:independent condition judgement file and interface, add more conditions #1756
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
nekohy
wants to merge
5
commits into
QuantumNous:alpha
Choose a base branch
from
nekohy:feats-add-more-conditions
base: alpha
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.
+281
−192
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
6a9763c
feats:independent condition judgement file and interface, add pass,bl…
nekohy 8fa1a88
Merge branch 'alpha' into feats-add-more-conditions
nekohy cbf1968
fix:hide the condition content,the flexable adding condition's way
nekohy 4c40e26
Merge remote-tracking branch 'origin/feats-add-more-conditions' into …
nekohy a15fd7e
Merge branch 'alpha' into feats-add-more-conditions
Calcium-Ion 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
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,213 @@ | ||
package common | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/tidwall/gjson" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// ConditionChecker 条件检查器接口 | ||
type ConditionChecker interface { | ||
CheckConditions(jsonStr string, conditions []ConditionOperation, logic string) (bool, error) | ||
CheckSingleCondition(jsonStr string, condition ConditionOperation) (bool, error) | ||
} | ||
|
||
// DefaultConditionChecker 默认条件检查器实现 | ||
type DefaultConditionChecker struct{} | ||
|
||
// NewConditionChecker 创建新的条件检查器 | ||
func NewConditionChecker() ConditionChecker { | ||
return &DefaultConditionChecker{} | ||
} | ||
|
||
type ConditionOperation struct { | ||
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时的行为 | ||
} | ||
|
||
// CheckConditions 检查多个条件 | ||
func CheckConditions(jsonStr string, conditions []ConditionOperation, logic string) (bool, error) { | ||
checker := NewConditionChecker() | ||
return checker.CheckConditions(jsonStr, conditions, logic) | ||
} | ||
|
||
// CheckSingleCondition 检查单个条件 | ||
func CheckSingleCondition(jsonStr string, condition ConditionOperation) (bool, error) { | ||
checker := NewConditionChecker() | ||
return checker.CheckSingleCondition(jsonStr, condition) | ||
} | ||
|
||
func (c *DefaultConditionChecker) CheckConditions(jsonStr string, conditions []ConditionOperation, logic string) (bool, error) { | ||
return checkConditions(jsonStr, conditions, logic) | ||
} | ||
|
||
func (c *DefaultConditionChecker) CheckSingleCondition(jsonStr string, condition ConditionOperation) (bool, error) { | ||
return checkSingleCondition(jsonStr, condition) | ||
} | ||
|
||
func checkConditions(jsonStr string, conditions []ConditionOperation, logic string) (bool, error) { | ||
if len(conditions) == 0 { | ||
return true, nil // 没有条件,直接通过 | ||
} | ||
results := make([]bool, len(conditions)) | ||
for i, condition := range conditions { | ||
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, nil | ||
} | ||
} | ||
return true, nil | ||
} else { | ||
for _, result := range results { | ||
if result { | ||
return true, nil | ||
} | ||
} | ||
return false, nil | ||
} | ||
} | ||
|
||
func checkSingleCondition(jsonStr string, condition ConditionOperation) (bool, error) { | ||
// 处理负数索引 | ||
path := processNegativeIndex(jsonStr, condition.Path) | ||
value := gjson.Get(jsonStr, 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 | ||
} | ||
|
||
func processNegativeIndex(jsonStr string, path string) string { | ||
re := regexp.MustCompile(`\.(-\d+)`) | ||
matches := re.FindAllStringSubmatch(path, -1) | ||
|
||
if len(matches) == 0 { | ||
return path | ||
} | ||
|
||
result := path | ||
for _, match := range matches { | ||
negIndex := match[1] | ||
index, _ := strconv.Atoi(negIndex) | ||
|
||
arrayPath := strings.Split(path, negIndex)[0] | ||
if strings.HasSuffix(arrayPath, ".") { | ||
arrayPath = arrayPath[:len(arrayPath)-1] | ||
} | ||
|
||
array := gjson.Get(jsonStr, arrayPath) | ||
if array.IsArray() { | ||
length := len(array.Array()) | ||
actualIndex := length + index | ||
if actualIndex >= 0 && actualIndex < length { | ||
result = strings.Replace(result, match[0], "."+strconv.Itoa(actualIndex), 1) | ||
} | ||
} | ||
} | ||
|
||
return result | ||
} | ||
|
||
// compareGjsonValues 直接比较两个gjson.Result,支持所有比较模式 | ||
func compareGjsonValues(jsonValue, targetValue gjson.Result, mode string) (bool, error) { | ||
switch mode { | ||
case "full": | ||
return compareEqual(jsonValue, targetValue) | ||
case "prefix": | ||
return strings.HasPrefix(jsonValue.String(), targetValue.String()), nil | ||
case "suffix": | ||
return strings.HasSuffix(jsonValue.String(), targetValue.String()), nil | ||
case "contains": | ||
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 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 | ||
} | ||
} | ||
|
||
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) | ||
} | ||
} |
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.
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.
Incorrect array path resolution for multiple negative indices (nested arrays).
arrayPath is derived from the original path for every match, so the second/next negative index may compute length from the wrong array. This mis-evaluates paths like a.-1.b.-1.
Apply a left-to-right replacement that recalculates arrayPath against the progressively updated path:
📝 Committable suggestion
🤖 Prompt for AI Agents