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

tarantool / go-tarantool / 19860973475

02 Dec 2025 01:52PM UTC coverage: 74.666% (-0.3%) from 74.994%
19860973475

Pull #508

github

laines-it
api: replaced Future.done with a sync.Cond

This commit reduces allocations.

Future.done allocation replaced with
- Future.cond (*sync.Cond)
- Future.finished (atomic.Bool)

Other code use Future.isDone() instead (Future.done == nil) check.

Added Future.finish() marks Future as done.
Future.WaitChan() now creates channel on demand.

Closes #496
Pull Request #508: api: replaced Future.done with a sync.Cond

33 of 53 new or added lines in 2 files covered. (62.26%)

153 existing lines in 3 files now uncovered.

2965 of 3971 relevant lines covered (74.67%)

10327.27 hits per line

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

74.37
/request.go
1
package tarantool
2

3
import (
4
        "context"
5
        "errors"
6
        "fmt"
7
        "io"
8
        "reflect"
9
        "strings"
10
        "sync"
11

12
        "github.com/tarantool/go-iproto"
13
        "github.com/vmihailenco/msgpack/v5"
14
)
15

16
type spaceEncoder struct {
17
        Id   uint32
18
        Name string
19
        IsId bool
20
}
21

22
func newSpaceEncoder(res SchemaResolver, spaceInfo interface{}) (spaceEncoder, error) {
877✔
23
        if res.NamesUseSupported() {
1,728✔
24
                if spaceName, ok := spaceInfo.(string); ok {
1,001✔
25
                        return spaceEncoder{
150✔
26
                                Id:   0,
150✔
27
                                Name: spaceName,
150✔
28
                                IsId: false,
150✔
29
                        }, nil
150✔
30
                }
150✔
31
        }
32

33
        spaceId, err := res.ResolveSpace(spaceInfo)
727✔
34
        return spaceEncoder{
727✔
35
                Id:   spaceId,
727✔
36
                IsId: true,
727✔
37
        }, err
727✔
38
}
39

40
func (e spaceEncoder) Encode(enc *msgpack.Encoder) error {
864✔
41
        if e.IsId {
1,578✔
42
                if err := enc.EncodeUint(uint64(iproto.IPROTO_SPACE_ID)); err != nil {
714✔
43
                        return err
×
44
                }
×
45
                return enc.EncodeUint(uint64(e.Id))
714✔
46
        }
47
        if err := enc.EncodeUint(uint64(iproto.IPROTO_SPACE_NAME)); err != nil {
150✔
48
                return err
×
49
        }
×
50
        return enc.EncodeString(e.Name)
150✔
51
}
52

53
type indexEncoder struct {
54
        Id   uint32
55
        Name string
56
        IsId bool
57
}
58

59
func newIndexEncoder(res SchemaResolver, indexInfo interface{},
60
        spaceNo uint32) (indexEncoder, error) {
727✔
61
        if res.NamesUseSupported() {
1,444✔
62
                if indexName, ok := indexInfo.(string); ok {
746✔
63
                        return indexEncoder{
29✔
64
                                Name: indexName,
29✔
65
                                IsId: false,
29✔
66
                        }, nil
29✔
67
                }
29✔
68
        }
69

70
        indexId, err := res.ResolveIndex(indexInfo, spaceNo)
698✔
71
        return indexEncoder{
698✔
72
                Id:   indexId,
698✔
73
                IsId: true,
698✔
74
        }, err
698✔
75
}
76

77
func (e indexEncoder) Encode(enc *msgpack.Encoder) error {
724✔
78
        if e.IsId {
1,419✔
79
                if err := enc.EncodeUint(uint64(iproto.IPROTO_INDEX_ID)); err != nil {
695✔
80
                        return err
×
81
                }
×
82
                return enc.EncodeUint(uint64(e.Id))
695✔
83
        }
84
        if err := enc.EncodeUint(uint64(iproto.IPROTO_INDEX_NAME)); err != nil {
29✔
85
                return err
×
86
        }
×
87
        return enc.EncodeString(e.Name)
29✔
88
}
89

90
func fillSearch(enc *msgpack.Encoder, spaceEnc spaceEncoder, indexEnc indexEncoder,
91
        key interface{}) error {
724✔
92
        if err := spaceEnc.Encode(enc); err != nil {
724✔
93
                return err
×
94
        }
×
95

96
        if err := indexEnc.Encode(enc); err != nil {
724✔
97
                return err
×
98
        }
×
99

100
        if err := enc.EncodeUint(uint64(iproto.IPROTO_KEY)); err != nil {
724✔
101
                return err
×
102
        }
×
103
        return enc.Encode(key)
724✔
104
}
105

106
// KeyValueBind is a type for encoding named SQL parameters
107
type KeyValueBind struct {
108
        Key   string
109
        Value interface{}
110
}
111

112
//
113
// private
114
//
115

116
// this map is needed for caching names of struct fields in lower case
117
// to avoid extra allocations in heap by calling strings.ToLower()
118
var lowerCaseNames sync.Map
119

