Skip to content

Commit 64ed530

Browse files
committed
修复对[]byte类型的解析,包括实现encoding.TextMarshaler 接口的类型,规范代码
1 parent 0ad2f03 commit 64ed530

19 files changed

+586
-939
lines changed

example/select_omit_any_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ func newAnyway() Anyway {
2121
}
2222

2323
func TestSelectAny(t *testing.T) {
24-
fmt.Println(filter.SelectMarshal("chat", newAnyway()).MustJSON())
24+
fmt.Println(filter.Select("chat", newAnyway()))
2525
//{"age":10,"name":"boyan"}
26-
fmt.Println(filter.SelectMarshal("article", newAnyway()).MustJSON())
26+
fmt.Println(filter.Select("article", newAnyway()))
2727
//{"name":"boyan","sex":10}
2828
}
2929

3030
func TestOmitAny(t *testing.T) {
31-
fmt.Println(filter.OmitMarshal("user", newAnyway()).MustJSON())
31+
fmt.Println(filter.Omit("user", newAnyway()))
3232
//{"age":10}
33-
fmt.Println(filter.OmitMarshal("profile", newAnyway()).MustJSON())
33+
fmt.Println(filter.Omit("profile", newAnyway()))
3434
//{"name":"boyan"}
3535
}

example/slice_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"github.com/liu-cn/json-filter/filter"
6+
67
"testing"
78
)
89

filter/example_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package filter
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
)
7+
8+
func ExampleSelect() {
9+
type (
10+
Tag struct {
11+
Icon string `json:"icon,select(article)"`
12+
Name string `json:"name,select(profile)"`
13+
}
14+
User struct {
15+
Age int `json:"age,select(article|profile)"`
16+
ID int `json:"id,select($any)"` //$any表示任何场景都选中该字段
17+
Name *string `json:"name,omitempty,select(article|profile)"` //为nil忽略
18+
Tags []Tag `json:"tags,select(article|profile)"`
19+
}
20+
)
21+
name := "小北"
22+
user := User{ID: 1, Name: &name, Age: 21, Tags: []Tag{{"icon", "foo"}, {"icon", "bar"}}}
23+
article := Select("article", &user) //传指针或值均可
24+
null := Select("null", user)
25+
user.Name = nil
26+
profile := Select("profile", user)
27+
articleJSON, _ := json.Marshal(article)
28+
fmt.Println(string(articleJSON))
29+
fmt.Println(profile) //可以直接打印,打印会直接输出过滤后的json
30+
fmt.Println(null)
31+
32+
//Output:
33+
//{"id":1,"name":"小北","tags":[{"icon":"icon"},{"icon":"icon"}]}
34+
//{"age":21,"id":1,"name":"小北","tags":[{"name":"foo"},{"name":"bar"}]}
35+
//{"id":1}
36+
}
37+
38+
func ExampleOmit() {
39+
40+
type (
41+
Tag struct {
42+
Icon string `json:"icon,omit(article)"`
43+
Name string `json:"name,omit(profile)"`
44+
}
45+
User struct {
46+
Age int `json:"age"`
47+
Password int `json:"password,omit($any)"` //$any表示任何场景都排除该字段
48+
Tags []Tag `json:"tags"`
49+
}
50+
)
51+
user := User{Age: 21, Tags: []Tag{{"icon", "foo"}, {"icon", "bar"}}}
52+
article := Omit("article", &user) //传指针或值均可
53+
profile := Omit("profile", user)
54+
articleJSON, _ := json.Marshal(article)
55+
fmt.Println(string(articleJSON))
56+
fmt.Println(profile) //可以直接打印,打印会直接输出过滤后的json
57+
58+
//Output:
59+
//{"age":21,"tags":[{"name":"foo"},{"name":"bar"}]}
60+
//{"age":21,"tags":[{"icon":"icon"},{"icon":"icon"}]}
61+
}

filter/filter.go

+38-85
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,45 @@ type Filter struct {
66
node *fieldNodeTree
77
}
88

9+
// Select 直接返回过滤后的数据结构,它可以被json.Marshal解析,直接打印会以过滤后的json字符串展示
10+
func Select(selectScene string, el interface{}) interface{} {
11+
return jsonFilter(selectScene, el, true)
12+
}
13+
14+
func jsonFilter(selectScene string, el interface{}, isSelect bool) Filter {
15+
tree := &fieldNodeTree{
16+
Key: "",
17+
ParentNode: nil,
18+
}
19+
tree.parseAny("", selectScene, el, isSelect)
20+
return Filter{
21+
node: tree,
22+
}
23+
}
24+
25+
// Omit 直接返回过滤后的数据结构,它可以被json.Marshal解析,直接打印会以过滤后的json字符串展示
26+
func Omit(omitScene string, el interface{}) interface{} {
27+
return jsonFilter(omitScene, el, false)
28+
}
29+
30+
// EnableCache 决定是否启用缓存,默认开启(强烈建议,除非万一缓存模式下出现bug,可以关闭缓存退回曾经的无缓存过滤模式),开启缓存后会有30%-40%的性能提升,开启缓存并没有副作用,只是会让结构体的字段tag常驻内存减少tag字符串处理操作
31+
func EnableCache(enable bool) {
32+
enableCache = enable
33+
}
34+
35+
// Deprecated
36+
// SelectMarshal 不建议使用,第一个参数填你结构体select标签里的场景,第二个参数是你需要过滤的结构体对象,如果字段的select标签里标注的有该场景那么该字段会被选中。
37+
func SelectMarshal(selectScene string, el interface{}) Filter {
38+
return jsonFilter(selectScene, el, true)
39+
}
40+
41+
// Deprecated
42+
// OmitMarshal 不建议使用,第一个参数填你结构体omit标签里的场景,第二个参数是你需要过滤的结构体对象,如果字段的omit标签里标注的有该场景那么该字段会被过滤掉
43+
func OmitMarshal(omitScene string, el interface{}) Filter {
44+
return jsonFilter(omitScene, el, false)
45+
}
946
func (f Filter) MarshalJSON() ([]byte, error) {
10-
return f.node.Bytes()
47+
return useJSONMarshalFunc(f.node.Marshal())
1148
}
1249

