• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

codenotary / immudb / 9367064922

04 Jun 2024 12:27PM UTC coverage: 89.43% (-0.02%) from 89.451%
9367064922

push

gh-ci

ostafen
Add support for JSON type

Signed-off-by: Stefano Scafiti <stefano.scafiti96@gmail.com>

521 of 575 new or added lines in 14 files covered. (90.61%)

12 existing lines in 5 files now uncovered.

35172 of 39329 relevant lines covered (89.43%)

160547.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.17
/embedded/sql/json_type.go
1
package sql
2

3
import (
4
        "encoding/json"
5
        "fmt"
6
        "strconv"
7
        "strings"
8
)
9

10
const (
11
        JSONTypeNumber = "NUMBER"
12
        JSONTypeBool   = "BOOL"
13
        JSONTypeString = "STRING"
14
        JSONTypeArray  = "ARRAY"
15
        JSONTypeObject = "OBJECT"
16
        JSONTypeNull   = "NULL"
17
)
18

19
type JSON struct {
20
        val interface{}
21
}
22

23
func NewJson(val interface{}) *JSON {
2,153✔
24
        return &JSON{val: val}
2,153✔
25
}
2,153✔
26

27
func (v *JSON) Type() SQLValueType {
1,666✔
28
        return JSONType
1,666✔
29
}
1,666✔
30

31
func (v *JSON) IsNull() bool {
1,609✔
32
        return false
1,609✔
33
}
1,609✔
34

35
func (v *JSON) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
7✔
36
        return JSONType, nil
7✔
37
}
7✔
38

39
func (v *JSON) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
7✔
40
        ok := t == JSONType
7✔
41
        switch t {
7✔
42
        case IntegerType, Float64Type:
3✔
43
                _, isInt := v.val.(int64)
3✔
44
                _, isFloat := v.val.(float64)
3✔
45
                ok = isInt || (isFloat && t == Float64Type)
3✔
46
        case VarcharType:
1✔
47
                _, ok = v.val.(string)
1✔
48
        case BooleanType:
1✔
49
                _, ok = v.val.(bool)
1✔
50
        case AnyType:
1✔
51
                ok = v.val == nil
1✔
52
        }
53

54
        if !ok {
8✔
55
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, JSONType, t)
1✔
56
        }
1✔
57
        return nil
6✔
58
}
59

60
func (v *JSON) substitute(params map[string]interface{}) (ValueExp, error) {
1,101✔
61
        return v, nil
1,101✔
62
}
1,101✔
63

64
func (v *JSON) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
1,101✔
65
        return v, nil
1,101✔
66
}
1,101✔
67

68
func (v *JSON) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
69
        return v
1✔
70
}
1✔
71

72
func (v *JSON) isConstant() bool {
101✔
73
        return true
101✔
74
}
101✔
75

76
func (v *JSON) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
77
        return nil
1✔
78
}
1✔
79

80
func (v *JSON) RawValue() interface{} {
1,056✔
81
        return v.val
1,056✔
82
}
1,056✔
83

84
func (v *JSON) Compare(val TypedValue) (int, error) {
2,427✔
85
        tv, ok := v.castToTypedValue()
2,427✔
86
        if !ok {
2,634✔
87
                return -1, fmt.Errorf("%w: comparison not defined for JSON %s", ErrNotComparableValues, v.primitiveType())
207✔
88
        }
207✔
89

90
        if val.Type() != JSONType {
3,934✔
91
                return tv.Compare(val)
1,714✔
92
        }
1,714✔
93

94
        res, err := val.Compare(tv)
506✔
95
        return -res, err
506✔
96
}
97

98
func (v *JSON) primitiveType() string {
507✔
99
        switch v.val.(type) {
507✔
100
        case int64, float64:
56✔
101
                return JSONTypeNumber
56✔
102
        case string:
28✔
103
                return JSONTypeString
28✔
104
        case bool:
48✔
105
                return JSONTypeBool
48✔
106
        case nil:
63✔
107
                return JSONTypeNull
63✔
108
        case []interface{}:
54✔
109
                return JSONTypeArray
54✔
110
        }
111
        return JSONTypeObject
258✔
112
}
113