120
func encodeSQLBind(enc *msgpack.Encoder, from interface{}) error {
29✔
121
        // internal function for encoding single map in msgpack
29✔
122
        encodeKeyInterface := func(key string, val interface{}) error {
38✔
123
                if err := enc.EncodeMapLen(1); err != nil {
9✔
UNCOV
124
                        return err
×
UNCOV
125
                }
×
126
                if err := enc.EncodeString(":" + key); err != nil {
9✔
UNCOV
127
                        return err
×
UNCOV
128
                }
×
129
                if err := enc.Encode(val); err != nil {
9✔
UNCOV
130
                        return err
×
UNCOV
131
                }
×
132
                return nil
9✔
133
        }
134

135
        encodeKeyValue := func(key string, val reflect.Value) error {
31✔
136
                if err := enc.EncodeMapLen(1); err != nil {
2✔
UNCOV
137
                        return err
×
UNCOV
138
                }
×
139
                if err := enc.EncodeString(":" + key); err != nil {
2✔
140
                        return err
×
UNCOV
141
                }
×
142
                if err := enc.EncodeValue(val); err != nil {
2✔
143
                        return err
×
144
                }
×
145
                return nil
2✔
146
        }
147

148
        encodeNamedFromMap := func(mp map[string]interface{}) error {
31✔
149
                if err := enc.EncodeArrayLen(len(mp)); err != nil {
2✔
UNCOV
150
                        return err
×
151
                }
×
152
                for k, v := range mp {
6✔
153
                        if err := encodeKeyInterface(k, v); err != nil {
4✔
UNCOV
154
                                return err
×
155
                        }
×
156
                }
157
                return nil
2✔
158
        }
159

160
        encodeNamedFromStruct := func(val reflect.Value) error {
30✔
161
                if err := enc.EncodeArrayLen(val.NumField()); err != nil {
1✔
UNCOV
162
                        return err
×
163
                }
×
164
                cached, ok := lowerCaseNames.Load(val.Type())
1✔
165
                if !ok {
2✔
166
                        fields := make([]string, val.NumField())
1✔
167
                        for i := 0; i < val.NumField(); i++ {
3✔
168
                                key := val.Type().Field(i).Name
2✔
169
                                fields[i] = strings.ToLower(key)
2✔
170
                                v := val.Field(i)
2✔
171
                                if err := encodeKeyValue(fields[i], v); err != nil {
2✔
172
                                        return err
×
173
                                }
×
174
                        }
175
                        lowerCaseNames.Store(val.Type(), fields)
1✔
176
                        return nil
1✔
177
                }
178

179
                fields := cached.([]string)
×
180
                for i := 0; i < val.NumField(); i++ {
×
UNCOV
181
                        k := fields[i]
×
UNCOV
182
                        v := val.Field(i)
×
183
                        if err := encodeKeyValue(k, v); err != nil {
×
184
                                return err
×
UNCOV
185
                        }
×
186
                }
187
                return nil
×
188
        }
189

190
        encodeSlice := func(from interface{}) error {
54✔
191
                castedSlice, ok := from.([]interface{})
25✔
192
                if !ok {
26✔
193
                        castedKVSlice := from.([]KeyValueBind)
1✔
194
                        t := len(castedKVSlice)
1✔
195
                        if err := enc.EncodeArrayLen(t); err != nil {
1✔
UNCOV
196
                                return err
×
UNCOV
197
                        }
×
198
                        for _, v := range castedKVSlice {
3✔
199
                                if err := encodeKeyInterface(v.Key, v.Value); err != nil {
2✔
UNCOV
200
                                        return err
×
UNCOV
201
                                }
×
202
                        }
203
                        return nil
1✔
204
                }
205

206
                if err := enc.EncodeArrayLen(len(castedSlice)); err != nil {
24✔
UNCOV
207
                        return err
×
UNCOV
208
                }
×
209
                for i := 0; i < len(castedSlice); i++ {
45✔
210
                        if kvb, ok := castedSlice[i].(KeyValueBind); ok {
24✔
211
                                k := kvb.Key
3✔
212
                                v := kvb.Value
3✔
213
                                if err := encodeKeyInterface(k, v); err != nil {
3✔
214
                                        return err
×
215
                                }
×
216
                        } else {
18✔
217
                                if err := enc.Encode(castedSlice[i]); err != nil {
18✔
UNCOV
218
                                        return err
×
UNCOV
219
                                }
×
220
                        }
221
                }
222
                return nil
24✔
223
        }
224

225
        val := reflect.ValueOf(from)
29✔
226
        switch val.Kind() {
29✔
227
        case reflect.Map:
2✔
228
                mp, ok := from.(map[string]interface{})
2✔
229
                if !ok {
2✔
UNCOV
230
                        return errors.New("failed to encode map: wrong format")
×
UNCOV
231
                }
×
232
                if err := encodeNamedFromMap(mp); err != nil {
2✔
UNCOV
233
                        return err
×
UNCOV
234
                }
×
235
        case reflect.Struct:
1✔
236
                if err := encodeNamedFromStruct(val); err != nil {
1✔
UNCOV
237
                        return err
×
UNCOV
238
                }
×
239
        case reflect.Slice, reflect.Array:
25✔
240
                if err := encodeSlice(from); err != nil {
25✔
UNCOV
241
                        return err
×
UNCOV
242
                }
×
243
        }
244
        return nil
29✔
245
}
246

247
// Request is an interface that provides the necessary data to create a request
248
// that will be sent to a tarantool instance.
249
type Request interface {
250
        // Type returns a IPROTO type of the request.
251
        Type() iproto.Type
252
        // Body fills an msgpack.Encoder with a request body.
253
        Body(resolver SchemaResolver, enc *msgpack.Encoder) error
254
        // Ctx returns a context of the request.
255
        Ctx() context.Context
256
        // Async returns true if the request does not expect response.
257
        Async() bool
258
        // Response creates a response for current request type.
259
        Response(header Header, body io.Reader) (Response, error)
260
}
261

262
// ConnectedRequest is an interface that provides the info about a Connection
263
// the request belongs to.
264
type ConnectedRequest interface {
265
        Request
266
        // Conn returns a Connection the request belongs to.
267
        Conn() *Connection
268
}
269

270
type baseRequest struct {
271
        rtype iproto.Type
272
        async bool
273
        ctx   context.Context
274
}
275

276
// Type returns a IPROTO type for the request.
277
func (req *baseRequest) Type() iproto.Type {
2,233✔
278
        return req.rtype
2,233✔
279
}
2,233✔
280

281
// Async returns true if the request does not require a response.
282
func (req *baseRequest) Async() bool {
1,893✔
283
        return req.async
1,893✔
284
}
1,893✔
285

286
// Ctx returns a context of the request.
287
func (req *baseRequest) Ctx() context.Context {
3,806✔
288
        return req.ctx
3,806✔
289
}
3,806✔
290

