andrey
9 months ago
7 changed files with 210 additions and 1 deletions
@ -0,0 +1,17 @@ |
|||||
|
{ |
||||
|
"app": { |
||||
|
"name": { |
||||
|
"var": [ |
||||
|
"name" |
||||
|
], |
||||
|
"title": "config title", |
||||
|
"timeout": "1m", |
||||
|
"success": true |
||||
|
} |
||||
|
}, |
||||
|
"cfg": { |
||||
|
"duration": 1260000000000, |
||||
|
"enabled": true, |
||||
|
"type":"json" |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
module gitoa.ru/go-4devs/config/provider/json |
||||
|
|
||||
|
go 1.21.5 |
||||
|
|
||||
|
require ( |
||||
|
github.com/tidwall/gjson v1.17.0 |
||||
|
gitoa.ru/go-4devs/config v0.0.1 |
||||
|
) |
||||
|
|
||||
|
require ( |
||||
|
github.com/tidwall/match v1.1.1 // indirect |
||||
|
github.com/tidwall/pretty v1.2.0 // indirect |
||||
|
) |
@ -0,0 +1,10 @@ |
|||||
|
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= |
||||
|
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= |
||||
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= |
||||
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= |
||||
|
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= |
||||
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= |
||||
|
gitoa.ru/go-4devs/config v0.0.0-20240125174937-085589a9383a h1:61iwpn1Ec4yIkBSvSz8knNENJuhj6v2rp6bfw1wkG0E= |
||||
|
gitoa.ru/go-4devs/config v0.0.0-20240125174937-085589a9383a/go.mod h1:3g2bwE2OTDyYwm33KN/Cqc8pEdGlWXnB8Ju3PsYNQr0= |
||||
|
gitoa.ru/go-4devs/config v0.0.1 h1:9KrOO09YbIMO8qL8aVn/G74DurGdOIW5y3O02bays4I= |
||||
|
gitoa.ru/go-4devs/config v0.0.1/go.mod h1:xfEC2Al9xnMLJUuekYs3KhJ5BIzWAseNwkMwbN6/xss= |
@ -0,0 +1,65 @@ |
|||||
|
package json |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"os" |
||||
|
"path/filepath" |
||||
|
"strings" |
||||
|
|
||||
|
"github.com/tidwall/gjson" |
||||
|
"gitoa.ru/go-4devs/config" |
||||
|
"gitoa.ru/go-4devs/config/value" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
Name = "json" |
||||
|
Separator = "." |
||||
|
) |
||||
|
|
||||
|
var _ config.Provider = (*Provider)(nil) |
||||
|
|
||||
|
func New(json []byte, opts ...Option) *Provider { |
||||
|
provider := Provider{ |
||||
|
key: func(s ...string) string { |
||||
|
return strings.Join(s, Separator) |
||||
|
}, |
||||
|
data: json, |
||||
|
} |
||||
|
|
||||
|
for _, opt := range opts { |
||||
|
opt(&provider) |
||||
|
} |
||||
|
|
||||
|
return &provider |
||||
|
} |
||||
|
|
||||
|
func NewFile(path string, opts ...Option) (*Provider, error) { |
||||
|
file, err := os.ReadFile(filepath.Clean(path)) |
||||
|
if err != nil { |
||||
|
return nil, fmt.Errorf("%w: unable to read config file %#q: file not found or unreadable", err, path) |
||||
|
} |
||||
|
|
||||
|
return New(file, opts...), nil |
||||
|
} |
||||
|
|
||||
|
type Option func(*Provider) |
||||
|
|
||||
|
type Provider struct { |
||||
|
data []byte |
||||
|
key func(...string) string |
||||
|
name string |
||||
|
} |
||||
|
|
||||
|
func (p *Provider) Name() string { |
||||
|
return p.name |
||||
|
} |
||||
|
|
||||
|
func (p *Provider) Value(ctx context.Context, path ...string) (config.Value, error) { |
||||
|
key := p.key(path...) |
||||
|
if val := gjson.GetBytes(p.data, key); val.Exists() { |
||||
|
return value.JString(val.String()), nil |
||||
|
} |
||||
|
|
||||
|
return nil, fmt.Errorf("%v:%w", p.Name(), config.ErrValueNotFound) |
||||
|
} |
@ -0,0 +1,55 @@ |
|||||
|
package json_test |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"log" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/config" |
||||
|
"gitoa.ru/go-4devs/config/provider/json" |
||||
|
"gitoa.ru/go-4devs/config/test" |
||||
|
) |
||||
|
|
||||
|
func ExampleClient_Value() { |
||||
|
ctx := context.Background() |
||||
|
|
||||
|
// read json config
|
||||
|
jsonConfig, jerr := fixture.ReadFile("fixture/config.json") |
||||
|
if jerr != nil { |
||||
|
log.Printf("failed load file:%v", jerr) |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
config, err := config.New( |
||||
|
json.New(jsonConfig), |
||||
|
) |
||||
|
if err != nil { |
||||
|
log.Print(err) |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
title, err := config.Value(ctx, "app.name.title") |
||||
|
if err != nil { |
||||
|
log.Print("app.name.title", err) |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
cfgValue, err := config.Value(ctx, "cfg") |
||||
|
if err != nil { |
||||
|
log.Print("cfg ", err) |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
cfg := test.Config{} |
||||
|
_ = cfgValue.Unmarshal(&cfg) |
||||
|
|
||||
|
fmt.Printf("title from json: %v\n", title.String()) |
||||
|
fmt.Printf("struct from json: %+v\n", cfg) |
||||
|
// Output:
|
||||
|
// title from json: config title
|
||||
|
// struct from json: {Duration:21m0s Enabled:true}
|
||||
|
} |
@ -0,0 +1,33 @@ |
|||||
|
package json_test |
||||
|
|
||||
|
import ( |
||||
|
"embed" |
||||
|
"testing" |
||||
|
"time" |
||||
|
|
||||
|
"gitoa.ru/go-4devs/config/provider/json" |
||||
|
"gitoa.ru/go-4devs/config/test" |
||||
|
"gitoa.ru/go-4devs/config/test/require" |
||||
|
) |
||||
|
|
||||
|
//go:embed fixture/*
|
||||
|
var fixture embed.FS |
||||
|
|
||||
|
func TestProvider(t *testing.T) { |
||||
|
t.Parallel() |
||||
|
|
||||
|
js, err := fixture.ReadFile("fixture/config.json") |
||||
|
require.NoError(t, err) |
||||
|
|
||||
|
prov := json.New(js) |
||||
|
sl := []string{} |
||||
|
read := []test.Read{ |
||||
|
test.NewRead("config title", "app.name.title"), |
||||
|
test.NewRead(time.Minute, "app.name.timeout"), |
||||
|
test.NewReadUnmarshal(&[]string{"name"}, &sl, "app.name.var"), |
||||
|
test.NewReadConfig("cfg"), |
||||
|
test.NewRead(true, "app", "name", "success"), |
||||
|
} |
||||
|
|
||||
|
test.Run(t, prov, read) |
||||
|
} |
Loading…
Reference in new issue