♻️ Refactor config
Make it easier to setup stores
This commit is contained in:
parent
ecae0d5f83
commit
6f06adc37d
12 changed files with 623 additions and 81 deletions
|
|
@ -1,18 +1,76 @@
|
|||
package config
|
||||
|
||||
type Config struct {
|
||||
Name string `toml:"name"`
|
||||
Env Env `toml:"env"`
|
||||
BaseURL string `toml:"base_url"`
|
||||
Conn ConnSettings `toml:"conn"`
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
name string
|
||||
env Env
|
||||
baseURL string
|
||||
stores stores
|
||||
md toml.MetaData
|
||||
}
|
||||
|
||||
type ConnSettings struct {
|
||||
Store string `toml:"store"`
|
||||
DSN string `toml:"dsn"`
|
||||
Settings map[string]any `toml:"settings"`
|
||||
var _ Config = config{}
|
||||
|
||||
func (c config) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func (c Config) Environment() Env {
|
||||
return ValidEnvOrDev(c.Env)
|
||||
func (c config) Env() Env {
|
||||
return ValidEnvOrDev(c.env)
|
||||
}
|
||||
|
||||
func (c config) BaseURL() string {
|
||||
return c.baseURL
|
||||
}
|
||||
|
||||
func (c config) Store(name string) (Store, error) {
|
||||
if name == "" {
|
||||
name = c.stores.store
|
||||
}
|
||||
return c.stores.GetStore(name)
|
||||
}
|
||||
|
||||
func (c config) StoreName() string {
|
||||
return c.stores.store
|
||||
}
|
||||
|
||||
type stores struct {
|
||||
store string
|
||||
settings map[string]toml.Primitive
|
||||
conf *config
|
||||
}
|
||||
|
||||
var ErrMissingStore = errors.New("unknown store")
|
||||
|
||||
func (ss stores) GetStore(name string) (Store, error) {
|
||||
if tp, ok := ss.settings[name]; ok {
|
||||
return store{name, tp, ss.conf.md}, nil
|
||||
}
|
||||
return nil, ErrMissingStore
|
||||
}
|
||||
|
||||
type store struct {
|
||||
name string
|
||||
settings toml.Primitive
|
||||
md toml.MetaData
|
||||
}
|
||||
|
||||
var _ Store = store{}
|
||||
|
||||
func (s store) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
func (s store) Map() (m map[string]any, err error) {
|
||||
err = s.Decode(&m)
|
||||
return
|
||||
}
|
||||
|
||||
func (s store) Decode(v any) error {
|
||||
return s.md.PrimitiveDecode(s.settings, v)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,20 +7,20 @@ import (
|
|||
)
|
||||
|
||||
func TestEnvDefaultsToDev(t *testing.T) {
|
||||
c := Config{}
|
||||
assert.Equal(t, Dev, c.Environment())
|
||||
c := config{}
|
||||
assert.Equal(t, Dev, c.Env())
|
||||
}
|
||||
|
||||
func TestInvalidEnvReturnsDev(t *testing.T) {
|
||||
c := Config{Env: Env("foobar")}
|
||||
assert.Equal(t, Dev, c.Environment())
|
||||
c := config{env: Env("foobar")}
|
||||
assert.Equal(t, Dev, c.Env())
|
||||
}
|
||||
|
||||
func TestValidEnvReturnsCorrect(t *testing.T) {
|
||||
for _, e := range Envs {
|
||||
t.Run(string(e), func(t *testing.T) {
|
||||
c := Config{Env: e}
|
||||
assert.Equal(t, e, c.Environment())
|
||||
c := config{env: e}
|
||||
assert.Equal(t, e, c.Env())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
17
config/interface.go
Normal file
17
config/interface.go
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package config
|
||||
|
||||
//go:generate mockgen -source interface.go -destination ../internal/testmocks/config/config_mock.go -package config -typed
|
||||
|
||||
type Config interface {
|
||||
Name() string
|
||||
Env() Env
|
||||
BaseURL() string
|
||||
StoreName() string
|
||||
Store(name string) (Store, error)
|
||||
}
|
||||
|
||||
type Store interface {
|
||||
Name() string
|
||||
Decode(v any) error
|
||||
Map() (map[string]any, error)
|
||||
}
|
||||
|
|
@ -2,7 +2,39 @@ package config
|
|||
|
||||
import "github.com/BurntSushi/toml"
|
||||
|
||||
func LoadFromToml(path string) (c Config, err error) {
|
||||
_, err = toml.DecodeFile(path, &c)
|
||||
return
|
||||
type confToml struct {
|
||||
Name string
|
||||
Env Env
|
||||
BaseURL string `toml:"base_url"`
|
||||
Stores storeSettings `toml:"stores"`
|
||||
}
|
||||
|
||||
type storeSettings struct {
|
||||
Store string
|
||||
Settings map[string]toml.Primitive
|
||||
}
|
||||
|
||||
func LoadFromToml(path string) (Config, error) {
|
||||
var c confToml
|
||||
md, err := toml.DecodeFile(path, &c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conf := config{
|
||||
name: c.Name,
|
||||
env: c.Env,
|
||||
baseURL: c.BaseURL,
|
||||
md: md,
|
||||
}
|
||||
|
||||
st := stores{
|
||||
store: c.Stores.Store,
|
||||
settings: c.Stores.Settings,
|
||||
conf: &conf,
|
||||
}
|
||||
|
||||
conf.stores = st
|
||||
|
||||
return conf, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,18 +13,33 @@ func TestLoadTomlMissing(t *testing.T) {
|
|||
assert.Error(t, e)
|
||||
}
|
||||
|
||||
type sqlSett struct {
|
||||
Path string
|
||||
Num int
|
||||
}
|
||||
|
||||
func TestLoadTomlGood(t *testing.T) {
|
||||
tmp, _ := os.CreateTemp("", "*.toml")
|
||||
defer os.Remove(tmp.Name())
|
||||
defer tmp.Close()
|
||||
fmt.Fprintln(tmp, `name = "Cool"`)
|
||||
fmt.Fprintln(tmp, "[conn]")
|
||||
fmt.Fprintln(tmp, "[stores]")
|
||||
fmt.Fprintln(tmp, `store = "sqlite"`)
|
||||
fmt.Fprintln(tmp, "[conn.settings]")
|
||||
fmt.Fprintln(tmp, "[stores.settings.sqlite]")
|
||||
fmt.Fprintln(tmp, `path = "tmp"`)
|
||||
fmt.Fprintln(tmp, `num = 42`)
|
||||
c, e := LoadFromToml(tmp.Name())
|
||||
assert.NoError(t, e)
|
||||
assert.Equal(t, "Cool", c.Name)
|
||||
assert.Equal(t, "sqlite", c.Conn.Store)
|
||||
assert.Equal(t, int64(42), c.Conn.Settings["num"])
|
||||
assert.Equal(t, "Cool", c.Name())
|
||||
|
||||
st, err := c.Store("")
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "sqlite", st.Name())
|
||||
|
||||
var sett sqlSett
|
||||
err = st.Decode(&sett)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 42, sett.Num)
|
||||
assert.Equal(t, "tmp", sett.Path)
|
||||
}
|
||||
|
|
|
|||
Reference in a new issue