Skip to content

Develop #4

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

Merged
merged 91 commits into from
Feb 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
3dac4c1
code refactor
lvan100 Jan 12, 2025
209071d
code refactor
lvan100 Jan 12, 2025
6321cec
code refactor
lvan100 Jan 12, 2025
62c2401
code refactor
lvan100 Jan 12, 2025
989d69f
code refactor
lvan100 Jan 13, 2025
794e0ed
code refactor
lvan100 Jan 13, 2025
f07769e
code refactor
lvan100 Jan 13, 2025
5707f09
code refactor
lvan100 Jan 14, 2025
147271e
code refactor
lvan100 Jan 14, 2025
461f247
code refactor
lvan100 Jan 14, 2025
45dff2e
code refactor
lvan100 Jan 14, 2025
0e95cb2
code refactor
lvan100 Jan 15, 2025
76b7e09
code refactor
lvan100 Jan 15, 2025
75591c6
code refactor
lvan100 Jan 15, 2025
9d66fde
code refactor
lvan100 Jan 16, 2025
f9f62a4
code refactor
lvan100 Jan 16, 2025
77d7242
code refactor
lvan100 Jan 16, 2025
c3478d5
code refactor
lvan100 Jan 16, 2025
e5dd978
add ConditionError
lvan100 Jan 17, 2025
d808d51
code refactor
lvan100 Jan 18, 2025
d25d480
code refactor
lvan100 Jan 18, 2025
509bec8
code refactor
lvan100 Jan 18, 2025
ab4a683
code refactor
lvan100 Jan 18, 2025
648bcb3
add errutil
lvan100 Jan 19, 2025
8f78111
code refactor
lvan100 Jan 19, 2025
4645255
code refactor
lvan100 Jan 19, 2025
9b5b897
code refactor
lvan100 Jan 19, 2025
e3855c1
code refactor
lvan100 Jan 19, 2025
348a2c8
code refactor
lvan100 Jan 20, 2025
c04115a
remove primary
lvan100 Jan 20, 2025
147a919
code refactor
lvan100 Jan 20, 2025
2d540b2
code refactor
lvan100 Jan 20, 2025
42b331e
code refactor
lvan100 Jan 20, 2025
5b69132
code refactor
lvan100 Jan 21, 2025
3d3b3e3
code refactor
lvan100 Jan 21, 2025
ce83c15
code refactor
lvan100 Jan 22, 2025
4ded60f
code refactor
lvan100 Jan 22, 2025
a07fd69
code refactor
lvan100 Jan 22, 2025
4bd6c58
code refactor
lvan100 Jan 22, 2025
dc78e8b
code refactor
lvan100 Jan 22, 2025
c8bca1f
code refactor
lvan100 Jan 23, 2025
334c163
code refactor
lvan100 Jan 23, 2025
5fc39b0
code refactor
lvan100 Jan 23, 2025
3edbe83
code refactor
lvan100 Jan 23, 2025
2a77dd2
add goutil
lvan100 Jan 24, 2025
0e274f4
code refactor
lvan100 Jan 24, 2025
34ac092
code refactor
lvan100 Jan 24, 2025
a72aedc
code refactor
lvan100 Jan 24, 2025
851361f
code refactor
lvan100 Jan 24, 2025
21f53e7
code refactor
lvan100 Jan 25, 2025
a42a617
code refactor
lvan100 Jan 25, 2025
0d12296
code refactor
lvan100 Jan 26, 2025
9730e9c
code refactor
lvan100 Jan 26, 2025
3fcaf64
code refactor
lvan100 Jan 26, 2025
e9b64ab
code refactor
lvan100 Feb 2, 2025
3bd366c
code refactor
lvan100 Feb 2, 2025
f4fbac3
code refactor
lvan100 Feb 4, 2025
5bb39f2
code refactor
lvan100 Feb 4, 2025
148f2f0
code refactor
lvan100 Feb 5, 2025
7796709
code refactor
lvan100 Feb 5, 2025
a2cd8a8
code refactor
lvan100 Feb 5, 2025
8ee19b0
code refactor
lvan100 Feb 5, 2025
0dcd92e
code refactor
lvan100 Feb 6, 2025
599e305
code refactor
lvan100 Feb 6, 2025
bf85fab
code refactor
lvan100 Feb 7, 2025
a96a9eb
code refactor
lvan100 Feb 8, 2025
8d2fcc3
code refactor
lvan100 Feb 8, 2025
d22e812
code refactor
lvan100 Feb 8, 2025
b53b975
code refactor
lvan100 Feb 8, 2025
697cbea
code refactor
lvan100 Feb 8, 2025
e2296d7
code refactor
lvan100 Feb 8, 2025
8db4094
code refactor
lvan100 Feb 9, 2025
39a9ab1
code refactor
lvan100 Feb 9, 2025
9b97217
code refactor
lvan100 Feb 9, 2025
1366b7e
code refactor
lvan100 Feb 9, 2025
531ed9c
code refactor
lvan100 Feb 10, 2025
6c8cc0f
code refactor
lvan100 Feb 10, 2025
f3769c6
code refactor
lvan100 Feb 11, 2025
e65cda1
code refactor
lvan100 Feb 11, 2025
ceb64e0
code refactor
lvan100 Feb 11, 2025
7e9a5dd
code refactor
lvan100 Feb 12, 2025
357fef7
code refactor
lvan100 Feb 12, 2025
0ff462c
code refactor
lvan100 Feb 12, 2025
df60924
code refactor
lvan100 Feb 12, 2025
363d4bc
code refactor
lvan100 Feb 12, 2025
6715ffd
code refactor
lvan100 Feb 15, 2025
f91ef89
code refactor
lvan100 Feb 15, 2025
c395c3e
code refactor
lvan100 Feb 15, 2025
986a982
code refactor
lvan100 Feb 15, 2025
04a218e
code refactor
lvan100 Feb 15, 2025
4d57765
code refactor
lvan100 Feb 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 62 additions & 51 deletions conf/bind.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 the original author or authors.
* Copyright 2024 The Go-Spring Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,7 +24,7 @@ import (
"strings"

"github.com/go-spring/spring-core/util"
"github.com/go-spring/spring-core/util/macro"
"github.com/go-spring/spring-core/util/errutil"
)

