forked from fl00r/go-tarantool-1.6
-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathschema.go
249 lines (204 loc) · 5.9 KB
/
schema.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
242
243
244
245
246
247
248
249
package crud
import (
"context"
"fmt"
"github.com/vmihailenco/msgpack/v5"
"github.com/vmihailenco/msgpack/v5/msgpcode"
"github.com/tarantool/go-tarantool/v2"
)
func msgpackIsMap(code byte) bool {
return code == msgpcode.Map16 || code == msgpcode.Map32 || msgpcode.IsFixedMap(code)
}
// SchemaOpts describes options for `crud.schema` method.
type SchemaOpts struct {
// Timeout is a `vshard.call` timeout and vshard
// master discovery timeout (in seconds).
Timeout OptFloat64
// VshardRouter is cartridge vshard group name or
// vshard router instance.
VshardRouter OptString
// Cached defines whether router should reload storage schema on call.
Cached OptBool
}
// EncodeMsgpack provides custom msgpack encoder.
func (opts SchemaOpts) EncodeMsgpack(enc *msgpack.Encoder) error {
const optsCnt = 3
names := [optsCnt]string{timeoutOptName, vshardRouterOptName,
cachedOptName}
values := [optsCnt]interface{}{}
exists := [optsCnt]bool{}
values[0], exists[0] = opts.Timeout.Get()
values[1], exists[1] = opts.VshardRouter.Get()
values[2], exists[2] = opts.Cached.Get()
return encodeOptions(enc, names[:], values[:], exists[:])
}
// SchemaRequest helps you to create request object to call `crud.schema`
// for execution by a Connection.
type SchemaRequest struct {
baseRequest
space OptString
opts SchemaOpts
}
// MakeSchemaRequest returns a new empty SchemaRequest.
func MakeSchemaRequest() SchemaRequest {
req := SchemaRequest{}
req.impl = newCall("crud.schema")
return req
}
// Space sets the space name for the SchemaRequest request.
// Note: default value is nil.
func (req SchemaRequest) Space(space string) SchemaRequest {
req.space = MakeOptString(space)
return req
}
// Opts sets the options for the SchemaRequest request.
// Note: default value is nil.
func (req SchemaRequest) Opts(opts SchemaOpts) SchemaRequest {
req.opts = opts
return req
}
// Body fills an encoder with the call request body.
func (req SchemaRequest) Body(res tarantool.SchemaResolver, enc *msgpack.Encoder) error {
if value, ok := req.space.Get(); ok {
req.impl = req.impl.Args([]interface{}{value, req.opts})
} else {
req.impl = req.impl.Args([]interface{}{nil, req.opts})
}
return req.impl.Body(res, enc)
}
// Context sets a passed context to CRUD request.
func (req SchemaRequest) Context(ctx context.Context) SchemaRequest {
req.impl = req.impl.Context(ctx)
return req
}
// Schema contains CRUD cluster schema definition.
type Schema map[string]SpaceSchema
// DecodeMsgpack provides custom msgpack decoder.
func (schema *Schema) DecodeMsgpack(d *msgpack.Decoder) error {
var l int
code, err := d.PeekCode()
if err != nil {
return err
}
if msgpackIsArray(code) {
// Process empty schema case.
l, err = d.DecodeArrayLen()
if err != nil {
return err
}
if l != 0 {
return fmt.Errorf("expected map or empty array, got non-empty array")
}
*schema = make(map[string]SpaceSchema, l)
} else if msgpackIsMap(code) {
l, err := d.DecodeMapLen()
if err != nil {
return err
}
*schema = make(map[string]SpaceSchema, l)
for i := 0; i < l; i++ {
key, err := d.DecodeString()
if err != nil {
return err
}
var spaceSchema SpaceSchema
if err := d.Decode(&spaceSchema); err != nil {
return err
}
(*schema)[key] = spaceSchema
}
} else {
return fmt.Errorf("unexpected code=%d decoding map or empty array", code)
}
return nil
}
// SpaceSchema contains a single CRUD space schema definition.
type SpaceSchema struct {
Format []FieldFormat `msgpack:"format"`
Indexes map[uint32]Index `msgpack:"indexes"`
}
// Index contains a CRUD space index definition.
type Index struct {
Id uint32 `msgpack:"id"`
Name string `msgpack:"name"`
Type string `msgpack:"type"`
Unique bool `msgpack:"unique"`
Parts []IndexPart `msgpack:"parts"`
}
// IndexField contains a CRUD space index part definition.
type IndexPart struct {
Fieldno uint32 `msgpack:"fieldno"`
Type string `msgpack:"type"`
ExcludeNull bool `msgpack:"exclude_null"`
IsNullable bool `msgpack:"is_nullable"`
}
// SchemaResult contains a schema request result for all spaces.
type SchemaResult struct {
Value Schema
}
// DecodeMsgpack provides custom msgpack decoder.
func (result *SchemaResult) DecodeMsgpack(d *msgpack.Decoder) error {
arrLen, err := d.DecodeArrayLen()
if err != nil {
return err
}
if arrLen == 0 {
return fmt.Errorf("unexpected empty response array")
}
// DecodeMapLen inside Schema decode processes `nil` as zero length map,
// so in `return nil, err` case we don't miss error info.
// https://github.com/vmihailenco/msgpack/blob/3f7bd806fea698e7a9fe80979aa3512dea0a7368/decode_map.go#L79-L81
if err = d.Decode(&result.Value); err != nil {
return err
}
if arrLen > 1 {
var crudErr *Error = nil
if err := d.Decode(&crudErr); err != nil {
return err
}
if crudErr != nil {
return crudErr
}
}
for i := 2; i < arrLen; i++ {
if err := d.Skip(); err != nil {
return err
}
}
return nil
}
// SchemaResult contains a schema request result for a single space.
type SpaceSchemaResult struct {
Value SpaceSchema
}
// DecodeMsgpack provides custom msgpack decoder.
func (result *SpaceSchemaResult) DecodeMsgpack(d *msgpack.Decoder) error {
arrLen, err := d.DecodeArrayLen()
if err != nil {
return err
}
if arrLen == 0 {
return fmt.Errorf("unexpected empty response array")
}
// DecodeMapLen inside SpaceSchema decode processes `nil` as zero length map,
// so in `return nil, err` case we don't miss error info.
// https://github.com/vmihailenco/msgpack/blob/3f7bd806fea698e7a9fe80979aa3512dea0a7368/decode_map.go#L79-L81
if err = d.Decode(&result.Value); err != nil {
return err
}
if arrLen > 1 {
var crudErr *Error = nil
if err := d.Decode(&crudErr); err != nil {
return err
}
if crudErr != nil {
return crudErr
}
}
for i := 2; i < arrLen; i++ {
if err := d.Skip(); err != nil {
return err
}
}
return nil
}