291
// Response creates a response for the baseRequest.
292
func (req *baseRequest) Response(header Header, body io.Reader) (Response, error) {
1,518✔
293
        return DecodeBaseResponse(header, body)
1,518✔
294
}
1,518✔
295

296
type spaceRequest struct {
297
        baseRequest
298
        space interface{}
299
}
300

301
func (req *spaceRequest) setSpace(space interface{}) {
893✔
302
        req.space = space
893✔
303
}
893✔
304

305
func EncodeSpace(res SchemaResolver, enc *msgpack.Encoder, space interface{}) error {
6✔
306
        spaceEnc, err := newSpaceEncoder(res, space)
6✔
307
        if err != nil {
7✔
308
                return err
1✔
309
        }
1✔
310
        if err := spaceEnc.Encode(enc); err != nil {
5✔
311
                return err
×
UNCOV
312
        }
×
313
        return nil
5✔
314
}
315

316
type spaceIndexRequest struct {
317
        spaceRequest
318
        index interface{}
319
}
320

321
func (req *spaceIndexRequest) setIndex(index interface{}) {
702✔
322
        req.index = index
702✔
323
}
702✔
324

325
// authRequest implements IPROTO_AUTH request.
326
type authRequest struct {
327
        auth       Auth
328
        user, pass string
329
}
330

331
// newChapSha1AuthRequest create a new authRequest with chap-sha1
332
// authentication method.
333
func newChapSha1AuthRequest(user, password, salt string) (authRequest, error) {
327✔
334
        req := authRequest{}
327✔
335
        scr, err := scramble(salt, password)
327✔
336
        if err != nil {
327✔
UNCOV
337
                return req, fmt.Errorf("scrambling failure: %w", err)
×
UNCOV
338
        }
×
339

340
        req.auth = ChapSha1Auth
327✔
341
        req.user = user
327✔
342
        req.pass = string(scr)
327✔
343
        return req, nil
327✔
344
}
345

346
// newPapSha256AuthRequest create a new authRequest with pap-sha256
347
// authentication method.
348
func newPapSha256AuthRequest(user, password string) authRequest {
2✔
349
        return authRequest{
2✔
350
                auth: PapSha256Auth,
2✔
351
                user: user,
2✔
352
                pass: password,
2✔
353
        }
2✔
354
}
2✔
355

356
// Type returns a IPROTO type for the request.
357
func (req authRequest) Type() iproto.Type {
329✔
358
        return iproto.IPROTO_AUTH
329✔
359
}
329✔
360

361
// Async returns true if the request does not require a response.
UNCOV
362
func (req authRequest) Async() bool {
×
UNCOV
363
        return false
×
UNCOV
364
}
×
365

366
// Ctx returns a context of the request.
UNCOV
367
func (req authRequest) Ctx() context.Context {
×
UNCOV
368
        return nil
×
UNCOV
369
}
×
370

371
// Body fills an encoder with the auth request body.
372
func (req authRequest) Body(_ SchemaResolver, enc *msgpack.Encoder) error {
329✔
373
        if err := enc.EncodeMapLen(2); err != nil {
329✔
374
                return err
×
375
        }
×
376

377
        if err := enc.EncodeUint32(uint32(iproto.IPROTO_USER_NAME)); err != nil {
329✔
UNCOV
378
                return err
×
UNCOV
379
        }
×
380

381
        if err := enc.EncodeString(req.user); err != nil {
329✔
UNCOV
382
                return err
×
UNCOV
383
        }
×
384

385
        if err := enc.EncodeUint32(uint32(iproto.IPROTO_TUPLE)); err != nil {
329✔
UNCOV
386
                return err
×
UNCOV
387
        }
×
388

389
        if err := enc.EncodeArrayLen(2); err != nil {
329✔
UNCOV
390
                return err
×
UNCOV
391
        }
×
392

393
        if err := enc.EncodeString(req.auth.String()); err != nil {
329✔
UNCOV
394
                return err
×
UNCOV
395
        }
×
396

397
        if err := enc.EncodeString(req.pass); err != nil {
329✔
UNCOV
398
                return err
×
UNCOV
399
        }
×
400

401
        return nil
329✔
402
}
403

404
// Response creates a response for the authRequest.
405
func (req authRequest) Response(header Header, body io.Reader) (Response, error) {
327✔
406
        return DecodeBaseResponse(header, body)
327✔
407
}
327✔
408

409
// PingRequest helps you to create an execute request object for execution
410
// by a Connection.
411
type PingRequest struct {
412
        baseRequest
413
}
414

415
// NewPingRequest returns a new PingRequest.
416
func NewPingRequest() *PingRequest {
47✔
417
        req := new(PingRequest)
47✔
418
        req.rtype = iproto.IPROTO_PING
47✔
419
        return req
47✔
420
}
47✔
421

422
// Body fills an msgpack.Encoder with the ping request body.
423
func (req *PingRequest) Body(_ SchemaResolver, enc *msgpack.Encoder) error {
38✔
424
        return enc.EncodeMapLen(0)
38✔
425
}
38✔
426

427
// Context sets a passed context to the request.
428
//
429
// Pay attention that when using context with request objects,
430
// the timeout option for Connection does not affect the lifetime
431
// of the request. For those purposes use context.WithTimeout() as
432
// the root context.
433
func (req *PingRequest) Context(ctx context.Context) *PingRequest {
7✔
434
        req.ctx = ctx
7✔
435
        return req
7✔
436
}
7✔
437

438
// SelectRequest allows you to create a select request object for execution
439
// by a Connection.
440
type SelectRequest struct {
441
        spaceIndexRequest
442
        isIteratorSet, fetchPos bool
443
        offset, limit           uint32
444
        iterator                Iter
445
        key, after              interface{}
446
}
447

