mirror of
https://github.com/spf13/viper
synced 2024-12-23 03:57:01 +00:00
Add tenant feature
This commit is contained in:
parent
16990631d4
commit
f9a0422e88
3 changed files with 246 additions and 0 deletions
50
README.md
50
README.md
|
@ -599,6 +599,56 @@ y.SetDefault("ContentDir", "foobar")
|
|||
When working with multiple vipers, it is up to the user to keep track of the
|
||||
different vipers.
|
||||
|
||||
### Working with tenant
|
||||
|
||||
Sometime you want your config to be override by a more specific one, use tenant for it.
|
||||
|
||||
Example:
|
||||
|
||||
config file:
|
||||
```json
|
||||
[shared]
|
||||
name = "name_shared"
|
||||
|
||||
[tenant_a]
|
||||
name = "name_a"
|
||||
|
||||
[tenant_b]
|
||||
|
||||
```
|
||||
|
||||
code:
|
||||
```go
|
||||
viper.SetTenantDefault("shared")
|
||||
viper.SetConfigName("teste")
|
||||
viper.AddConfigPath(".")
|
||||
viper.ReadInConfig()
|
||||
|
||||
fmt.Printf(viper.GetStringTenant("tenant_a", "name")) // name_a
|
||||
fmt.Printf(viper.GetStringTenant("tenant_b", "name")) // name_shared
|
||||
```
|
||||
|
||||
config file:
|
||||
```json
|
||||
name = "name_shared"
|
||||
|
||||
[tenant_a]
|
||||
name = "name_a"
|
||||
|
||||
[tenant_b]
|
||||
|
||||
```
|
||||
|
||||
code:
|
||||
```go
|
||||
viper.SetConfigName("teste")
|
||||
viper.AddConfigPath(".")
|
||||
viper.ReadInConfig()
|
||||
|
||||
fmt.Printf(viper.GetStringTenant("tenant_a", "name")) // name_a
|
||||
fmt.Printf(viper.GetStringTenant("tenant_b", "name")) // name_shared
|
||||
```
|
||||
|
||||
## Q & A
|
||||
|
||||
Q: Why not INI files?
|
||||
|
|
162
viper.go
162
viper.go
|
@ -157,6 +157,9 @@ type Viper struct {
|
|||
typeByDefValue bool
|
||||
|
||||
onConfigChange func(fsnotify.Event)
|
||||
|
||||
//name of default tenant
|
||||
tenantDefault string
|
||||
}
|
||||
|
||||
// Returns an initialized Viper instance.
|
||||
|
@ -270,6 +273,12 @@ func (v *Viper) WatchConfig() {
|
|||
}()
|
||||
}
|
||||
|
||||
// Explicitly define the tenant default that will be override by others tenants
|
||||
func SetTenantDefault(tenDefault string) { v.SetTenantDefault(tenDefault) }
|
||||
func (v *Viper) SetTenantDefault(tenDefault string) {
|
||||
v.tenantDefault = tenDefault
|
||||
}
|
||||
|
||||
// Explicitly define the path, name and extension of the config file
|
||||
// Viper will use this and not check any of the config paths
|
||||
func SetConfigFile(in string) { v.SetConfigFile(in) }
|
||||
|
@ -542,66 +551,219 @@ func (v *Viper) Sub(key string) *Viper {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a string considering the tenant selected
|
||||
func GetStringTenant(tenant string, key string) string { return v.GetStringTenant(tenant, key) }
|
||||
func (v *Viper) GetStringTenant(tenant string, key string) string {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToString(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToString(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToString(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a string
|
||||
func GetString(key string) string { return v.GetString(key) }
|
||||
func (v *Viper) GetString(key string) string {
|
||||
return cast.ToString(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a boolean considering the tenant selected
|
||||
func GetBoolTenant(tenant string, key string) bool { return v.GetBoolTenant(tenant, key) }
|
||||
func (v *Viper) GetBoolTenant(tenant string, key string) bool {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToBool(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToBool(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToBool(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a boolean
|
||||
func GetBool(key string) bool { return v.GetBool(key) }
|
||||
func (v *Viper) GetBool(key string) bool {
|
||||
return cast.ToBool(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a int considering the tenant selected
|
||||
func GetIntTenant(tenant string, key string) int { return v.GetIntTenant(tenant, key) }
|
||||
func (v *Viper) GetIntTenant(tenant string, key string) int {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToInt(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToInt(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToInt(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as an integer
|
||||
func GetInt(key string) int { return v.GetInt(key) }
|
||||
func (v *Viper) GetInt(key string) int {
|
||||
return cast.ToInt(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a int considering the tenant selected
|
||||
func GetInt64Tenant(tenant string, key string) int64 { return v.GetInt64Tenant(tenant, key) }
|
||||
func (v *Viper) GetInt64Tenant(tenant string, key string) int64 {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToInt64(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToInt64(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToInt64(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as an integer
|
||||
func GetInt64(key string) int64 { return v.GetInt64(key) }
|
||||
func (v *Viper) GetInt64(key string) int64 {
|
||||
return cast.ToInt64(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a float considering the tenant selected
|
||||
func GetFloat64Tenant(tenant string, key string) float64 { return v.GetFloat64Tenant(tenant, key) }
|
||||
func (v *Viper) GetFloat64Tenant(tenant string, key string) float64 {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToFloat64(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToFloat64(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToFloat64(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a float64
|
||||
func GetFloat64(key string) float64 { return v.GetFloat64(key) }
|
||||
func (v *Viper) GetFloat64(key string) float64 {
|
||||
return cast.ToFloat64(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a time considering the tenant selected
|
||||
func GetTimeTenant(tenant string, key string) time.Time { return v.GetTimeTenant(tenant, key) }
|
||||
func (v *Viper) GetTimeTenant(tenant string, key string) time.Time {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToTime(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToTime(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToTime(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as time
|
||||
func GetTime(key string) time.Time { return v.GetTime(key) }
|
||||
func (v *Viper) GetTime(key string) time.Time {
|
||||
return cast.ToTime(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a duration considering the tenant selected
|
||||
func GetDurationTenant(tenant string, key string) time.Duration {
|
||||
return v.GetDurationTenant(tenant, key)
|
||||
}
|
||||
func (v *Viper) GetDurationTenant(tenant string, key string) time.Duration {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToDuration(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToDuration(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToDuration(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a duration
|
||||
func GetDuration(key string) time.Duration { return v.GetDuration(key) }
|
||||
func (v *Viper) GetDuration(key string) time.Duration {
|
||||
return cast.ToDuration(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a slice of strings considering the tenant selected
|
||||
func GetStringSliceTenant(tenant string, key string) []string {
|
||||
return v.GetStringSliceTenant(tenant, key)
|
||||
}
|
||||
func (v *Viper) GetStringSliceTenant(tenant string, key string) []string {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToStringSlice(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToStringSlice(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToStringSlice(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a slice of strings
|
||||
func GetStringSlice(key string) []string { return v.GetStringSlice(key) }
|
||||
func (v *Viper) GetStringSlice(key string) []string {
|
||||
return cast.ToStringSlice(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a map of interfaces considering the tenant selected
|
||||
func GetStringMapTenant(tenant string, key string) map[string]interface{} {
|
||||
return v.GetStringMapTenant(tenant, key)
|
||||
}
|
||||
func (v *Viper) GetStringMapTenant(tenant string, key string) map[string]interface{} {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToStringMap(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToStringMap(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToStringMap(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a map of interfaces
|
||||
func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) }
|
||||
func (v *Viper) GetStringMap(key string) map[string]interface{} {
|
||||
return cast.ToStringMap(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a map of strings considering the tenant selected
|
||||
func GetStringMapStringTenant(tenant string, key string) map[string]string {
|
||||
return v.GetStringMapStringTenant(tenant, key)
|
||||
}
|
||||
func (v *Viper) GetStringMapStringTenant(tenant string, key string) map[string]string {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToStringMapString(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToStringMapString(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToStringMapString(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a map of strings
|
||||
func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) }
|
||||
func (v *Viper) GetStringMapString(key string) map[string]string {
|
||||
return cast.ToStringMapString(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as map to a slice of strings considering the tenant selected
|
||||
func GetStringMapStringSliceTenant(tenant string, key string) map[string][]string {
|
||||
return v.GetStringMapStringSliceTenant(tenant, key)
|
||||
}
|
||||
func (v *Viper) GetStringMapStringSliceTenant(tenant string, key string) map[string][]string {
|
||||
if v.IsSet(tenant + "." + key) {
|
||||
return cast.ToStringMapStringSlice(v.Get(tenant + "." + key))
|
||||
}
|
||||
|
||||
if v.tenantDefault != "" {
|
||||
return cast.ToStringMapStringSlice(v.Get(v.tenantDefault + "." + key))
|
||||
}
|
||||
return cast.ToStringMapStringSlice(v.Get(key))
|
||||
}
|
||||
|
||||
// Returns the value associated with the key as a map to a slice of strings.
|
||||
func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) }
|
||||
func (v *Viper) GetStringMapStringSlice(key string) map[string][]string {
|
||||
|
|
|
@ -102,6 +102,21 @@ var remoteExample = []byte(`{
|
|||
"newkey":"remote"
|
||||
}`)
|
||||
|
||||
var tenantExample = []byte(`
|
||||
title = "TOML Example"
|
||||
attr = "Foo"
|
||||
|
||||
[owner]
|
||||
title = "TOML!"`)
|
||||
|
||||
var tenantExampleWithDefault = []byte(`
|
||||
[default]
|
||||
title = "TOML Example"
|
||||
attr = "Foo"
|
||||
|
||||
[owner]
|
||||
title = "TOML!"`)
|
||||
|
||||
func initConfigs() {
|
||||
Reset()
|
||||
SetConfigType("yaml")
|
||||
|
@ -760,6 +775,25 @@ func TestSub(t *testing.T) {
|
|||
assert.Equal(t, subv, (*Viper)(nil))
|
||||
}
|
||||
|
||||
func TestTenant(t *testing.T) {
|
||||
v := New()
|
||||
v.SetConfigType("toml")
|
||||
v.ReadConfig(bytes.NewBuffer(tenantExample))
|
||||
|
||||
assert.Equal(t, v.GetStringTenant("owner", "title"), "TOML!")
|
||||
assert.Equal(t, v.GetStringTenant("owner", "attr"), "Foo")
|
||||
}
|
||||
|
||||
func TestTenantWithDefault(t *testing.T) {
|
||||
v := New()
|
||||
v.SetConfigType("toml")
|
||||
v.SetTenantDefault("default")
|
||||
v.ReadConfig(bytes.NewBuffer(tenantExampleWithDefault))
|
||||
|
||||
assert.Equal(t, v.GetStringTenant("owner", "title"), "TOML!")
|
||||
assert.Equal(t, v.GetStringTenant("owner", "attr"), "Foo")
|
||||
}
|
||||
|
||||
var yamlMergeExampleTgt = []byte(`
|
||||
hello:
|
||||
pop: 37890
|
||||
|
|
Loading…
Reference in a new issue