-
Notifications
You must be signed in to change notification settings - Fork 86
/
array.go
241 lines (203 loc) · 5.06 KB
/
array.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
package document
import (
"github.com/buger/jsonparser"
"github.com/genjidb/genji/internal/errors"
"github.com/genjidb/genji/types"
)
// ErrValueNotFound must be returned by Array implementations, when calling the GetByIndex method and
// the index wasn't found in the array.
var (
ErrValueNotFound = errors.New("value not found")
)
// ArrayLength returns the length of an array.
func ArrayLength(a types.Array) (int, error) {
if vb, ok := a.(*ValueBuffer); ok {
return len(vb.Values), nil
}
var len int
err := a.Iterate(func(_ int, _ types.Value) error {
len++
return nil
})
return len, err
}
var errStop = errors.New("stop")
// ArrayContains iterates over a and returns whether v is equal to one of its values.
func ArrayContains(a types.Array, v types.Value) (bool, error) {
var found bool
err := a.Iterate(func(i int, vv types.Value) error {
ok, err := types.IsEqual(vv, v)
if err != nil {
return err
}
if ok {
found = true
return errStop
}
return nil
})
if err != nil && !errors.Is(err, errStop) {
return false, err
}
return found, nil
}
// ValueBuffer is an array that holds values in memory.
type ValueBuffer struct {
Values []types.Value
err error
}
// NewValueBuffer creates a buffer of values.
func NewValueBuffer(values ...types.Value) *ValueBuffer {
return &ValueBuffer{Values: values}
}
// Iterate over all the values of the buffer. It implements the Array interface.
func (vb *ValueBuffer) Iterate(fn func(i int, value types.Value) error) error {
for i, v := range vb.Values {
err := fn(i, v)
if err != nil {
return err
}
}
return nil
}
// GetByIndex returns a value set at the given index. If the index is out of range it returns an error.
func (vb *ValueBuffer) GetByIndex(i int) (types.Value, error) {
if i >= len(vb.Values) {
return nil, ErrFieldNotFound
}
return vb.Values[i], nil
}
// Len returns the length the of array
func (vb *ValueBuffer) Len() int {
if vb == nil {
return 0
}
return len(vb.Values)
}
// Append a value to the buffer and return a new buffer.
func (vb *ValueBuffer) Append(v types.Value) *ValueBuffer {
vb.Values = append(vb.Values, v)
return vb
}
// ScanArray copies all the values of a to the buffer.
func (vb *ValueBuffer) ScanArray(a types.Array) error {
return a.Iterate(func(i int, v types.Value) error {
vb.Values = append(vb.Values, v)
return nil
})
}
// Copy deep copies all the values from the given array.
// If a value is a document or an array, it will be stored as a *FieldBuffer or *ValueBuffer respectively.
func (vb *ValueBuffer) Copy(a types.Array) error {
err := vb.ScanArray(a)
if err != nil {
return err
}
if len(vb.Values) == 0 {
return nil
}
for i, v := range vb.Values {
switch v.Type() {
case types.DocumentValue:
var buf FieldBuffer
err = buf.Copy(v.V().(types.Document))
if err != nil {
return err
}
err = vb.Replace(i, types.NewDocumentValue(&buf))
if err != nil {
return err
}
case types.ArrayValue:
var buf ValueBuffer
err = buf.Copy(v.V().(types.Array))
if err != nil {
return err
}
err = vb.Replace(i, types.NewArrayValue(&buf))
if err != nil {
return err
}
}
}
return nil
}
// Apply a function to all the values of the buffer.
func (vb *ValueBuffer) Apply(fn func(p Path, v types.Value) (types.Value, error)) error {
path := Path{PathFragment{}}
for i, v := range vb.Values {
path[0].ArrayIndex = i
switch v.Type() {
case types.DocumentValue:
buf, ok := v.V().(*FieldBuffer)
if !ok {
buf = NewFieldBuffer()
err := buf.Copy(v.V().(types.Document))
if err != nil {
return err
}
}
err := buf.Apply(func(p Path, v types.Value) (types.Value, error) {
return fn(append(path, p...), v)
})
if err != nil {
return err
}
vb.Values[i] = types.NewDocumentValue(buf)
case types.ArrayValue:
buf, ok := v.V().(*ValueBuffer)
if !ok {
buf = NewValueBuffer()
err := buf.Copy(v.V().(types.Array))
if err != nil {
return err
}
}
err := buf.Apply(func(p Path, v types.Value) (types.Value, error) {
return fn(append(path, p...), v)
})
if err != nil {
return err
}
vb.Values[i] = types.NewArrayValue(buf)
default:
var err error
v, err = fn(path, v)
if err != nil {
return err
}
vb.Values[i] = v
}
}
return nil
}
// Replace the value of the index by v.
func (vb *ValueBuffer) Replace(index int, v types.Value) error {
if len(vb.Values) <= index {
return ErrFieldNotFound
}
vb.Values[index] = v
return nil
}
// MarshalJSON implements the json.Marshaler interface.
func (vb ValueBuffer) MarshalJSON() ([]byte, error) {
return MarshalJSONArray(&vb)
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (vb *ValueBuffer) UnmarshalJSON(data []byte) error {
var err error
_, perr := jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, _ error) {
v, err := parseJSONValue(dataType, value)
if err != nil {
return
}
vb.Values = append(vb.Values, v)
})
if err != nil {
return err
}
if perr != nil {
return perr
}
return nil
}