448
// NewSelectRequest returns a new empty SelectRequest.
449
func NewSelectRequest(space interface{}) *SelectRequest {
677✔
450
        req := new(SelectRequest)
677✔
451
        req.rtype = iproto.IPROTO_SELECT
677✔
452
        req.setSpace(space)
677✔
453
        req.isIteratorSet = false
677✔
454
        req.fetchPos = false
677✔
455
        req.iterator = IterAll
677✔
456
        req.key = []interface{}{}
677✔
457
        req.after = nil
677✔
458
        req.limit = 0xFFFFFFFF
677✔
459
        return req
677✔
460
}
677✔
461

462
// Index sets the index for the select request.
463
// Note: default value is 0.
464
func (req *SelectRequest) Index(index interface{}) *SelectRequest {
662✔
465
        req.setIndex(index)
662✔
466
        return req
662✔
467
}
662✔
468

469
// Offset sets the offset for the select request.
470
// Note: default value is 0.
471
func (req *SelectRequest) Offset(offset uint32) *SelectRequest {
15✔
472
        req.offset = offset
15✔
473
        return req
15✔
474
}
15✔
475

476
// Limit sets the limit for the select request.
477
// Note: default value is 0xFFFFFFFF.
478
func (req *SelectRequest) Limit(limit uint32) *SelectRequest {
649✔
479
        req.limit = limit
649✔
480
        return req
649✔
481
}
649✔
482

483
// Iterator set the iterator for the select request.
484
// Note: default value is IterAll if key is not set or IterEq otherwise.
485
func (req *SelectRequest) Iterator(iterator Iter) *SelectRequest {
34✔
486
        req.iterator = iterator
34✔
487
        req.isIteratorSet = true
34✔
488
        return req
34✔
489
}
34✔
490

491
// Key set the key for the select request.
492
// Note: default value is empty.
493
func (req *SelectRequest) Key(key interface{}) *SelectRequest {
40✔
494
        req.key = key
40✔
495
        if !req.isIteratorSet {
47✔
496
                req.iterator = IterEq
7✔
497
        }
7✔
498
        return req
40✔
499
}
500

501
// FetchPos determines whether to fetch positions of the last tuple. A position
502
// descriptor will be saved in Response.Pos value.
503
//
504
// Note: default value is false.
505
//
506
// Requires Tarantool >= 2.11.
507
// Since 1.11.0
508
func (req *SelectRequest) FetchPos(fetch bool) *SelectRequest {
4✔
509
        req.fetchPos = fetch
4✔
510
        return req
4✔
511
}
4✔
512

513
// After must contain a tuple from which selection must continue or its
514
// position (a value from Response.Pos).
515
//
516
// Note: default value in nil.
517
//
518
// Requires Tarantool >= 2.11.
519
// Since 1.11.0
520
func (req *SelectRequest) After(after interface{}) *SelectRequest {
3✔
521
        req.after = after
3✔
522
        return req
3✔
523
}
3✔
524

525
// Body fills an encoder with the select request body.
526
func (req *SelectRequest) Body(res SchemaResolver, enc *msgpack.Encoder) error {
685✔
527
        spaceEnc, err := newSpaceEncoder(res, req.space)
685✔
528
        if err != nil {
687✔
529
                return err
2✔
530
        }
2✔
531

532
        indexEnc, err := newIndexEncoder(res, req.index, spaceEnc.Id)
683✔
533
        if err != nil {
684✔
534
                return err
1✔
535
        }
1✔
536

537
        mapLen := 6
682✔
538
        if req.fetchPos {
687✔
539
                mapLen++
5✔
540
        }
5✔
541
        if req.after != nil {
685✔
542
                mapLen++
3✔
543
        }
3✔
544

545
        if err := enc.EncodeMapLen(mapLen); err != nil {
682✔
UNCOV
546
                return err
×
UNCOV
547
        }
×
548

549
        if err := enc.EncodeUint(uint64(iproto.IPROTO_ITERATOR)); err != nil {
682✔
UNCOV
550
                return err
×
UNCOV
551
        }
×
552

553
        if err := enc.EncodeUint(uint64(req.iterator)); err != nil {
682✔
UNCOV
554
                return err
×
UNCOV
555
        }
×
556

557
        if err := enc.EncodeUint(uint64(iproto.IPROTO_OFFSET)); err != nil {
682✔
UNCOV
558
                return err
×
UNCOV
559
        }
×
560

561
        if err := enc.EncodeUint(uint64(req.offset)); err != nil {
682✔
UNCOV
562
                return err
×
UNCOV
563
        }
×
564

565
        if err := enc.EncodeUint(uint64(iproto.IPROTO_LIMIT)); err != nil {
682✔
UNCOV
566
                return err
×
UNCOV
567
        }
×
568

569
        if err := enc.EncodeUint(uint64(req.limit)); err != nil {
682✔
UNCOV
570
                return err
×
UNCOV
571
        }
×
572

573
        if err := fillSearch(enc, spaceEnc, indexEnc, req.key); err != nil {
682✔
574
                return err
×
575
        }
×
576

577
        if req.fetchPos {
687✔
578
                if err := enc.EncodeUint(uint64(iproto.IPROTO_FETCH_POSITION)); err != nil {
5✔
579
                        return err
×
UNCOV
580
                }
×
581

582
                if err := enc.EncodeBool(req.fetchPos); err != nil {
5✔
583
                        return err
×
UNCOV
584
                }
×
585
        }
586

587
        if req.after != nil {
685✔
588
                if pos, ok := req.after.([]byte); ok {
4✔
589
                        if err := enc.EncodeUint(uint64(iproto.IPROTO_AFTER_POSITION)); err != nil {
1✔
UNCOV
590
                                return err
×
UNCOV
591
                        }
×
592

593
                        if err := enc.EncodeString(string(pos)); err != nil {
1✔
UNCOV
594
                                return err
×
UNCOV
595
                        }
×
596
                } else {
2✔
597
                        if err := enc.EncodeUint(uint64(iproto.IPROTO_AFTER_TUPLE)); err != nil {
2✔
UNCOV
598
                                return err
×
UNCOV
599
                        }
×
600

601
                        if err := enc.Encode(req.after); err != nil {
2✔
UNCOV
602
                                return err
×
UNCOV
603
                        }
×
604
                }
605
        }
606

607
        return nil
682✔
608
}
609

