mirror of
https://github.com/spf13/viper
synced 2024-11-16 18:07:02 +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
|
When working with multiple vipers, it is up to the user to keep track of the
|
||||||
different vipers.
|
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 & A
|
||||||
|
|
||||||
Q: Why not INI files?
|
Q: Why not INI files?
|
||||||
|
|
162
viper.go
162
viper.go
|
@ -157,6 +157,9 @@ type Viper struct {
|
||||||
typeByDefValue bool
|
typeByDefValue bool
|
||||||
|
|
||||||
onConfigChange func(fsnotify.Event)
|
onConfigChange func(fsnotify.Event)
|
||||||
|
|
||||||
|
//name of default tenant
|
||||||
|
tenantDefault string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an initialized Viper instance.
|
// 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
|
// Explicitly define the path, name and extension of the config file
|
||||||
// Viper will use this and not check any of the config paths
|
// Viper will use this and not check any of the config paths
|
||||||
func SetConfigFile(in string) { v.SetConfigFile(in) }
|
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
|
// Returns the value associated with the key as a string
|
||||||
func GetString(key string) string { return v.GetString(key) }
|
func GetString(key string) string { return v.GetString(key) }
|
||||||
func (v *Viper) GetString(key string) string {
|
func (v *Viper) GetString(key string) string {
|
||||||
return cast.ToString(v.Get(key))
|
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
|
// Returns the value associated with the key as a boolean
|
||||||
func GetBool(key string) bool { return v.GetBool(key) }
|
func GetBool(key string) bool { return v.GetBool(key) }
|
||||||
func (v *Viper) GetBool(key string) bool {
|
func (v *Viper) GetBool(key string) bool {
|
||||||
return cast.ToBool(v.Get(key))
|
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
|
// Returns the value associated with the key as an integer
|
||||||
func GetInt(key string) int { return v.GetInt(key) }
|
func GetInt(key string) int { return v.GetInt(key) }
|
||||||
func (v *Viper) GetInt(key string) int {
|
func (v *Viper) GetInt(key string) int {
|
||||||
return cast.ToInt(v.Get(key))
|
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
|
// Returns the value associated with the key as an integer
|
||||||
func GetInt64(key string) int64 { return v.GetInt64(key) }
|
func GetInt64(key string) int64 { return v.GetInt64(key) }
|
||||||
func (v *Viper) GetInt64(key string) int64 {
|
func (v *Viper) GetInt64(key string) int64 {
|
||||||
return cast.ToInt64(v.Get(key))
|
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
|
// Returns the value associated with the key as a float64
|
||||||
func GetFloat64(key string) float64 { return v.GetFloat64(key) }
|
func GetFloat64(key string) float64 { return v.GetFloat64(key) }
|
||||||
func (v *Viper) GetFloat64(key string) float64 {
|
func (v *Viper) GetFloat64(key string) float64 {
|
||||||
return cast.ToFloat64(v.Get(key))
|
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
|
// Returns the value associated with the key as time
|
||||||
func GetTime(key string) time.Time { return v.GetTime(key) }
|
func GetTime(key string) time.Time { return v.GetTime(key) }
|
||||||
func (v *Viper) GetTime(key string) time.Time {
|
func (v *Viper) GetTime(key string) time.Time {
|
||||||
return cast.ToTime(v.Get(key))
|
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
|
// Returns the value associated with the key as a duration
|
||||||
func GetDuration(key string) time.Duration { return v.GetDuration(key) }
|
func GetDuration(key string) time.Duration { return v.GetDuration(key) }
|
||||||
func (v *Viper) GetDuration(key string) time.Duration {
|
func (v *Viper) GetDuration(key string) time.Duration {
|
||||||
return cast.ToDuration(v.Get(key))
|
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
|
// Returns the value associated with the key as a slice of strings
|
||||||
func GetStringSlice(key string) []string { return v.GetStringSlice(key) }
|
func GetStringSlice(key string) []string { return v.GetStringSlice(key) }
|
||||||
func (v *Viper) GetStringSlice(key string) []string {
|
func (v *Viper) GetStringSlice(key string) []string {
|
||||||
return cast.ToStringSlice(v.Get(key))
|
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
|
// Returns the value associated with the key as a map of interfaces
|
||||||
func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) }
|
func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) }
|
||||||
func (v *Viper) GetStringMap(key string) map[string]interface{} {
|
func (v *Viper) GetStringMap(key string) map[string]interface{} {
|
||||||
return cast.ToStringMap(v.Get(key))
|
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
|
// Returns the value associated with the key as a map of strings
|
||||||
func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) }
|
func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) }
|
||||||
func (v *Viper) GetStringMapString(key string) map[string]string {
|
func (v *Viper) GetStringMapString(key string) map[string]string {
|
||||||
return cast.ToStringMapString(v.Get(key))
|
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.
|
// 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 GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) }
|
||||||
func (v *Viper) GetStringMapStringSlice(key string) map[string][]string {
|
func (v *Viper) GetStringMapStringSlice(key string) map[string][]string {
|
||||||
|
|
|
@ -102,6 +102,21 @@ var remoteExample = []byte(`{
|
||||||
"newkey":"remote"
|
"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() {
|
func initConfigs() {
|
||||||
Reset()
|
Reset()
|
||||||
SetConfigType("yaml")
|
SetConfigType("yaml")
|
||||||
|
@ -760,6 +775,25 @@ func TestSub(t *testing.T) {
|
||||||
assert.Equal(t, subv, (*Viper)(nil))
|
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(`
|
var yamlMergeExampleTgt = []byte(`
|
||||||
hello:
|
hello:
|
||||||
pop: 37890
|
pop: 37890
|
||||||
|
|
Loading…
Reference in a new issue