-
Notifications
You must be signed in to change notification settings - Fork 10
/
jsonProvider.go
94 lines (74 loc) · 2.01 KB
/
jsonProvider.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package configuration
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"reflect"
"strings"
)
const JSONFileProviderName = `JSONFileProvider`
var ErrFileMustHaveJSONExt = errors.New("file must have .json extension")
// NewJSONFileProvider creates new provider which reads values from JSON files.
func NewJSONFileProvider(fileName string) (fp *FileProvider) {
return &FileProvider{fileName: fileName}
}
type FileProvider struct {
fileName string
fileData any
}
func (fp *FileProvider) Name() string {
return JSONFileProviderName
}
func (fp *FileProvider) Init(_ any) error {
file, err := os.Open(fp.fileName)
if err != nil {
return fmt.Errorf("%s.Init: %w", JSONFileProviderName, err)
}
defer file.Close()
b, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("%s.Init: %w", JSONFileProviderName, err)
}
if !strings.HasSuffix(strings.ToLower(fp.fileName), ".json") {
return ErrFileMustHaveJSONExt
}
if err := json.Unmarshal(b, &fp.fileData); err != nil {
return fmt.Errorf("%s.Init: %w", JSONFileProviderName, err)
}
return nil
}
func (fp *FileProvider) Provide(field reflect.StructField, v reflect.Value) error {
path := field.Tag.Get("file_json")
if len(path) == 0 {
// field doesn't have a proper tag
return fmt.Errorf("%s: key is empty", JSONFileProviderName)
}
valStr, ok := findValStrByPath(fp.fileData, strings.Split(path, "."))
if !ok {
return fmt.Errorf("%s: findValStrByPath returns empty value", JSONFileProviderName)
}
return SetField(field, v, valStr)
}
func findValStrByPath(i any, path []string) (string, bool) {
if len(path) == 0 {
return "", false
}
firstInPath := strings.ToLower(path[0])
currentFieldStr, ok := i.(map[string]any) // unmarshal from JSON
if !ok {
return "", false
}
for k, v := range currentFieldStr {
currentFieldStr[strings.ToLower(k)] = v
}
if len(path) == 1 {
val, ok := currentFieldStr[firstInPath]
if !ok {
return "", false
}
return fmt.Sprint(val), true
}
return findValStrByPath(currentFieldStr[firstInPath], path[1:])
}