Skip to content

Commit cea99bf

Browse files
committed
a463dfbba9906d64fb4b5e18ef91b58ea23d5b31
prepare for release v1.1.3
1 parent ac39eae commit cea99bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+7702
-9137
lines changed

conf/bind.go

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525

2626
"github.com/go-spring/spring-base/code"
2727
"github.com/go-spring/spring-base/util"
28-
"github.com/go-spring/spring-core/expr"
28+
"github.com/go-spring/spring-core/validate"
2929
)
3030

3131
var (
@@ -145,23 +145,11 @@ func BindValue(p *Properties, v reflect.Value, t reflect.Type, param BindParam,
145145
return nil
146146
}
147147

148-
validate := func(input string, val interface{}) error {
149-
if input == "" {
150-
return nil
151-
}
152-
if b, err := expr.Eval(input, val); err != nil {
153-
return err
154-
} else if !b {
155-
return fmt.Errorf("validate failed on %q for value %v", input, val)
156-
}
157-
return nil
158-
}
159-
160148
switch v.Kind() {
161149
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
162150
var u uint64
163151
if u, err = strconv.ParseUint(val, 0, 0); err == nil {
164-
if err = validate(param.Validate, u); err != nil {
152+
if err = validate.Field(u, param.Validate); err != nil {
165153
return err
166154
}
167155
v.SetUint(u)
@@ -171,7 +159,7 @@ func BindValue(p *Properties, v reflect.Value, t reflect.Type, param BindParam,
171159
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
172160
var i int64
173161
if i, err = strconv.ParseInt(val, 0, 0); err == nil {
174-
if err = validate(param.Validate, i); err != nil {
162+
if err = validate.Field(i, param.Validate); err != nil {
175163
return err
176164
}
177165
v.SetInt(i)
@@ -181,7 +169,7 @@ func BindValue(p *Properties, v reflect.Value, t reflect.Type, param BindParam,
181169
case reflect.Float32, reflect.Float64:
182170
var f float64
183171
if f, err = strconv.ParseFloat(val, 64); err == nil {
184-
if err = validate(param.Validate, f); err != nil {
172+
if err = validate.Field(f, param.Validate); err != nil {
185173
return err
186174
}
187175
v.SetFloat(f)
@@ -191,15 +179,15 @@ func BindValue(p *Properties, v reflect.Value, t reflect.Type, param BindParam,
191179
case reflect.Bool:
192180
var b bool
193181
if b, err = strconv.ParseBool(val); err == nil {
194-
if err = validate(param.Validate, b); err != nil {
182+
if err = validate.Field(b, param.Validate); err != nil {
195183
return err
196184
}
197185
v.SetBool(b)
198186
return nil
199187
}
200188
return util.Wrapf(err, code.FileLine(), "bind %s error", param.Path)
201189
case reflect.String:
202-
if err = validate(param.Validate, val); err != nil {
190+
if err = validate.Field(val, param.Validate); err != nil {
203191
return err
204192
}
205193
v.SetString(val)
@@ -357,8 +345,8 @@ func bindStruct(p *Properties, v reflect.Value, t reflect.Type, param BindParam,
357345
}
358346

359347
if tag, ok := ft.Tag.Lookup("value"); ok {
360-
validate, _ := ft.Tag.Lookup("validate")
361-
if err := subParam.BindTag(tag, validate); err != nil {
348+
validateTag, _ := ft.Tag.Lookup(validate.TagName())
349+
if err := subParam.BindTag(tag, validateTag); err != nil {
362350
return util.Wrapf(err, code.FileLine(), "bind %s error", param.Path)
363351
}
364352
if filter != nil {

conf/bind_test.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
)
2727

2828
type DB struct {
29-
UserName string `value:"${username}" validate:"len($)>=4"`
29+
UserName string `value:"${username}" expr:"len($)>=4"`
3030
Password string `value:"${password}"`
3131
Url string `value:"${url}"`
3232
Port string `value:"${port}"`
@@ -216,14 +216,3 @@ func TestProperties_Bind(t *testing.T) {
216216
assert.Equal(t, s.M, map[string]string{})
217217
})
218218
}
219-
220-
func TestProperties_Validate(t *testing.T) {
221-
t.Run("", func(t *testing.T) {
222-
p := conf.New()
223-
v := &struct {
224-
V int `value:"${:=3}" validate:"$<3"`
225-
}{}
226-
err := p.Bind(v)
227-
assert.Error(t, err, "validate failed on \"\\$<3\" for value 3")
228-
})
229-
}

conf/conf.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func RegisterSplitter(name string, fn Splitter) {
9191
// time.Time, time.Duration, or other user-defined value type.
9292
func RegisterConverter(fn util.Converter) {
9393
t := reflect.TypeOf(fn)
94-
if !util.IsValidConverter(t) {
94+
if !util.IsConverter(t) {
9595
panic(errors.New("converter should be func(string)(type,error)"))
9696
}
9797
converters[t.Out(0)] = fn
@@ -110,14 +110,14 @@ func RegisterConverter(fn util.Converter) {
110110
// but it costs more CPU time when getting properties because it reads property node
111111
// by node. So `conf` uses a tree to strictly verify and a flat map to store.
112112
type Properties struct {
113-
storage internal.Storage
113+
storage *internal.Storage
114114
}
115115

116116
// New creates empty *Properties.
117117
func New() *Properties {
118-
p := &Properties{}
119-
p.storage.Init()
120-
return p
118+
return &Properties{
119+
storage: internal.NewStorage(),
120+
}
121121
}
122122

123123
// Map creates *Properties from map.
@@ -195,6 +195,12 @@ func (p *Properties) Bytes(b []byte, ext string) error {
195195
return nil
196196
}
197197

198+
func (p *Properties) Copy() *Properties {
199+
return &Properties{
200+
storage: p.storage.Copy(),
201+
}
202+
}
203+
198204
// Keys returns all sorted keys.
199205
func (p *Properties) Keys() []string {
200206
return p.storage.Keys()
@@ -231,7 +237,7 @@ func (p *Properties) Get(key string, opts ...GetOption) string {
231237
return arg.def
232238
}
233239

234-
func flatten(key string, val interface{}, result map[string]string) error {
240+
func Flatten(key string, val interface{}, result map[string]string) error {
235241
switch v := reflect.ValueOf(val); v.Kind() {
236242
case reflect.Map:
237243
if v.Len() == 0 {
@@ -241,7 +247,7 @@ func flatten(key string, val interface{}, result map[string]string) error {
241247
for _, k := range v.MapKeys() {
242248
mapKey := cast.ToString(k.Interface())
243249
mapValue := v.MapIndex(k).Interface()
244-
err := flatten(key+"."+mapKey, mapValue, result)
250+
err := Flatten(key+"."+mapKey, mapValue, result)
245251
if err != nil {
246252
return err
247253
}
@@ -254,7 +260,7 @@ func flatten(key string, val interface{}, result map[string]string) error {
254260
for i := 0; i < v.Len(); i++ {
255261
subKey := fmt.Sprintf("%s[%d]", key, i)
256262
subValue := v.Index(i).Interface()
257-
err := flatten(subKey, subValue, result)
263+
err := Flatten(subKey, subValue, result)
258264
if err != nil {
259265
return err
260266
}
@@ -272,8 +278,11 @@ func flatten(key string, val interface{}, result map[string]string) error {
272278
// when it doesn't exist in the slice or map even they share a same
273279
// prefix path.
274280
func (p *Properties) Set(key string, val interface{}) error {
281+
if key == "" {
282+
return nil
283+
}
275284
m := make(map[string]string)
276-
err := flatten(key, val, m)
285+
err := Flatten(key, val, m)
277286
if err != nil {
278287
return err
279288
}

conf/conf_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ func TestBindMap(t *testing.T) {
345345
})
346346
assert.Nil(t, err)
347347
err = p.Bind(&r)
348-
assert.Error(t, err, ".*bind.go:.* bind S error; .*bind.go:.* bind S.A error; property \"a\" isn't map")
348+
assert.Error(t, err, ".*bind.go:.* bind S error; .*bind.go:.* bind S.A error; property 'a' is value")
349349
})
350350

351351
t.Run("", func(t *testing.T) {
@@ -410,10 +410,10 @@ func TestProperties_Set(t *testing.T) {
410410
assert.Equal(t, p.Keys(), []string{"m.a"})
411411

412412
err = p.Set("m", 1)
413-
assert.Error(t, err, "property \"m\" is a map but \"m\" wants other type")
413+
assert.Error(t, err, "property 'm' is a map but 'm' wants other type")
414414

415415
err = p.Set("m", []string{"b"})
416-
assert.Error(t, err, "property \"m\" is a map but \"m\\[0]\" wants other type")
416+
assert.Error(t, err, "property 'm' is a map but 'm\\[0]' wants other type")
417417
})
418418

419419
t.Run("map empty", func(t *testing.T) {

conf/internal/path.go

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,105 +18,110 @@ package internal
1818

1919
import (
2020
"fmt"
21+
"strconv"
2122
"strings"
2223
)
2324

2425
type PathType int
2526

2627
const (
27-
PathTypeKey PathType = iota
28-
PathTypeIndex
28+
PathTypeKey PathType = iota // PathTypeKey is map key like a/b in a[0][1].b
29+
PathTypeIndex // PathTypeIndex is array index like 0/1 in a[0][1].b
2930
)
3031

3132
type Path struct {
3233
Type PathType
3334
Elem string
3435
}
3536

36-
// SplitPath splits the key into individual parts.
37+
// JoinPath joins path elements into a single path.
38+
func JoinPath(path []Path) string {
39+
var s strings.Builder
40+
for i, p := range path {
41+
switch p.Type {
42+
case PathTypeKey:
43+
if i > 0 {
44+
s.WriteString(".")
45+
}
46+
s.WriteString(p.Elem)
47+
case PathTypeIndex:
48+
s.WriteString("[")
49+
s.WriteString(p.Elem)
50+
s.WriteString("]")
51+
}
52+
}
53+
return s.String()
54+
}
55+
56+
// SplitPath splits key into individual path elements.
3757
func SplitPath(key string) ([]Path, error) {
3858
if key == "" {
3959
return nil, nil
4060
}
4161
var (
4262
path []Path
63+
lastPos int
4364
lastChar int32
44-
lastIndex int
45-
leftBracket bool
65+
openBracket bool
4666
)
4767
for i, c := range key {
4868
switch c {
4969
case ' ':
5070
return nil, fmt.Errorf("invalid key '%s'", key)
5171
case '.':
52-
if leftBracket {
72+
if openBracket {
5373
return nil, fmt.Errorf("invalid key '%s'", key)
5474
}
5575
if lastChar == ']' {
56-
lastIndex = i + 1
76+
lastPos = i + 1
5777
lastChar = c
5878
continue
5979
}
60-
if lastIndex == i {
80+
if lastPos == i {
6181
return nil, fmt.Errorf("invalid key '%s'", key)
6282
}
63-
path = append(path, Path{PathTypeKey, key[lastIndex:i]})
64-
lastIndex = i + 1
83+
path = append(path, Path{PathTypeKey, key[lastPos:i]})
84+
lastPos = i + 1
6585
lastChar = c
6686
case '[':
67-
if leftBracket {
87+
if openBracket {
6888
return nil, fmt.Errorf("invalid key '%s'", key)
6989
}
7090
if i == 0 || lastChar == ']' {
71-
lastIndex = i + 1
72-
leftBracket = true
91+
lastPos = i + 1
92+
openBracket = true
7393
lastChar = c
7494
continue
7595
}
76-
if lastChar == '.' || lastIndex == i {
96+
if lastChar == '.' || lastPos == i {
7797
return nil, fmt.Errorf("invalid key '%s'", key)
7898
}
79-
path = append(path, Path{PathTypeKey, key[lastIndex:i]})
80-
lastIndex = i + 1
81-
leftBracket = true
99+
path = append(path, Path{PathTypeKey, key[lastPos:i]})
100+
lastPos = i + 1
101+
openBracket = true
82102
lastChar = c
83103
case ']':
84-
if !leftBracket || lastIndex == i {
104+
if !openBracket || lastPos == i {
105+
return nil, fmt.Errorf("invalid key '%s'", key)
106+
}
107+
s := key[lastPos:i]
108+
_, err := strconv.ParseUint(s, 10, 64)
109+
if err != nil {
85110
return nil, fmt.Errorf("invalid key '%s'", key)
86111
}
87-
path = append(path, Path{PathTypeIndex, key[lastIndex:i]})
88-
lastIndex = i + 1
89-
leftBracket = false
112+
path = append(path, Path{PathTypeIndex, s})
113+
lastPos = i + 1
114+
openBracket = false
90115
lastChar = c
91116
default:
92117
lastChar = c
93118
}
94119
}
95-
if leftBracket || lastChar == '.' {
120+
if openBracket || lastChar == '.' {
96121
return nil, fmt.Errorf("invalid key '%s'", key)
97122
}
98123
if lastChar != ']' {
99-
path = append(path, Path{PathTypeKey, key[lastIndex:]})
124+
path = append(path, Path{PathTypeKey, key[lastPos:]})
100125
}
101126
return path, nil
102127
}
103-
104-
func GenPath(path []Path) string {
105-
var s strings.Builder
106-
for i, p := range path {
107-
if p.Type == PathTypeKey {
108-
if i > 0 {
109-
s.WriteString(".")
110-
}
111-
s.WriteString(p.Elem)
112-
continue
113-
}
114-
if p.Type == PathTypeIndex {
115-
s.WriteString("[")
116-
s.WriteString(p.Elem)
117-
s.WriteString("]")
118-
continue
119-
}
120-
}
121-
return s.String()
122-
}

conf/internal/path_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ func TestSplitPath(t *testing.T) {
146146
assert.Equal(t, err, c.Err, fmt.Sprintf("index: %d key: %q", i, c.Key))
147147
assert.Equal(t, p, c.Path, fmt.Sprintf("index:%d key: %q", i, c.Key))
148148
if err == nil {
149-
s := internal.GenPath(p)
149+
s := internal.JoinPath(p)
150150
assert.Equal(t, s, c.Key, fmt.Sprintf("index:%d key: %q", i, c.Key))
151151
}
152152
}

0 commit comments

Comments
 (0)