Skip to content

Commit

Permalink
chore: optimise function config.ConfigKeyToEnv (#475)
Browse files Browse the repository at this point in the history
  • Loading branch information
mihir20 committed May 21, 2024
1 parent 5e79a3f commit 0cbe3e2
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 11 deletions.
9 changes: 1 addition & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ package config

import (
"fmt"
"regexp"
"strconv"
"strings"
"sync"
Expand All @@ -46,12 +45,6 @@ import (

const DefaultEnvPrefix = "RSERVER"

// regular expression matching lowercase letter followed by an uppercase letter
var camelCaseMatch = regexp.MustCompile("([a-z0-9])([A-Z])")

// regular expression matching uppercase letters contained in environment variable names
var upperCaseMatch = regexp.MustCompile("^[A-Z0-9_]+$")

// Default is the singleton config instance
var Default *Config

Expand Down Expand Up @@ -341,7 +334,7 @@ func getOrCreatePointer[T configTypes](
// the replacer cannot detect camelCase keys.
func (c *Config) bindEnv(key string) {
envVar := key
if !upperCaseMatch.MatchString(key) {
if !isUpperCaseConfigKey(key) {
envVar = ConfigKeyToEnv(c.envPrefix, key)
}
// bind once
Expand Down
13 changes: 13 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,9 @@ func TestConfigKeyToEnv(t *testing.T) {
require.Equal(t, expected, ConfigKeyToEnv(DefaultEnvPrefix, "KeyVar1Var2"))
require.Equal(t, expected, ConfigKeyToEnv(DefaultEnvPrefix, "RSERVER_KEY_VAR1_VAR2"))
require.Equal(t, "KEY_VAR1_VAR2", ConfigKeyToEnv(DefaultEnvPrefix, "KEY_VAR1_VAR2"))
require.Equal(t, expected, ConfigKeyToEnv(DefaultEnvPrefix, "Key_Var1.Var2"))
require.Equal(t, expected, ConfigKeyToEnv(DefaultEnvPrefix, "key_Var1_Var2"))
require.Equal(t, "RSERVER_KEY_VAR_1_VAR2", ConfigKeyToEnv(DefaultEnvPrefix, "Key_Var.1.Var2"))
}

func TestGetEnvThroughViper(t *testing.T) {
Expand Down Expand Up @@ -724,3 +727,13 @@ func TestConfigLoad(t *testing.T) {
require.Error(t, err)
})
}

// Benchmark for the original ConfigKeyToEnv function
func BenchmarkConfigKeyToEnv(b *testing.B) {
envPrefix := "MYAPP"
configKey := "myConfig.KeyName"
for i := 0; i < b.N; i++ {
_ = ConfigKeyToEnv(envPrefix, configKey)
}
b.ReportAllocs()
}
37 changes: 34 additions & 3 deletions config/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,46 @@ package config
import (
"os"
"strings"
"unicode"
)

func isUpperCaseConfigKey(s string) bool {
for _, ch := range s {
if !(ch == '_' || unicode.IsUpper(ch) || unicode.IsDigit(ch)) {
return false
}
}
return true
}

// ConfigKeyToEnv gets the env variable name from a given config key
func ConfigKeyToEnv(envPrefix, s string) string {
if upperCaseMatch.MatchString(s) {
// Check if the string is already in upper case format
if isUpperCaseConfigKey(s) {
return s
}
snake := camelCaseMatch.ReplaceAllString(s, "${1}_${2}")
return envPrefix + "_" + strings.ToUpper(strings.ReplaceAll(snake, ".", "_"))

// convert camelCase to snake_case
var builder strings.Builder

// Add the prefix
builder.WriteString(envPrefix)
builder.WriteByte('_')

// Transform the input string to the desired format
for i, r := range s {
if r >= 'A' && r <= 'Z' && i > 0 && (s[i-1] >= 'a' && s[i-1] <= 'z' || s[i-1] >= '0' && s[i-1] <= '9') {
builder.WriteByte('_')
} else if r == '.' {
r = '_'
}
if unicode.IsLetter(r) {
r = unicode.ToUpper(r)
}
builder.WriteRune(r)
}

return builder.String()
}

// getEnv returns the environment value stored in key variable
Expand Down

0 comments on commit 0cbe3e2

Please sign in to comment.