forked from linkedin/goavro
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrecordCache.go
89 lines (79 loc) · 2.34 KB
/
recordCache.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
package goavro
import (
"fmt"
"strings"
)
// ErrNotRecord is returned when codepath expecs goavro.Record, but found something else.
type ErrNotRecord struct {
datum interface{}
}
// Error returns a string representation of the ErrNotRecord error.
func (e ErrNotRecord) Error() string {
return fmt.Sprintf("expected to find *goavro.Record, but found %T", e.datum)
}
// RecordCache provides simplified way of getting a value from a nested field, while memoizing
// intermediate results in a cache for future lookups.
type RecordCache struct {
db map[string]interface{}
top *Record
delim byte
}
// NewRecordCache returns a new RecordCache structure used to get values from nested fields.
//
// func example(codec Codec, someReader io.Reader) (string, error) {
// decoded, err := codec.Decode(someReader)
// record, ok := decoded.(*Record)
// if !ok {
// return "", ErrNotRecord{decoded}
// }
//
// rc, err := NewRecordCache(record, '/')
// if err != nil {
// return "", err
// }
// account, err := rc.Get("com.example.user/com.example.account")
// if err != nil {
// return "", err
// }
// s, ok := account.(string)
// if !ok {
// return "", fmt.Errorf("expected: string; actual: %T", account)
// }
// return s, nil
// }
func NewRecordCache(record *Record, delim byte) (*RecordCache, error) {
return &RecordCache{delim: delim, db: make(map[string]interface{}), top: record}, nil
}
// Get splits the specified name by the stored delimiter, and attempts to retrieve the nested value
// corresponding to the nested fields.
func (rc *RecordCache) Get(name string) (interface{}, error) {
if val, ok := rc.db[name]; ok {
return val, nil
}
var err error
var val interface{}
var parent interface{} = rc.top
var parentName, childName string
if index := strings.LastIndexByte(name, rc.delim); index >= 0 {
parentName, childName = name[:index], name[index+1:]
parent, err = rc.Get(parentName)
if err != nil {
return nil, err
}
rc.db[parentName] = parent
if _, ok := parent.(*Record); !ok {
return nil, ErrNotRecord{datum: parent}
}
name = childName
}
val, err = parent.(*Record).GetQualified(name)
if err != nil {
if nerr, ok := err.(ErrNoSuchField); ok {
nerr.path = parentName
return nil, nerr
}
return nil, err
}
rc.db[name] = val
return val, nil
}