var (
Expand Down Expand Up @@ -94,22 +94,27 @@ type BindParam struct {
}

func (param *BindParam) BindTag(tag string, validate reflect.StructTag) error {
param.Validate = validate
parsedTag, err := ParseTag(tag)
if err != nil {
return err
}
if parsedTag.Key == "" { // ${:=} 默认值语法
if parsedTag.HasDef {
param.Tag = parsedTag
return nil
}
return fmt.Errorf("xxxx") // todo
}
if parsedTag.Key == "ROOT" {
parsedTag.Key = ""
} else if parsedTag.Key == "" {
parsedTag.Key = "ANONYMOUS"
}
param.Tag = parsedTag
if param.Key == "" {
param.Key = parsedTag.Key
} else if parsedTag.Key != "" {
param.Key = param.Key + "." + parsedTag.Key
}
param.Validate = validate
param.Tag = parsedTag
return nil
}

Expand All @@ -118,11 +123,11 @@ type Filter interface {
}

// BindValue binds properties to a value.
func BindValue(p readOnlyProperties, v reflect.Value, t reflect.Type, param BindParam, filter Filter) (RetErr error) {
func BindValue(p ReadOnlyProperties, v reflect.Value, t reflect.Type, param BindParam, filter Filter) (RetErr error) {

if !util.IsValueType(t) {
if !util.IsPropBindingTarget(t) {
err := errors.New("target should be value type")
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return fmt.Errorf("bind path=%s type=%s error: %w", param.Path, v.Type().String(), err)
}

defer func() {
Expand All @@ -144,29 +149,29 @@ func BindValue(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bind
return bindSlice(p, v, t, param, filter)
case reflect.Array:
err := errors.New("use slice instead of array")
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return fmt.Errorf("bind path=%s type=%s error: %w", param.Path, v.Type().String(), err)
default: // for linter
}

fn := converters[t]
if fn == nil && v.Kind() == reflect.Struct {
if err := bindStruct(p, v, t, param, filter); err != nil {
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return err // no wrap
}
return nil
}

val, err := resolve(p, param)
if err != nil {
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return errutil.WrapError(err, "bind path=%s type=%s error", param.Path, v.Type().String())
}

if fn != nil {
fnValue := reflect.ValueOf(fn)
out := fnValue.Call([]reflect.Value{reflect.ValueOf(val)})
if !out[1].IsNil() {
err = out[1].Interface().(error)
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return errutil.WrapError(err, "bind path=%s type=%s error", param.Path, v.Type().String())
}
v.Set(out[0])
return nil
Expand All @@ -179,45 +184,45 @@ func BindValue(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bind
v.SetUint(u)
return nil
}
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return errutil.WrapError(err, "bind path=%s type=%s error", param.Path, v.Type().String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
var i int64
if i, err = strconv.ParseInt(val, 0, 0); err == nil {
v.SetInt(i)
return nil
}
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return errutil.WrapError(err, "bind path=%s type=%s error", param.Path, v.Type().String())
case reflect.Float32, reflect.Float64:
var f float64
if f, err = strconv.ParseFloat(val, 64); err == nil {
v.SetFloat(f)
return nil
}
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return errutil.WrapError(err, "bind path=%s type=%s error", param.Path, v.Type().String())
case reflect.Bool:
var b bool
if b, err = strconv.ParseBool(val); err == nil {
v.SetBool(b)
return nil
}
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return errutil.WrapError(err, "bind path=%s type=%s error", param.Path, v.Type().String())
case reflect.String:
v.SetString(val)
return nil
default: // for linter
}

err = fmt.Errorf("unsupported bind type %q", t.String())
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
err = errors.New("unsupported bind type")
return fmt.Errorf("bind path=%s type=%s error: %w", param.Path, v.Type().String(), err)
}

// bindSlice binds properties to a slice value.
func bindSlice(p readOnlyProperties, v reflect.Value, t reflect.Type, param BindParam, filter Filter) error {
func bindSlice(p ReadOnlyProperties, v reflect.Value, t reflect.Type, param BindParam, filter Filter) error {

et := t.Elem()
p, err := getSlice(p, et, param)
if err != nil {
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return errutil.WrapError(err, "bind path=%s type=%s error", param.Path, v.Type().String())
}

slice := reflect.MakeSlice(t, 0, 0)
Expand All @@ -238,14 +243,14 @@ func bindSlice(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bind
break
}
if err != nil {
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return errutil.WrapError(err, "bind path=%s type=%s error", param.Path, v.Type().String())
}
slice = reflect.Append(slice, e)
}
return nil
}

func getSlice(p readOnlyProperties, et reflect.Type, param BindParam) (readOnlyProperties, error) {
func getSlice(p ReadOnlyProperties, et reflect.Type, param BindParam) (ReadOnlyProperties, error) {

// properties that defined as list.
if p.Has(param.Key + "[0]") {
Expand All @@ -259,13 +264,13 @@ func getSlice(p readOnlyProperties, et reflect.Type, param BindParam) (readOnlyP
strVal = p.Get(param.Key)
} else {
if !param.Tag.HasDef {
return nil, fmt.Errorf("%s: property %q %w", macro.FileLine(), param.Key, ErrNotExist)
return nil, fmt.Errorf("property %q %w", param.Key, ErrNotExist)
}
if param.Tag.Def == "" {
return nil, nil
}
if !util.IsPrimitiveValueType(et) && converters[et] == nil {
return nil, fmt.Errorf("%s: can't find converter for %s", macro.FileLine(), et.String())
return nil, fmt.Errorf("can't find converter for %s", et.String())
}
strVal = param.Tag.Def
}
Expand All @@ -286,35 +291,44 @@ func getSlice(p readOnlyProperties, et reflect.Type, param BindParam) (readOnlyP
}
} else if fn, ok := splitters[s]; ok && fn != nil {
if arrVal, err = fn(strVal); err != nil {
return nil, fmt.Errorf("%s: split error: %w, value: %q", macro.FileLine(), err, strVal)
return nil, fmt.Errorf("split error: %w, value: %q", err, strVal)
}
} else {
return nil, fmt.Errorf("%s: unknown splitter %q", macro.FileLine(), s)
return nil, fmt.Errorf("unknown splitter %q", s)
}

r := New()
for i, s := range arrVal {
k := fmt.Sprintf("%s[%d]", param.Key, i)
_ = r.storage.Set(k, s)
if err = r.storage.Set(k, s); err != nil {
return nil, err
}
}
return r, nil
}

// bindMap binds properties to a map value.
func bindMap(p readOnlyProperties, v reflect.Value, t reflect.Type, param BindParam, filter Filter) error {
func bindMap(p ReadOnlyProperties, v reflect.Value, t reflect.Type, param BindParam, filter Filter) error {

if param.Tag.HasDef && param.Tag.Def != "" {
err := errors.New("map can't have a non-empty default value")
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return fmt.Errorf("bind path=%s type=%s error: %w", param.Path, v.Type().String(), err)
}

et := t.Elem()
ret := reflect.MakeMap(t)
defer func() { v.Set(ret) }()

// 当成默认值处理
if param.Tag.Key == "" {
if param.Tag.HasDef {
return nil
}
}

keys, err := p.SubKeys(param.Key)
if err != nil {
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return errutil.WrapError(err, "bind path=%s type=%s error", param.Path, v.Type().String())
}

for _, key := range keys {
Expand All @@ -327,21 +341,20 @@ func bindMap(p readOnlyProperties, v reflect.Value, t reflect.Type, param BindPa
Key: subKey,
Path: param.Path,
}
err = BindValue(p, e, et, subParam, filter)
if err != nil {
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
if err = BindValue(p, e, et, subParam, filter); err != nil {
return err // no wrap
}
ret.SetMapIndex(reflect.ValueOf(key), e)
}
return nil
}

// bindStruct binds properties to a struct value.
func bindStruct(p readOnlyProperties, v reflect.Value, t reflect.Type, param BindParam, filter Filter) error {
func bindStruct(p ReadOnlyProperties, v reflect.Value, t reflect.Type, param BindParam, filter Filter) error {

if param.Tag.HasDef && param.Tag.Def != "" {
err := errors.New("struct can't have a non-empty default value")
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return fmt.Errorf("bind path=%s type=%s error: %w", param.Path, v.Type().String(), err)
}

for i := 0; i < t.NumField(); i++ {
Expand All @@ -359,7 +372,7 @@ func bindStruct(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bin

if tag, ok := ft.Tag.Lookup("value"); ok {
if err := subParam.BindTag(tag, ft.Tag); err != nil {
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return errutil.WrapError(err, "bind path=%s type=%s error", param.Path, v.Type().String())
}
if filter != nil {
ret, err := filter.Do(fv.Addr().Interface(), subParam)
Expand All @@ -371,7 +384,7 @@ func bindStruct(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bin
}
}
if err := BindValue(p, fv, ft.Type, subParam, filter); err != nil {
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return err // no wrap
}
continue
}
Expand All @@ -382,12 +395,12 @@ func bindStruct(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bin
continue
}
if err := bindStruct(p, fv, ft.Type, subParam, filter); err != nil {
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return err // no wrap
}
continue
}

if util.IsValueType(ft.Type) {
if util.IsPropBindingTarget(ft.Type) {
if subParam.Key == "" {
subParam.Key = ft.Name
} else {
Expand All @@ -396,33 +409,31 @@ func bindStruct(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bin
subParam.Key = strings.ToLower(subParam.Key)
subParam.Key = strings.ReplaceAll(subParam.Key, "_", ".")
if err := BindValue(p, fv, ft.Type, subParam, filter); err != nil {
return fmt.Errorf("%s: bind %s error, %w", macro.FileLine(), param.Path, err)
return err // no wrap
}
}
}
return nil
}

// resolve returns property references processed property value.
func resolve(p readOnlyProperties, param BindParam) (string, error) {
func resolve(p ReadOnlyProperties, param BindParam) (string, error) {
const defVal = "@@def@@"
val := p.Get(param.Key, Def(defVal))
val := p.Get(param.Key, defVal)
if val != defVal {
return resolveString(p, val)
}
if p.Has(param.Key) {
err := fmt.Errorf("property %q isn't simple value", param.Key)
return "", fmt.Errorf("%s: resolve property %q error, %w", macro.FileLine(), param.Key, err)
return "", fmt.Errorf("property key=%s isn't simple value", param.Key)
}
if param.Tag.HasDef {
return resolveString(p, param.Tag.Def)
}
err := fmt.Errorf("property %q %w", param.Key, ErrNotExist)
return "", fmt.Errorf("%s: resolve property %q error, %w", macro.FileLine(), param.Key, err)
return "", fmt.Errorf("property key=%s %w", param.Key, ErrNotExist)
}

// resolveString returns property references processed string.
func resolveString(p readOnlyProperties, s string) (string, error) {
func resolveString(p ReadOnlyProperties, s string) (string, error) {

var (
length = len(s)
Expand Down Expand Up @@ -456,20 +467,20 @@ func resolveString(p readOnlyProperties, s string) (string, error) {

if end < 0 || count > 0 {
err := ErrInvalidSyntax
return "", fmt.Errorf("%s: resolve string %q error, %w", macro.FileLine(), s, err)
return "", fmt.Errorf("resolve string %q error: %w", s, err)
}

var param BindParam
_ = param.BindTag(s[start:end+1], "")

s1, err := resolve(p, param)
if err != nil {
return "", fmt.Errorf("%s: resolve string %q error, %w", macro.FileLine(), s, err)
return "", errutil.WrapError(err, "resolve string %q error", s)
}

s2, err := resolveString(p, s[end+1:])
if err != nil {
return "", fmt.Errorf("%s: resolve string %q error, %w", macro.FileLine(), s, err)
return "", errutil.WrapError(err, "resolve string %q error", s)
}

return s[:start] + s1 + s2, nil
Expand Down
Loading