610
// Context sets a passed context to the request.
611
//
612
// Pay attention that when using context with request objects,
613
// the timeout option for Connection does not affect the lifetime
614
// of the request. For those purposes use context.WithTimeout() as
615
// the root context.
616
func (req *SelectRequest) Context(ctx context.Context) *SelectRequest {
1✔
617
        req.ctx = ctx
1✔
618
        return req
1✔
619
}
1✔
620

621
// Response creates a response for the SelectRequest.
622
func (req *SelectRequest) Response(header Header, body io.Reader) (Response, error) {
668✔
623
        baseResp, err := createBaseResponse(header, body)
668✔
624
        if err != nil {
668✔
UNCOV
625
                return nil, err
×
UNCOV
626
        }
×
627
        return &SelectResponse{baseResponse: baseResp}, nil
668✔
628
}
629

630
// InsertRequest helps you to create an insert request object for execution
631
// by a Connection.
632
type InsertRequest struct {
633
        spaceRequest
634
        tuple interface{}
635
}
636

637
// NewInsertRequest returns a new empty InsertRequest.
638
func NewInsertRequest(space interface{}) *InsertRequest {
39✔
639
        req := new(InsertRequest)
39✔
640
        req.rtype = iproto.IPROTO_INSERT
39✔
641
        req.setSpace(space)
39✔
642
        req.tuple = []interface{}{}
39✔
643
        return req
39✔
644
}
39✔
645

646
// Tuple sets the tuple for insertion the insert request.
647
// Note: default value is nil.
648
func (req *InsertRequest) Tuple(tuple interface{}) *InsertRequest {
31✔
649
        req.tuple = tuple
31✔
650
        return req
31✔
651
}
31✔
652

653
// Body fills an msgpack.Encoder with the insert request body.
654
func (req *InsertRequest) Body(res SchemaResolver, enc *msgpack.Encoder) error {
33✔
655
        spaceEnc, err := newSpaceEncoder(res, req.space)
33✔
656
        if err != nil {
34✔
657
                return err
1✔
658
        }
1✔
659

660
        if err := enc.EncodeMapLen(2); err != nil {
32✔
UNCOV
661
                return err
×
UNCOV
662
        }
×
663

664
        if err := spaceEnc.Encode(enc); err != nil {
32✔
UNCOV
665
                return err
×
UNCOV
666
        }
×
667

668
        if err := enc.EncodeUint(uint64(iproto.IPROTO_TUPLE)); err != nil {
32✔
UNCOV
669
                return err
×
UNCOV
670
        }
×
671

672
        return enc.Encode(req.tuple)
32✔
673
}
674

675
// Context sets a passed context to the request.
676
//
677
// Pay attention that when using context with request objects,
678
// the timeout option for Connection does not affect the lifetime
679
// of the request. For those purposes use context.WithTimeout() as
680
// the root context.
681
func (req *InsertRequest) Context(ctx context.Context) *InsertRequest {
1✔
682
        req.ctx = ctx
1✔
683
        return req
1✔
684
}
1✔
685

686
// ReplaceRequest helps you to create a replace request object for execution
687
// by a Connection.
688
type ReplaceRequest struct {
689
        spaceRequest
690
        tuple interface{}
691
}
692

693
// NewReplaceRequest returns a new empty ReplaceRequest.
694
func NewReplaceRequest(space interface{}) *ReplaceRequest {
98✔
695
        req := new(ReplaceRequest)
98✔
696
        req.rtype = iproto.IPROTO_REPLACE
98✔
697
        req.setSpace(space)
98✔
698
        req.tuple = []interface{}{}
98✔
699
        return req
98✔
700
}
98✔
701

702
// Tuple sets the tuple for replace by the replace request.
703
// Note: default value is nil.
704
func (req *ReplaceRequest) Tuple(tuple interface{}) *ReplaceRequest {
90✔
705
        req.tuple = tuple
90✔
706
        return req
90✔
707
}
90✔
708

709
// Body fills an msgpack.Encoder with the replace request body.
710
func (req *ReplaceRequest) Body(res SchemaResolver, enc *msgpack.Encoder) error {
92✔
711
        spaceEnc, err := newSpaceEncoder(res, req.space)
92✔
712
        if err != nil {
93✔
713
                return err
1✔
714
        }
1✔
715

716
        if err := enc.EncodeMapLen(2); err != nil {
91✔
UNCOV
717
                return err
×
UNCOV
718
        }
×
719

720
        if err := spaceEnc.Encode(enc); err != nil {
91✔
UNCOV
721
                return err
×
UNCOV
722
        }
×
723

724
        if err := enc.EncodeUint(uint64(iproto.IPROTO_TUPLE)); err != nil {
91✔
UNCOV
725
                return err
×
UNCOV
726
        }
×
727

728
        return enc.Encode(req.tuple)
91✔
729
}
730

731
// Context sets a passed context to the request.
732
//
733
// Pay attention that when using context with request objects,
734
// the timeout option for Connection does not affect the lifetime
735
// of the request. For those purposes use context.WithTimeout() as
736
// the root context.
737
func (req *ReplaceRequest) Context(ctx context.Context) *ReplaceRequest {
1✔
738
        req.ctx = ctx
1✔
739
        return req
1✔
740
}
1✔
741

742
// DeleteRequest helps you to create a delete request object for execution
743
// by a Connection.
744
type DeleteRequest struct {
745
        spaceIndexRequest
746
        key interface{}
747
}
748

749
// NewDeleteRequest returns a new empty DeleteRequest.
750
func NewDeleteRequest(space interface{}) *DeleteRequest {
40✔
751
        req := new(DeleteRequest)
40✔
752
        req.rtype = iproto.IPROTO_DELETE
40✔
753
        req.setSpace(space)
40✔
754
        req.key = []interface{}{}
40✔
755
        return req
40✔
756
}
40✔
757