114
func (v *JSON) castToTypedValue() (TypedValue, bool) {
2,530✔
115
        var tv TypedValue
2,530✔
116
        switch val := v.val.(type) {
2,530✔
117
        case int64:
2✔
118
                tv = NewInteger(val)
2✔
119
        case string:
1,102✔
120
                tv = NewVarchar(val)
1,102✔
121
        case float64:
1,114✔
122
                tv = NewFloat64(val)
1,114✔
123
        case bool:
103✔
124
                tv = NewBool(val)
103✔
125
        case nil:
2✔
126
                tv = NewNull(JSONType)
2✔
127
        default:
207✔
128
                return nil, false
207✔
129
        }
130
        return tv, true
2,323✔
131
}
132

133
func (v *JSON) String() string {
25✔
134
        data, _ := json.Marshal(v.val)
25✔
135
        return string(data)
25✔
136
}
25✔
137

138
func (v *JSON) lookup(fields []string) TypedValue {
2,226✔
139
        currVal := v.val
2,226✔
140
        for i, field := range fields {
7,824✔
141
                switch cv := currVal.(type) {
5,598✔
142
                case map[string]interface{}:
5,415✔
143
                        v, hasField := cv[field]
5,415✔
144
                        if !hasField || (v == nil && i < len(field)-1) {
5,415✔
NEW
145
                                return NewNull(AnyType)
×
NEW
146
                        }
×
147
                        currVal = v
5,415✔
148

5,415✔
149
                        if currVal == nil {
5,415✔
NEW
150
                                break
×
151
                        }
152
                case []interface{}:
118✔
153
                        idx, err := strconv.ParseInt(field, 10, 64)
118✔
154
                        if err != nil || idx < 0 || idx >= int64(len(cv)) {
136✔
155
                                return NewNull(AnyType)
18✔
156
                        }
18✔
157
                        currVal = cv[idx]
100✔
158
                default:
65✔
159
                        return NewNull(AnyType)
65✔
160
                }
161
        }
162
        return NewJson(currVal)
2,143✔
163
}
164

165
type JSONSelector struct {
166
        *ColSelector
167
        fields []string
168
}
169

170
func (sel *JSONSelector) substitute(params map[string]interface{}) (ValueExp, error) {
400✔
171
        return sel, nil
400✔
172
}
400✔
173

174
func (v *JSONSelector) alias() string {
1,440✔
175
        if v.ColSelector.as != "" {
2,040✔
176
                return v.ColSelector.as
600✔
177
        }
600✔
178
        return v.string()
840✔
179
}
180

181
func (v *JSONSelector) resolve(implicitTable string) (string, string, string) {
725✔
182
        aggFn, table, _ := v.ColSelector.resolve(implicitTable)
725✔
183
        return aggFn, table, v.string()
725✔
184
}
725✔
185

186
func (v *JSONSelector) string() string {
1,565✔
187
        return fmt.Sprintf("%s->%s", v.ColSelector.col, strings.Join(v.fields, "->"))
1,565✔
188
}
1,565✔
189

190
func (sel *JSONSelector) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
2,127✔
191
        val, err := sel.ColSelector.reduce(tx, row, implicitTable)
2,127✔
192
        if err != nil {
2,127✔
NEW
193
                return nil, err
×
NEW
194
        }
×
195

196
        jsonVal, ok := val.(*JSON)
2,127✔
197
        if !ok {
2,128✔
198
                return val, fmt.Errorf("-> operator cannot be applied on column of type %s", val.Type())
1✔
199
        }
1✔
200
        return jsonVal.lookup(sel.fields), nil
2,126✔
201
}
202

203
func (sel *JSONSelector) reduceSelectors(row *Row, implicitTable string) ValueExp {
100✔
204
        val := sel.ColSelector.reduceSelectors(row, implicitTable)
100✔
205

100✔
206
        jsonVal, ok := val.(*JSON)
100✔
207
        if !ok {
100✔
NEW
208
                return sel
×
NEW
209
        }
×
210
        return jsonVal.lookup(sel.fields)
100✔
211
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc