浏览代码

feat: conf add FillDefault func

MarkJoyMa 2 年之前
父节点
当前提交
f3cf891d4f
共有 3 个文件被更改,包括 70 次插入8 次删除
  1. 16 6
      core/conf/config.go
  2. 40 0
      core/conf/config_test.go
  3. 14 2
      core/mapping/unmarshaler.go

+ 16 - 6
core/conf/config.go

@@ -13,12 +13,17 @@ import (
 	"github.com/zeromicro/go-zero/internal/encoding"
 )
 
-var loaders = map[string]func([]byte, any) error{
-	".json": LoadFromJsonBytes,
-	".toml": LoadFromTomlBytes,
-	".yaml": LoadFromYamlBytes,
-	".yml":  LoadFromYamlBytes,
-}
+const jsonTagKey = "json"
+
+var (
+	fillDefaultUnmarshaler = mapping.NewUnmarshaler(jsonTagKey, mapping.WithDefault())
+	loaders                = map[string]func([]byte, any) error{
+		".json": LoadFromJsonBytes,
+		".toml": LoadFromTomlBytes,
+		".yaml": LoadFromYamlBytes,
+		".yml":  LoadFromYamlBytes,
+	}
+)
 
 // children and mapField should not be both filled.
 // named fields and map cannot be bound to the same field name.
@@ -27,6 +32,11 @@ type fieldInfo struct {
 	mapField *fieldInfo
 }
 
+// FillDefault fills the default values for the given v.
+func FillDefault(v any) error {
+	return fillDefaultUnmarshaler.Unmarshal(map[string]any{}, v)
+}
+
 // Load loads config into v from file, .json, .yaml and .yml are acceptable.
 func Load(file string, v any, opts ...Option) error {
 	content, err := os.ReadFile(file)

+ 40 - 0
core/conf/config_test.go

@@ -1039,3 +1039,43 @@ func createTempFile(ext, text string) (string, error) {
 
 	return filename, nil
 }
+
+func TestFillDefaultUnmarshal(t *testing.T) {
+	t.Run("nil", func(t *testing.T) {
+		type St struct{}
+		err := FillDefault(St{})
+		assert.Error(t, err)
+	})
+
+	t.Run("not nil", func(t *testing.T) {
+		type St struct{}
+		err := FillDefault(&St{})
+		assert.NoError(t, err)
+	})
+
+	t.Run("default", func(t *testing.T) {
+		type St struct {
+			A string `json:",default=a"`
+			B string
+		}
+		var st St
+		err := FillDefault(&st)
+		assert.NoError(t, err)
+		assert.Equal(t, st.A, "a")
+	})
+
+	t.Run("env", func(t *testing.T) {
+		type St struct {
+			A string `json:",default=a"`
+			B string
+			C string `json:",env=TEST_C"`
+		}
+		t.Setenv("TEST_C", "c")
+
+		var st St
+		err := FillDefault(&st)
+		assert.NoError(t, err)
+		assert.Equal(t, st.A, "a")
+		assert.Equal(t, st.C, "c")
+	})
+}

+ 14 - 2
core/mapping/unmarshaler.go

@@ -47,6 +47,7 @@ type (
 	UnmarshalOption func(*unmarshalOptions)
 
 	unmarshalOptions struct {
+		fillDefault  bool
 		fromString   bool
 		canonicalKey func(key string) string
 	}
@@ -710,7 +711,7 @@ func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect
 
 	valuer := createValuer(m, opts)
 	mapValue, hasValue := getValue(valuer, canonicalKey)
-	if !hasValue {
+	if !hasValue || u.opts.fillDefault {
 		return u.processNamedFieldWithoutValue(field.Type, value, opts, fullName)
 	}
 
@@ -801,6 +802,10 @@ func (u *Unmarshaler) processNamedFieldWithoutValue(fieldType reflect.Type, valu
 		}
 	}
 
+	if u.opts.fillDefault {
+		return nil
+	}
+
 	switch fieldKind {
 	case reflect.Array, reflect.Map, reflect.Slice:
 		if !opts.optional() {
@@ -873,13 +878,20 @@ func WithStringValues() UnmarshalOption {
 	}
 }
 
-// WithCanonicalKeyFunc customizes an Unmarshaler with Canonical Key func
+// WithCanonicalKeyFunc customizes an Unmarshaler with Canonical Key func.
 func WithCanonicalKeyFunc(f func(string) string) UnmarshalOption {
 	return func(opt *unmarshalOptions) {
 		opt.canonicalKey = f
 	}
 }
 
+// WithDefault customizes an Unmarshaler with fill default values.
+func WithDefault() UnmarshalOption {
+	return func(opt *unmarshalOptions) {
+		opt.fillDefault = true
+	}
+}
+
 func createValuer(v valuerWithParent, opts *fieldOptionsWithContext) valuerWithParent {
 	if opts.inherit() {
 		return recursiveValuer{