758
// Index sets the index for the delete request.
759
// Note: default value is 0.
760
func (req *DeleteRequest) Index(index interface{}) *DeleteRequest {
30✔
761
        req.setIndex(index)
30✔
762
        return req
30✔
763
}
30✔
764

765
// Key sets the key of tuple for the delete request.
766
// Note: default value is empty.
767
func (req *DeleteRequest) Key(key interface{}) *DeleteRequest {
28✔
768
        req.key = key
28✔
769
        return req
28✔
770
}
28✔
771

772
// Body fills an msgpack.Encoder with the delete request body.
773
func (req *DeleteRequest) Body(res SchemaResolver, enc *msgpack.Encoder) error {
34✔
774
        spaceEnc, err := newSpaceEncoder(res, req.space)
34✔
775
        if err != nil {
36✔
776
                return err
2✔
777
        }
2✔
778

779
        indexEnc, err := newIndexEncoder(res, req.index, spaceEnc.Id)
32✔
780
        if err != nil {
33✔
781
                return err
1✔
782
        }
1✔
783

784
        if err := enc.EncodeMapLen(3); err != nil {
31✔
UNCOV
785
                return err
×
UNCOV
786
        }
×
787

788
        return fillSearch(enc, spaceEnc, indexEnc, req.key)
31✔
789
}
790

791
// Context sets a passed context to the request.
792
//
793
// Pay attention that when using context with request objects,
794
// the timeout option for Connection does not affect the lifetime
795
// of the request. For those purposes use context.WithTimeout() as
796
// the root context.
797
func (req *DeleteRequest) Context(ctx context.Context) *DeleteRequest {
1✔
798
        req.ctx = ctx
1✔
799
        return req
1✔
800
}
1✔
801

802
// UpdateRequest helps you to create an update request object for execution
803
// by a Connection.
804
type UpdateRequest struct {
805
        spaceIndexRequest
806
        key interface{}
807
        ops *Operations
808
}
809

810
// NewUpdateRequest returns a new empty UpdateRequest.
811
func NewUpdateRequest(space interface{}) *UpdateRequest {
20✔
812
        req := new(UpdateRequest)
20✔
813
        req.rtype = iproto.IPROTO_UPDATE
20✔
814
        req.setSpace(space)
20✔
815
        req.key = []interface{}{}
20✔
816
        return req
20✔
817
}
20✔
818

819
// Index sets the index for the update request.
820
// Note: default value is 0.
821
func (req *UpdateRequest) Index(index interface{}) *UpdateRequest {
10✔
822
        req.setIndex(index)
10✔
823
        return req
10✔
824
}
10✔
825

826
// Key sets the key of tuple for the update request.
827
// Note: default value is empty.
828
func (req *UpdateRequest) Key(key interface{}) *UpdateRequest {
8✔
829
        req.key = key
8✔
830
        return req
8✔
831
}
8✔
832

833
// Operations sets operations to be performed on update.
834
// Note: default value is empty.
835
func (req *UpdateRequest) Operations(ops *Operations) *UpdateRequest {
7✔
836
        req.ops = ops
7✔
837
        return req
7✔
838
}
7✔
839

840
// Body fills an msgpack.Encoder with the update request body.
841
func (req *UpdateRequest) Body(res SchemaResolver, enc *msgpack.Encoder) error {
14✔
842
        spaceEnc, err := newSpaceEncoder(res, req.space)
14✔
843
        if err != nil {
16✔
844
                return err
2✔
845
        }
2✔
846

847
        indexEnc, err := newIndexEncoder(res, req.index, spaceEnc.Id)
12✔
848
        if err != nil {
13✔
849
                return err
1✔
850
        }
1✔
851

852
        if err := enc.EncodeMapLen(4); err != nil {
11✔
UNCOV
853
                return err
×
UNCOV
854
        }
×
855

856
        if err := fillSearch(enc, spaceEnc, indexEnc, req.key); err != nil {
11✔
UNCOV
857
                return err
×
UNCOV
858
        }
×
859

860
        if err := enc.EncodeUint(uint64(iproto.IPROTO_TUPLE)); err != nil {
11✔
UNCOV
861
                return err
×
UNCOV
862
        }
×
863

864
        if req.ops == nil {
15✔
865
                return enc.EncodeArrayLen(0)
4✔
866
        } else {
11✔
867
                return enc.Encode(req.ops)
7✔
868
        }
7✔
869
}
870

871
// Context sets a passed context to the request.
872
//
873
// Pay attention that when using context with request objects,
874
// the timeout option for Connection does not affect the lifetime
875
// of the request. For those purposes use context.WithTimeout() as
876
// the root context.
877
func (req *UpdateRequest) Context(ctx context.Context) *UpdateRequest {
1✔
878
        req.ctx = ctx
1✔
879
        return req
1✔
880
}
1✔
881

882
// UpsertRequest helps you to create an upsert request object for execution
883
// by a Connection.
884
type UpsertRequest struct {
885
        spaceRequest
886
        tuple interface{}
887
        ops   *Operations
888
}
889

890
// NewUpsertRequest returns a new empty UpsertRequest.
891
func NewUpsertRequest(space interface{}) *UpsertRequest {
19✔
892
        req := new(UpsertRequest)
19✔
893
        req.rtype = iproto.IPROTO_UPSERT
19✔
894
        req.setSpace(space)
19✔
895
        req.tuple = []interface{}{}
19✔
896
        return req
19✔
897
}
19✔
898

899
// Tuple sets the tuple for insertion or update by the upsert request.
900
// Note: default value is empty.
901
func (req *UpsertRequest) Tuple(tuple interface{}) *UpsertRequest {
10✔
902
        req.tuple = tuple
10✔
903
        return req
10✔
904
}
10✔
905