1350
// Deprecated
@@ -41,87 +78,3 @@ func (f Filter) String() string {
4178
}
4279
return json
4380
}
44-
45-
// Deprecated
46-
// SelectMarshal 不建议使用,第一个参数填你结构体select标签里的场景,第二个参数是你需要过滤的结构体对象,如果字段的select标签里标注的有该场景那么该字段会被选中。
47-
func SelectMarshal(selectScene string, el interface{}) Filter {
48-
if enableCache {
49-
return selectWithCache(selectScene, el)
50-
}
51-
return selectMarshal(selectScene, el)
52-
}
53-
func selectMarshal(selectScene string, el interface{}) Filter {
54-
tree := &fieldNodeTree{
55-
Key: "",
56-
ParentNode: nil,
57-
}
58-
tree.ParseSelectValue("", selectScene, el)
59-
return Filter{
60-
node: tree,
61-
}
62-
}
63-
64-
// Select 直接返回过滤后的数据结构,相当于直接SelectMarshal后再调用Interface方法
65-
func Select(selectScene string, el interface{}) interface{} {
66-
if enableCache {
67-
return selectWithCache(selectScene, el)
68-
}
69-
return selectMarshal(selectScene, el)
70-
}
71-
72-
// selectWithCache 直接返回过滤后的数据结构,相当于直接SelectMarshal后再调用Interface方法
73-
func selectWithCache(selectScene string, el interface{}) Filter {
74-
tree := &fieldNodeTree{
75-
Key: "",
76-
ParentNode: nil,
77-
}
78-
tree.ParseSelectValueWithCache("", selectScene, el)
79-
return Filter{
80-
node: tree,
81-
}
82-
}
83-
84-
// Omit 直接返回过滤后的数据结构,相当于直接OmitMarshal后再调用Interface方法
85-
func Omit(omitScene string, el interface{}) interface{} {
86-
if enableCache {
87-
return omitWithCache(omitScene, el)
88-
}
89-
return omitMarshal(omitScene, el)
90-
}
91-
92-
// Deprecated
93-
// OmitMarshal 不建议使用,第一个参数填你结构体omit标签里的场景,第二个参数是你需要过滤的结构体对象,如果字段的omit标签里标注的有该场景那么该字段会被过滤掉
94-
func OmitMarshal(omitScene string, el interface{}) Filter {
95-
if enableCache {
96-
return omitWithCache(omitScene, el)
97-
}
98-
return omitMarshal(omitScene, el)
99-
}
100-
101-
func omitMarshal(omitScene string, el interface{}) Filter {
102-
tree := &fieldNodeTree{
103-
Key: "",
104-
ParentNode: nil,
105-
}
106-
tree.ParseOmitValue("", omitScene, el)
107-
return Filter{
108-
node: tree,
109-
}
110-
}
111-
112-
// omitWithCache 第一个参数填你结构体omit标签里的场景,第二个参数是你需要过滤的结构体对象,如果字段的omit标签里标注的有该场景那么该字段会被过滤掉
113-
func omitWithCache(omitScene string, el interface{}) Filter {
114-
tree := &fieldNodeTree{
115-
Key: "",
116-
ParentNode: nil,
117-
}
118-
tree.ParseOmitValueWithCache("", omitScene, el)
119-
return Filter{
120-
node: tree,
121-
}
122-
}
123-
124-
// EnableCache 决定是否启用缓存,默认开启(强烈建议,除非万一缓存模式下出现bug,可以关闭缓存退回曾经的无缓存过滤模式),开启缓存后会有30%-40%的性能提升,开启缓存并没有副作用,只是会让结构体的字段tag常驻内存减少tag字符串处理操作
125-
func EnableCache(enable bool) {
126-
enableCache = enable
127-
}

filter/json_marshal_func.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package filter
2+
3+
import "encoding/json"
4+
5+
type jsonMarshalFunc = func(v interface{}) ([]byte, error)
6+
7+
// var useJSONMarshal = false
8+
var useJSONMarshalFunc = json.Marshal
9+
10+
// SetJSONMarshal 默认使用官方的json.Marshal 解析过滤后的数据结构,可以自定义json解析方法 比如换成字节的github.com/bytedance/sonic 这个进行json解析,
11+
// filter.SetJSONMarshal(sonic.Marshal)就可以了,但是sonic(速度是官方的2-3倍)这个库好像需要go 1.15以上,可以根据自己的需要选择自己需要的json解析库
12+
// 如果对性能要求没有那么高没必要换,这个方法在任意位置调用一次就可以了
13+
func SetJSONMarshal(fn jsonMarshalFunc) {
14+
if fn != nil {
15+
useJSONMarshalFunc = fn
16+
}
17+
}

filter/node_decode.go

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
)
66

77
type fieldNodeTree struct {
8+
isSelect bool //是否是select 方法
89
Key string //字段名
910
Val interface{} //字段值,基础数据类型,int string,bool 等类型直接存在这里面,如果是struct,切片数组map 类型则字段所有k v会存在ChildNodes里
1011
IsSlice bool //是否是切片,或者数组,

0 commit comments

Comments
 (0)