feat: query_parser support new one filter parse pattern.
This commit is contained in:
@@ -53,8 +53,13 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
QueryDelimiter = "__" // 分隔符
|
||||
JsonFieldDelimiter = "." // JSONB字段分隔符
|
||||
JSONFilterFieldOperatorDelimiter = "__" // JSON过滤器 - 字段名和操作符的分隔符
|
||||
|
||||
QueryFilterFieldOperatorDelimiter = ":" // 自定义查询字符串过滤器 - 字段名和操作符的分隔符
|
||||
QueryFilterQueriesDelimiter = "," // 自定义查询字符串过滤器 - 多个键值对的分隔符
|
||||
QueryFilterValuesDelimiter = "|" // 自定义查询字符串过滤器 - 多个值的分隔符
|
||||
|
||||
JsonFieldDelimiter = "." // JSON字段分隔符
|
||||
)
|
||||
|
||||
type FilterHandler func(field, operator, value string)
|
||||
@@ -89,6 +94,40 @@ func ParseFilterJSONString(query string, handler FilterHandler) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// ParseFilterQueryString 解析过滤条件的查询字符串,调用处理函数
|
||||
func ParseFilterQueryString(query string, handler FilterHandler) error {
|
||||
if query == "" {
|
||||
return nil // 如果查询字符串为空,直接返回
|
||||
}
|
||||
|
||||
// 按逗号分割查询字符串,得到多个键值对
|
||||
pairs := SplitQueryQueries(query)
|
||||
for _, pair := range pairs {
|
||||
// 按冒号分割键值对,提取字段名和值
|
||||
parts := SplitQueryFieldAndOperator(pair)
|
||||
if len(parts) != 2 {
|
||||
continue // 跳过无效的键值对
|
||||
}
|
||||
|
||||
// 解码字段名
|
||||
key, err := DecodeSpecialCharacters(strings.TrimSpace(parts[0]))
|
||||
if err != nil {
|
||||
continue // 跳过解码失败的键值对
|
||||
}
|
||||
|
||||
// 解码字段值
|
||||
value, err := DecodeSpecialCharacters(strings.TrimSpace(parts[1]))
|
||||
if err != nil {
|
||||
continue // 跳过解码失败的键值对
|
||||
}
|
||||
|
||||
// 调用 ParseFilterField 解析字段和操作符
|
||||
ParseFilterField(key, value, handler)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseFilterField 解析过滤条件字符串,调用处理函数
|
||||
func ParseFilterField(key, value string, handler FilterHandler) {
|
||||
if key == "" || value == "" {
|
||||
@@ -96,7 +135,7 @@ func ParseFilterField(key, value string, handler FilterHandler) {
|
||||
}
|
||||
|
||||
// 处理字段和操作符
|
||||
parts := SplitFieldAndOperator(key)
|
||||
parts := SplitJsonFieldAndOperator(key)
|
||||
if len(parts) < 1 {
|
||||
return // 无效的字段格式
|
||||
}
|
||||
@@ -115,9 +154,24 @@ func ParseFilterField(key, value string, handler FilterHandler) {
|
||||
handler(field, op, value)
|
||||
}
|
||||
|
||||
// SplitFieldAndOperator 将字段字符串按分隔符分割成字段名和操作符
|
||||
func SplitFieldAndOperator(field string) []string {
|
||||
return strings.Split(field, QueryDelimiter)
|
||||
// SplitJsonFieldAndOperator JSON过滤器 - 分割“字段名”和“操作符”
|
||||
func SplitJsonFieldAndOperator(field string) []string {
|
||||
return strings.Split(field, JSONFilterFieldOperatorDelimiter)
|
||||
}
|
||||
|
||||
// SplitQueryFieldAndOperator 自定义查询字符串过滤器 - 分割“字段名”和“操作符”
|
||||
func SplitQueryFieldAndOperator(field string) []string {
|
||||
return strings.Split(field, QueryFilterFieldOperatorDelimiter)
|
||||
}
|
||||
|
||||
// SplitQueryQueries 自定义查询字符串过滤器 - 分割多个键值对
|
||||
func SplitQueryQueries(field string) []string {
|
||||
return strings.Split(field, QueryFilterQueriesDelimiter)
|
||||
}
|
||||
|
||||
// SplitQueryValues 自定义查询字符串过滤器 - 分割多个值
|
||||
func SplitQueryValues(field string) []string {
|
||||
return strings.Split(field, QueryFilterValuesDelimiter)
|
||||
}
|
||||
|
||||
// SplitJSONField 将JSONB字段字符串按分隔符分割成多个字段
|
||||
|
||||
@@ -81,6 +81,149 @@ func TestParseFilterJSONString(t *testing.T) {
|
||||
assert.Equal(t, 0, len(results))
|
||||
}
|
||||
|
||||
func TestParseFilterQueryString(t *testing.T) {
|
||||
var results []struct {
|
||||
Field string
|
||||
Operator string
|
||||
Value string
|
||||
}
|
||||
|
||||
handler := func(field, operator, value string) {
|
||||
results = append(results, struct {
|
||||
Field string
|
||||
Operator string
|
||||
Value string
|
||||
}{Field: field, Operator: operator, Value: value})
|
||||
}
|
||||
|
||||
// 测试解析单个过滤条件
|
||||
results = nil
|
||||
err := ParseFilterQueryString("name__exact:John", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(results))
|
||||
assert.Equal(t, "name", results[0].Field)
|
||||
assert.Equal(t, "exact", results[0].Operator)
|
||||
assert.Equal(t, "John", results[0].Value)
|
||||
|
||||
// 测试解析多个过滤条件
|
||||
results = nil
|
||||
err = ParseFilterQueryString("age__gte:30,status__exact:active", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(results))
|
||||
assert.Equal(t, "age", results[0].Field)
|
||||
assert.Equal(t, "gte", results[0].Operator)
|
||||
assert.Equal(t, "30", results[0].Value)
|
||||
assert.Equal(t, "status", results[1].Field)
|
||||
assert.Equal(t, "exact", results[1].Operator)
|
||||
assert.Equal(t, "active", results[1].Value)
|
||||
|
||||
// 测试空字符串
|
||||
results = nil
|
||||
err = ParseFilterQueryString("", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(results))
|
||||
|
||||
// 测试无效的查询字符串
|
||||
results = nil
|
||||
err = ParseFilterQueryString("invalid_query", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(results))
|
||||
|
||||
// 测试包含特殊字符的字段和值
|
||||
results = nil
|
||||
err = ParseFilterQueryString("na!me__exact:Jo@hn", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(results))
|
||||
assert.Equal(t, "na_me", results[0].Field)
|
||||
assert.Equal(t, "exact", results[0].Operator)
|
||||
assert.Equal(t, "Jo@hn", results[0].Value)
|
||||
|
||||
// 测试包含特殊字符的多个过滤条件
|
||||
results = nil
|
||||
err = ParseFilterQueryString("ag#e__gte:30,sta$tus__exact:ac^tive", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(results))
|
||||
assert.Equal(t, "ag_e", results[0].Field)
|
||||
assert.Equal(t, "gte", results[0].Operator)
|
||||
assert.Equal(t, "30", results[0].Value)
|
||||
assert.Equal(t, "sta_tus", results[1].Field)
|
||||
assert.Equal(t, "exact", results[1].Operator)
|
||||
assert.Equal(t, "ac^tive", results[1].Value)
|
||||
|
||||
// 测试 Field 中包含分隔符
|
||||
results = nil
|
||||
err = ParseFilterQueryString("na:me__exact:John", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(results))
|
||||
|
||||
// 测试 Operator 中包含分隔符
|
||||
results = nil
|
||||
err = ParseFilterQueryString("name__ex:act:John", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(results))
|
||||
|
||||
// 测试 Value 中包含分隔符
|
||||
results = nil
|
||||
err = ParseFilterQueryString("name__exact:Jo|hn", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(results))
|
||||
assert.Equal(t, "name", results[0].Field)
|
||||
assert.Equal(t, "exact", results[0].Operator)
|
||||
assert.Equal(t, "Jo|hn", results[0].Value)
|
||||
|
||||
// 测试多个过滤条件中包含分隔符
|
||||
results = nil
|
||||
err = ParseFilterQueryString("ag:e__gte:30,sta|tus__exact:ac|tive", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(results))
|
||||
|
||||
// 测试 Field 中包含编码后的分隔符
|
||||
results = nil
|
||||
encodedField := EncodeSpecialCharacters("na:me")
|
||||
err = ParseFilterQueryString(encodedField+"__exact:John", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(results))
|
||||
assert.Equal(t, "na_me", results[0].Field) // 注意:这里的字段名会被转换为 snake_case
|
||||
assert.Equal(t, "exact", results[0].Operator)
|
||||
assert.Equal(t, "John", results[0].Value)
|
||||
|
||||
// 测试 Operator 中包含编码后的分隔符
|
||||
results = nil
|
||||
encodedOperator := EncodeSpecialCharacters("ex:act")
|
||||
err = ParseFilterQueryString("name__"+encodedOperator+":John", handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(results))
|
||||
assert.Equal(t, "name", results[0].Field)
|
||||
assert.Equal(t, "ex:act", results[0].Operator)
|
||||
assert.Equal(t, "John", results[0].Value)
|
||||
|
||||
// 测试 Value 中包含编码后的分隔符
|
||||
results = nil
|
||||
encodedValue := EncodeSpecialCharacters("Jo|hn")
|
||||
err = ParseFilterQueryString("name__exact:"+encodedValue, handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(results))
|
||||
assert.Equal(t, "name", results[0].Field)
|
||||
assert.Equal(t, "exact", results[0].Operator)
|
||||
assert.Equal(t, "Jo|hn", results[0].Value)
|
||||
|
||||
// 测试多个过滤条件中包含编码后的分隔符
|
||||
results = nil
|
||||
encodedField1 := EncodeSpecialCharacters("ag:e")
|
||||
encodedValue1 := EncodeSpecialCharacters("30")
|
||||
encodedField2 := EncodeSpecialCharacters("sta|tus")
|
||||
encodedValue2 := EncodeSpecialCharacters("ac|tive")
|
||||
err = ParseFilterQueryString(encodedField1+"__gte:"+encodedValue1+","+encodedField2+"__exact:"+encodedValue2, handler)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(results))
|
||||
assert.Equal(t, "ag_e", results[0].Field) // 注意:这里的字段名会被转换为 snake_case
|
||||
assert.Equal(t, "gte", results[0].Operator)
|
||||
assert.Equal(t, "30", results[0].Value)
|
||||
assert.Equal(t, "sta_tus", results[1].Field) // 注意:这里的字段名会被转换为 snake_case
|
||||
assert.Equal(t, "exact", results[1].Operator)
|
||||
assert.Equal(t, "ac|tive", results[1].Value)
|
||||
}
|
||||
|
||||
func TestParseFilterField(t *testing.T) {
|
||||
var results []struct {
|
||||
Field string
|
||||
@@ -128,25 +271,25 @@ func TestParseFilterField(t *testing.T) {
|
||||
assert.Equal(t, 0, len(results))
|
||||
}
|
||||
|
||||
func TestSplitFieldAndOperator(t *testing.T) {
|
||||
func TestSplitJsonFieldAndOperator(t *testing.T) {
|
||||
// 测试正常分割
|
||||
result := SplitFieldAndOperator("name__exact")
|
||||
result := SplitJsonFieldAndOperator("name__exact")
|
||||
assert.Equal(t, 2, len(result))
|
||||
assert.Equal(t, "name", result[0])
|
||||
assert.Equal(t, "exact", result[1])
|
||||
|
||||
// 测试无操作符
|
||||
result = SplitFieldAndOperator("name")
|
||||
result = SplitJsonFieldAndOperator("name")
|
||||
assert.Equal(t, 1, len(result))
|
||||
assert.Equal(t, "name", result[0])
|
||||
|
||||
// 测试空字符串
|
||||
result = SplitFieldAndOperator("")
|
||||
result = SplitJsonFieldAndOperator("")
|
||||
assert.Equal(t, 1, len(result))
|
||||
assert.Equal(t, "", result[0])
|
||||
|
||||
// 测试多个分隔符
|
||||
result = SplitFieldAndOperator("name__exact__extra")
|
||||
result = SplitJsonFieldAndOperator("name__exact__extra")
|
||||
assert.Equal(t, 3, len(result))
|
||||
assert.Equal(t, "name", result[0])
|
||||
assert.Equal(t, "exact", result[1])
|
||||
@@ -179,3 +322,80 @@ func TestSplitJSONField(t *testing.T) {
|
||||
assert.Equal(t, "address", result[2])
|
||||
assert.Equal(t, "city", result[3])
|
||||
}
|
||||
|
||||
func TestSplitQueryFieldAndOperator(t *testing.T) {
|
||||
// 测试正常分割
|
||||
result := SplitQueryFieldAndOperator("name:exact")
|
||||
assert.Equal(t, 2, len(result))
|
||||
assert.Equal(t, "name", result[0])
|
||||
assert.Equal(t, "exact", result[1])
|
||||
|
||||
// 测试无操作符
|
||||
result = SplitQueryFieldAndOperator("name")
|
||||
assert.Equal(t, 1, len(result))
|
||||
assert.Equal(t, "name", result[0])
|
||||
|
||||
// 测试空字符串
|
||||
result = SplitQueryFieldAndOperator("")
|
||||
assert.Equal(t, 1, len(result))
|
||||
assert.Equal(t, "", result[0])
|
||||
|
||||
// 测试多个分隔符
|
||||
result = SplitQueryFieldAndOperator("name:exact:extra")
|
||||
assert.Equal(t, 3, len(result))
|
||||
assert.Equal(t, "name", result[0])
|
||||
assert.Equal(t, "exact", result[1])
|
||||
assert.Equal(t, "extra", result[2])
|
||||
}
|
||||
|
||||
func TestSplitQueryQueries(t *testing.T) {
|
||||
// 测试正常分割多个键值对
|
||||
result := SplitQueryQueries("name:John,age:30,status:active")
|
||||
assert.Equal(t, 3, len(result))
|
||||
assert.Equal(t, "name:John", result[0])
|
||||
assert.Equal(t, "age:30", result[1])
|
||||
assert.Equal(t, "status:active", result[2])
|
||||
|
||||
// 测试单个键值对
|
||||
result = SplitQueryQueries("name:John")
|
||||
assert.Equal(t, 1, len(result))
|
||||
assert.Equal(t, "name:John", result[0])
|
||||
|
||||
// 测试空字符串
|
||||
result = SplitQueryQueries("")
|
||||
assert.Equal(t, 1, len(result))
|
||||
assert.Equal(t, "", result[0])
|
||||
|
||||
// 测试多个分隔符
|
||||
result = SplitQueryQueries("name:John,,age:30")
|
||||
assert.Equal(t, 3, len(result))
|
||||
assert.Equal(t, "name:John", result[0])
|
||||
assert.Equal(t, "", result[1])
|
||||
assert.Equal(t, "age:30", result[2])
|
||||
}
|
||||
|
||||
func TestSplitQueryValues(t *testing.T) {
|
||||
// 测试正常分割多个值
|
||||
result := SplitQueryValues("value1|value2|value3")
|
||||
assert.Equal(t, 3, len(result))
|
||||
assert.Equal(t, "value1", result[0])
|
||||
assert.Equal(t, "value2", result[1])
|
||||
assert.Equal(t, "value3", result[2])
|
||||
|
||||
// 测试单个值
|
||||
result = SplitQueryValues("value1")
|
||||
assert.Equal(t, 1, len(result))
|
||||
assert.Equal(t, "value1", result[0])
|
||||
|
||||
// 测试空字符串
|
||||
result = SplitQueryValues("")
|
||||
assert.Equal(t, 1, len(result))
|
||||
assert.Equal(t, "", result[0])
|
||||
|
||||
// 测试多个分隔符
|
||||
result = SplitQueryValues("value1||value2")
|
||||
assert.Equal(t, 3, len(result))
|
||||
assert.Equal(t, "value1", result[0])
|
||||
assert.Equal(t, "", result[1])
|
||||
assert.Equal(t, "value2", result[2])
|
||||
}
|
||||
|
||||
13
query_parser/utils.go
Normal file
13
query_parser/utils.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package query_parser
|
||||
|
||||
import "net/url"
|
||||
|
||||
// EncodeSpecialCharacters 对字符串进行编码
|
||||
func EncodeSpecialCharacters(input string) string {
|
||||
return url.QueryEscape(input)
|
||||
}
|
||||
|
||||
// DecodeSpecialCharacters 对字符串进行解码
|
||||
func DecodeSpecialCharacters(input string) (string, error) {
|
||||
return url.QueryUnescape(input)
|
||||
}
|
||||
Reference in New Issue
Block a user