906
// Operations sets operations to be performed on update case by the upsert request.
907
// Note: default value is empty.
908
func (req *UpsertRequest) Operations(ops *Operations) *UpsertRequest {
9✔
909
        req.ops = ops
9✔
910
        return req
9✔
911
}
9✔
912

913
// Body fills an msgpack.Encoder with the upsert request body.
914
func (req *UpsertRequest) Body(res SchemaResolver, enc *msgpack.Encoder) error {
13✔
915
        spaceEnc, err := newSpaceEncoder(res, req.space)
13✔
916
        if err != nil {
14✔
917
                return err
1✔
918
        }
1✔
919

920
        if err := enc.EncodeMapLen(3); err != nil {
12✔
UNCOV
921
                return err
×
UNCOV
922
        }
×
923

924
        if err := spaceEnc.Encode(enc); err != nil {
12✔
UNCOV
925
                return err
×
UNCOV
926
        }
×
927

928
        if err := enc.EncodeUint(uint64(iproto.IPROTO_TUPLE)); err != nil {
12✔
UNCOV
929
                return err
×
UNCOV
930
        }
×
931

932
        if err := enc.Encode(req.tuple); err != nil {
12✔
UNCOV
933
                return err
×
UNCOV
934
        }
×
935

936
        if err := enc.EncodeUint(uint64(iproto.IPROTO_OPS)); err != nil {
12✔
UNCOV
937
                return err
×
UNCOV
938
        }
×
939

940
        if req.ops == nil {
15✔
941
                return enc.EncodeArrayLen(0)
3✔
942
        } else {
12✔
943
                return enc.Encode(req.ops)
9✔
944
        }
9✔
945
}
946

947
// Context sets a passed context to the request.
948
//
949
// Pay attention that when using context with request objects,
950
// the timeout option for Connection does not affect the lifetime
951
// of the request. For those purposes use context.WithTimeout() as
952
// the root context.
953
func (req *UpsertRequest) Context(ctx context.Context) *UpsertRequest {
1✔
954
        req.ctx = ctx
1✔
955
        return req
1✔
956
}
1✔
957

958
// CallRequest helps you to create a call request object for execution
959
// by a Connection.
960
type CallRequest struct {
961
        baseRequest
962
        function string
963
        args     interface{}
964
}
965

966
// NewCallRequest returns a new empty CallRequest. It uses request code for
967
// Tarantool >= 1.7.
968
func NewCallRequest(function string) *CallRequest {
169✔
969
        req := new(CallRequest)
169✔
970
        req.rtype = iproto.IPROTO_CALL
169✔
971
        req.function = function
169✔
972
        return req
169✔
973
}
169✔
974

975
// Args sets the args for the call request.
976
// Note: default value is empty.
977
func (req *CallRequest) Args(args interface{}) *CallRequest {
60✔
978
        req.args = args
60✔
979
        return req
60✔
980
}
60✔
981

982
// Body fills an encoder with the call request body.
983
func (req *CallRequest) Body(_ SchemaResolver, enc *msgpack.Encoder) error {
145✔
984
        if err := enc.EncodeMapLen(2); err != nil {
145✔
UNCOV
985
                return err
×
UNCOV
986
        }
×
987

988
        if err := enc.EncodeUint(uint64(iproto.IPROTO_FUNCTION_NAME)); err != nil {
145✔
UNCOV
989
                return err
×
UNCOV
990
        }
×
991

992
        if err := enc.EncodeString(req.function); err != nil {
145✔
UNCOV
993
                return err
×
UNCOV
994
        }
×
995

996
        if err := enc.EncodeUint(uint64(iproto.IPROTO_TUPLE)); err != nil {
145✔
UNCOV
997
                return err
×
UNCOV
998
        }
×
999

1000
        if req.args == nil {
253✔
1001
                return enc.EncodeArrayLen(0)
108✔
1002
        } else {
145✔
1003
                return enc.Encode(req.args)
37✔
1004
        }
37✔
1005
}
1006

1007
// Context sets a passed context to the request.
1008
//
1009
// Pay attention that when using context with request objects,
1010
// the timeout option for Connection does not affect the lifetime
1011
// of the request. For those purposes use context.WithTimeout() as
1012
// the root context.
1013
func (req *CallRequest) Context(ctx context.Context) *CallRequest {
4✔
1014
        req.ctx = ctx
4✔
1015
        return req
4✔
1016
}
4✔
1017

1018
// NewCall16Request returns a new empty Call16Request. It uses request code for
1019
// Tarantool 1.6.
1020
// Deprecated since Tarantool 1.7.2.
1021
func NewCall16Request(function string) *CallRequest {
12✔
1022
        req := NewCallRequest(function)
12✔
1023
        req.rtype = iproto.IPROTO_CALL_16
12✔
1024
        return req
12✔
1025
}
12✔
1026

1027
// NewCall17Request returns a new empty CallRequest. It uses request code for
1028
// Tarantool >= 1.7.
1029
func NewCall17Request(function string) *CallRequest {
14✔
1030
        req := NewCallRequest(function)
14✔
1031
        req.rtype = iproto.IPROTO_CALL
14✔
1032
        return req
14✔
1033
}
14✔
1034

1035
// EvalRequest helps you to create an eval request object for execution
1036
// by a Connection.
1037
type EvalRequest struct {
1038
        baseRequest
1039
        expr string
1040
        args interface{}
1041
}
1042

1043
// NewEvalRequest returns a new empty EvalRequest.
1044
func NewEvalRequest(expr string) *EvalRequest {
97✔
1045
        req := new(EvalRequest)
97✔
1046
        req.rtype = iproto.IPROTO_EVAL
97✔
1047
        req.expr = expr
97✔
1048
        req.args = []interface{}{}
97✔
1049
        return req
97✔
1050
}
97✔
1051

1052
// Args sets the args for the eval request.
1053
// Note: default value is empty.
1054
func (req *EvalRequest) Args(args interface{}) *EvalRequest {
88✔
1055
        req.args = args
88✔
1056
        return req
88✔
1057
}
88✔
1058

