forked from goccy/go-zetasqlite
-
Notifications
You must be signed in to change notification settings - Fork 1
/
decoder.go
123 lines (119 loc) · 3.04 KB
/
decoder.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package internal
import (
"encoding/base64"
"fmt"
"math/big"
"strconv"
"github.com/goccy/go-json"
)
func DecodeValue(v interface{}) (Value, error) {
if isNullValue(v) {
return nil, nil
}
switch vv := v.(type) {
case int64:
return IntValue(vv), nil
case float64:
return FloatValue(vv), nil
case bool:
return BoolValue(vv), nil
}
s, ok := v.(string)
if !ok {
return nil, fmt.Errorf("unexpected value type: %T", v)
}
decoded, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, fmt.Errorf("failed to decode value: %w", err)
}
var layout ValueLayout
if err := json.Unmarshal(decoded, &layout); err != nil {
return nil, fmt.Errorf("failed to get value layout: %w", err)
}
return decodeFromValueLayout(&layout)
}
func decodeFromValueLayout(layout *ValueLayout) (Value, error) {
switch layout.Header {
case StringValueType:
return StringValue(layout.Body), nil
case BytesValueType:
decoded, err := base64.StdEncoding.DecodeString(layout.Body)
if err != nil {
return nil, err
}
return BytesValue(decoded), nil
case NumericValueType:
r := new(big.Rat)
r.SetString(layout.Body)
return &NumericValue{Rat: r}, nil
case BigNumericValueType:
r := new(big.Rat)
r.SetString(layout.Body)
return &NumericValue{Rat: r, isBigNumeric: true}, nil
case DateValueType:
t, err := parseDate(layout.Body)
if err != nil {
return nil, err
}
return DateValue(t), nil
case DatetimeValueType:
t, err := parseDatetime(layout.Body)
if err != nil {
return nil, err
}
return DatetimeValue(t), nil
case TimeValueType:
t, err := parseTime(layout.Body)
if err != nil {
return nil, err
}
return TimeValue(t), nil
case TimestampValueType:
unixnano, err := strconv.ParseInt(layout.Body, 10, 64)
if err != nil {
return nil, fmt.Errorf("failed to parse unixnano for timestamp value %s: %w", layout.Body, err)
}
return TimestampValue(timeFromUnixNano(unixnano)), nil
case IntervalValueType:
return parseInterval(layout.Body)
case JsonValueType:
return JsonValue(layout.Body), nil
case ArrayValueType:
var arr []interface{}
if err := json.Unmarshal([]byte(layout.Body), &arr); err != nil {
return nil, fmt.Errorf("failed to decode array body: %w", err)
}
ret := &ArrayValue{
values: make([]Value, 0, len(arr)),
}
for _, elem := range arr {
value, err := DecodeValue(elem)
if err != nil {
return nil, err
}
ret.values = append(ret.values, value)
}
return ret, nil
case StructValueType:
var structLayout StructValueLayout
if err := json.Unmarshal([]byte(layout.Body), &structLayout); err != nil {
return nil, err
}
m := map[string]Value{}
values := make([]Value, 0, len(structLayout.Values))
for i, data := range structLayout.Values {
value, err := DecodeValue(data)
if err != nil {
return nil, err
}
m[structLayout.Keys[i]] = value
values = append(values, value)
}
ret := &StructValue{}
ret.keys = structLayout.Keys
ret.values = values
ret.m = m
return ret, nil
}
return nil, fmt.Errorf("unexpected value header: %s", layout.Header)
}