Skip to content
/ defaults Public

Go default values filling for structures with support of almost all types of data

License

Notifications You must be signed in to change notification settings

sidai/defaults

Repository files navigation

defaults Test GitHub release License

Structures default value filling with support in almost all types of data using struct tags or struct type

Notice

This repo is inspired by go-defaults and applies the same 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 or Type
    If both rules found when filling a field, FuncsByKind is used first before FuncsByType

  • 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 Examples:

    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 Examples:

    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

About

Go default values filling for structures with support of almost all types of data

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Languages