1059
// Body fills an msgpack.Encoder with the eval request body.
1060
func (req *EvalRequest) Body(_ SchemaResolver, enc *msgpack.Encoder) error {
91✔
1061
        if err := enc.EncodeMapLen(2); err != nil {
91✔
UNCOV
1062
                return err
×
UNCOV
1063
        }
×
1064

1065
        if err := enc.EncodeUint(uint64(iproto.IPROTO_EXPR)); err != nil {
91✔
UNCOV
1066
                return err
×
UNCOV
1067
        }
×
1068

1069
        if err := enc.EncodeString(req.expr); err != nil {
91✔
UNCOV
1070
                return err
×
UNCOV
1071
        }
×
1072

1073
        if err := enc.EncodeUint(uint64(iproto.IPROTO_TUPLE)); err != nil {
91✔
UNCOV
1074
                return err
×
UNCOV
1075
        }
×
1076

1077
        if req.args == nil {
92✔
1078
                return enc.EncodeArrayLen(0)
1✔
1079
        } else {
91✔
1080
                return enc.Encode(req.args)
90✔
1081
        }
90✔
1082
}
1083

1084
// Context sets a passed context to the request.
1085
//
1086
// Pay attention that when using context with request objects,
1087
// the timeout option for Connection does not affect the lifetime
1088
// of the request. For those purposes use context.WithTimeout() as
1089
// the root context.
1090
func (req *EvalRequest) Context(ctx context.Context) *EvalRequest {
1✔
1091
        req.ctx = ctx
1✔
1092
        return req
1✔
1093
}
1✔
1094

1095
// ExecuteRequest helps you to create an execute request object for execution
1096
// by a Connection.
1097
type ExecuteRequest struct {
1098
        baseRequest
1099
        expr string
1100
        args interface{}
1101
}
1102

1103
// NewExecuteRequest returns a new empty ExecuteRequest.
1104
func NewExecuteRequest(expr string) *ExecuteRequest {
33✔
1105
        req := new(ExecuteRequest)
33✔
1106
        req.rtype = iproto.IPROTO_EXECUTE
33✔
1107
        req.expr = expr
33✔
1108
        req.args = []interface{}{}
33✔
1109
        return req
33✔
1110
}
33✔
1111

1112
// Args sets the args for the execute request.
1113
// Note: default value is empty.
1114
func (req *ExecuteRequest) Args(args interface{}) *ExecuteRequest {
20✔
1115
        req.args = args
20✔
1116
        return req
20✔
1117
}
20✔
1118

1119
// Body fills an msgpack.Encoder with the execute request body.
1120
func (req *ExecuteRequest) Body(_ SchemaResolver, enc *msgpack.Encoder) error {
27✔
1121
        if err := enc.EncodeMapLen(2); err != nil {
27✔
UNCOV
1122
                return err
×
UNCOV
1123
        }
×
1124

1125
        if err := enc.EncodeUint(uint64(iproto.IPROTO_SQL_TEXT)); err != nil {
27✔
UNCOV
1126
                return err
×
UNCOV
1127
        }
×
1128

1129
        if err := enc.EncodeString(req.expr); err != nil {
27✔
UNCOV
1130
                return err
×
UNCOV
1131
        }
×
1132

1133
        if err := enc.EncodeUint(uint64(iproto.IPROTO_SQL_BIND)); err != nil {
27✔
UNCOV
1134
                return err
×
UNCOV
1135
        }
×
1136

1137
        return encodeSQLBind(enc, req.args)
27✔
1138
}
1139

1140
// Context sets a passed context to the request.
1141
//
1142
// Pay attention that when using context with request objects,
1143
// the timeout option for Connection does not affect the lifetime
1144
// of the request. For those purposes use context.WithTimeout() as
1145
// the root context.
1146
func (req *ExecuteRequest) Context(ctx context.Context) *ExecuteRequest {
1✔
1147
        req.ctx = ctx
1✔
1148
        return req
1✔
1149
}
1✔
1150

1151
// Response creates a response for the ExecuteRequest.
1152
func (req *ExecuteRequest) Response(header Header, body io.Reader) (Response, error) {
29✔
1153
        baseResp, err := createBaseResponse(header, body)
29✔
1154
        if err != nil {
29✔
UNCOV
1155
                return nil, err
×
UNCOV
1156
        }
×
1157
        return &ExecuteResponse{baseResponse: baseResp}, nil
29✔
1158
}
1159

1160
// WatchOnceRequest synchronously fetches the value currently associated with a
1161
// specified notification key without subscribing to changes.
1162
type WatchOnceRequest struct {
1163
        baseRequest
1164
        key string
1165
}
1166

1167
// NewWatchOnceRequest returns a new watchOnceRequest.
1168
func NewWatchOnceRequest(key string) *WatchOnceRequest {
8✔
1169
        req := new(WatchOnceRequest)
8✔
1170
        req.rtype = iproto.IPROTO_WATCH_ONCE
8✔
1171
        req.key = key
8✔
1172
        return req
8✔
1173
}
8✔
1174

1175
// Body fills an msgpack.Encoder with the watchOnce request body.
1176
func (req *WatchOnceRequest) Body(_ SchemaResolver, enc *msgpack.Encoder) error {
2✔
1177
        if err := enc.EncodeMapLen(1); err != nil {
2✔
UNCOV
1178
                return err
×
UNCOV
1179
        }
×
1180

1181
        if err := enc.EncodeUint(uint64(iproto.IPROTO_EVENT_KEY)); err != nil {
2✔
UNCOV
1182
                return err
×
UNCOV
1183
        }
×
1184

1185
        return enc.EncodeString(req.key)
2✔
1186
}
1187

1188
// Context sets a passed context to the request.
1189
func (req *WatchOnceRequest) Context(ctx context.Context) *WatchOnceRequest {
1✔
1190
        req.ctx = ctx
1✔
1191
        return req
1✔
1192
}
1✔
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