https://github.com/sidai/defaults
Go default values filling for structures with support of almost all types of data
https://github.com/sidai/defaults
defaults go golang
Last synced: 5 months ago
JSON representation
Go default values filling for structures with support of almost all types of data
- Host: GitHub
- URL: https://github.com/sidai/defaults
- Owner: sidai
- License: mit
- Created: 2021-07-23T10:30:25.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2022-03-02T03:22:51.000Z (over 4 years ago)
- Last Synced: 2024-06-20T12:36:47.806Z (about 2 years ago)
- Topics: defaults, go, golang
- Language: Go
- Homepage:
- Size: 22.5 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
defaults [](https://github.com/sidai/defaults/actions/workflows/test.yml) [](https://github.com/sidai/defaults/releases) [](./LICENSE)
=======
Structures default value filling with support in almost all types of data using [struct tags](http://golang.org/pkg/reflect/#StructTag) or [struct type](https://pkg.go.dev/reflect#Type)
Notice
-------
This repo is inspired by [go-defaults](https://github.com/sidai/go-defaults) and applies the same [LICENSE](https://github.com/sidai/defaults/blob/master/LICENSE).
The aforementioned repo provides basic default value filling for simple data types. However,
1. It does not support complex structure like `pointer`, `interface`, `map` or `slice of map`.
2. It always recursively fills the struct with default value but there are cases struct filling should be skipped.
3. The default filler provided is not exported which makes it hard for customization.
I created this repo to provide more data types support, more flexibility in default value filling for struct and export the function for better customization.
Supported Data Types
-------
- **Primitive Types:**
- `bool`
- `int`, `int8`, `int16`, `int32`, `int64`
- `uint`, `uint8`, `uint16`, `uint32`, `uint64`
- `float32`, `float64`
- `[]byte`, `string`
- **Custom Types:**
- `time.Duration`, `time.Time`
- Aliased types. e.g `type UserName string`
- Self-defined types. e.g. `type User struct {Name string, Age int}`
- **Complex Types:**
- `map`, `slice`, `interface`, `struct`
- **Nested Types:**
- e.g. `map[int][]*User`, `[]map[int]*User`, `map[int]map[int]*User`
- **Pointer Types:**
- e.g. `*int`, `*User`, `**int`, `**User`
Rules
-------
- Filling rules can be defined either by [Kind](https://pkg.go.dev/reflect#Kind) or [Type](https://pkg.go.dev/reflect#Type)
If both rules found when filling a field,
[FuncsByKind](https://github.com/sidai/defaults/blob/master/filler.go#L17) is used first before
[FuncsByType](https://github.com/sidai/defaults/blob/master/filler.go#L18)
- Skip default filling for non-zero fields to prevent fields with initial value being reset
- By default struct is recursively filled only when it is *empty*
Use `default:"omit"` to always skip struct filling
Use `default:"dive"` to always apply struct filling even when it is not empty
Usage
-------
- **Installation**: ```go get github.com/sidai/defaults```
- **[FuncsByKind](https://github.com/sidai/defaults/blob/master/filler.go#L17) Examples**:
```go
type Role string
type Admin struct {
Name string
Role Role `default:"admin"`
}
func (a *Admin) GetRole() Role {
return a.Role
}
type User interface {
GetRole() Role
}
type ExampleFuncsByKind struct {
Int int `default:"1"` // Primitive
IntPtrPtr **int `default:"1"` // Ptr type
Role Role `default:"DBA"` // Alias of Primitive
Duration time.Duration `default:"1s"` // Duration
Time time.Time `default:"2007-07-07T07:07:07.007Z"` // Time
ListOfInt []int `default:"[1,2,3,4]"` // Slice
ListOfIntList [][]int `default:"[[1,2],[3,4]]"` // 2D Slice
ListOfIntMap []map[int]int `default:"[{1:10,2:20},{3:30,4:40}]"` // Slice of Map
Admin Admin // Struct
AdminPtr *Admin // Struct Ptr
AdminOmit Admin `default:"omit"` // Struct w Omit
AdminWithVal Admin // Struct w Initial Value
AdminWithValDive Admin `default:"dive"` // Struct w Dive
User User // Interface
UserWithVal User // Interface w Implementation
UserWithValDive User `default:"dive"` // Interface w Implementation & Dive
}
...
foo := ExampleFuncsByKind{
AdminWithVal: Admin{Name: "admin1"},
AdminWithValDive: Admin{Name: "admin2"},
UserWithVal: &Admin{Name: "admin3"},
UserWithValDive: &Admin{Name: "admin4"},
}
SetDefaults(&foo)
foo = {
"Int": 1,
"IntPtrPtr": (**int) 1,
"Role": "DBA",
"Duration": 1s,
"Time": "2007-07-07 07:07:07.007 +0000 UTC",
"ListOfInt": [1, 2, 3, 4],
"ListOfIntList": [[1, 2], [3, 4]],
"ListOfIntMap": [{1: 10, 2: 20}, {3: 30, 4: 40}],
"Admin": {"Name": "", "Role": "admin"}, // Role filled with default value "admin" for emtpy field
"AdminPtr": (*Admin) {"Name": "", "Role": "admin"}, // Role filled with default value "admin" for emtpy pointer field
"AdminOmit": {"Name": "", "Role": ""}, // Role not filled even when AdminOmit is emtpy since "omit" tag found
"AdminWithVal": {"Name": "admin1", "Role": ""}, // Role not filled since AdminWithVal field is not empty
"AdminWithValDive": {"Name": "admin2", "Role": "admin"}, // Role filled even when AdminWithValDive field is not empty since "dive" tag found
"User": nil, // User not filled no implementation found
"UserWithVal": (*Admin) {"Name": "admin3", "Role": ""}, // User Role not filled since implementation UserWithVal is not empty
"UserWithValDive": (*Admin) {"Name": "admin4", "Role": "admin"} // User Role filled since implementation UserWithValDive has "dive" tag
}
```
- **[FuncsByType](https://github.com/sidai/defaults/blob/master/filler.go#L18) Examples**:
```go
type Enum string
type DefaultData struct {
String string
Int int
}
type ExampleFuncsByType struct {
Enum Enum
EnumWithTag Enum `default:"tag"`
EnumWithValueNTag Enum `default:"tag"`
DefaultData DefaultData
DefaultDataOmit DefaultData `default:"omit"`
DefaultDataWithVal DefaultData
DefaultDataWithValDive DefaultData `default:"dive"`
}
foo := ExampleFuncsByType{
EnumWithValueNTag: Enum("value"),
DefaultDataWithVal: DefaultData{Int: 1},
DefaultDataWithValDive: DefaultData{Int: 1},
}
RegisterDefaultType(Enum("type"))
RegisterDefaultType(DefaultData{String: "type", Int: 7})
SetDefaults(&foo)
...
foo = {
"Enum": "type", // Use FuncsByType
"EnumWithTag": "tag", // Use tag as FuncsByKind has higher precedence
"EnumWithValueNTag": "value", // No filling applied as value is not empty
"DefaultData": {String: "type", Int: 7}, // Use FuncsByType
"DefaultDataOmit": {String: "", Int: 0}, // Omit tag works for FuncsByType
"DefaultDataWithVal": {String: "", Int: 1}, // FuncsByType skip filling when value is not empty
"DefaultDataWithValDive": {String: "", Int: 1} // FuncsByType ignores dive tag as it works on the extra type only
}
```
- More Examples [*Here*](https://github.com/sidai/defaults/blob/master/filler_test.go)