Skip to content

Commit 098ebdd

Browse files
committed
api: support IPROTO_FEATURE_SPACE_AND_INDEX_NAMES
Support `IPROTO_FEATURE_SPACE_AND_INDEX_NAMES` for Tarantool version >= 3.0.0-alpha. It allows to use space and index names in requests instead of their IDs. `ResolveSpaceIndex` function for `SchemaResolver` interface split into two: `ResolveSpace` and `ResolveIndex`. `NamesUseSupported` function added into the interface to get information if usage of space and index names is supported. `Schema` structure no longer implements `SchemaResolver` interface. Part of #338
1 parent 772b21f commit 098ebdd

12 files changed

+661
-239
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
2323
- Support `IPROTO_WATCH_ONCE` request type for Tarantool
2424
version >= 3.0.0-alpha1 (#337)
2525
- Support `yield_every` option for crud select requests (#350)
26+
- Support `IPROTO_FEATURE_SPACE_AND_INDEX_NAMES` for Tarantool
27+
version >= 3.0.0-alpha1 (#338). It allows to use space and index names
28+
in requests instead of their IDs.
2629

2730
### Changed
2831

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,14 @@ and user may cancel it in process.
245245
* `iproto.Feature` type used instead of `ProtocolFeature`.
246246
* `iproto.IPROTO_FEATURE_` constants used instead of local ones.
247247

248+
#### Schema changes
249+
250+
* `ResolveSpaceIndex` function for `SchemaResolver` interface split into two:
251+
`ResolveSpace` and `ResolveIndex`. `NamesUseSupported` function added into the
252+
interface to get information if the usage of space and index names in requests
253+
is supported.
254+
* `Schema` structure no longer implements `SchemaResolver` interface.
255+
248256
## Contributing
249257

250258
See [the contributing guide](CONTRIBUTING.md) for detailed instructions on how

connection.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ type Connection struct {
162162
cond *sync.Cond
163163
// Schema contains schema loaded on connection.
164164
Schema *Schema
165+
// schemaResolver contains a SchemaResolver implementation.
166+
schemaResolver SchemaResolver
165167
// requestId contains the last request ID for requests with nil context.
166168
requestId uint32
167169
// contextRequestId contains the last request ID for requests with context.
@@ -426,6 +428,10 @@ func Connect(ctx context.Context, addr string, opts Opts) (conn *Connection, err
426428
if err = conn.createConnection(ctx); err != nil {
427429
return nil, err
428430
}
431+
conn.schemaResolver = &noSchemaResolver{
432+
isFeatureInSlice(iproto.IPROTO_FEATURE_SPACE_AND_INDEX_NAMES,
433+
conn.serverProtocolInfo.Features),
434+
}
429435

430436
go conn.pinger()
431437
if conn.opts.Timeout > 0 {
@@ -1102,7 +1108,7 @@ func (conn *Connection) putFuture(fut *Future, req Request, streamId uint64) {
11021108
}
11031109
blen := shard.buf.Len()
11041110
reqid := fut.requestId
1105-
if err := pack(&shard.buf, shard.enc, reqid, req, streamId, conn.Schema); err != nil {
1111+
if err := pack(&shard.buf, shard.enc, reqid, req, streamId, conn.schemaResolver); err != nil {
11061112
shard.buf.Trunc(blen)
11071113
shard.bufmut.Unlock()
11081114
if f := conn.fetchFuture(reqid); f == fut {

crud/request_test.go

+4-39
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package crud_test
33
import (
44
"bytes"
55
"context"
6-
"errors"
76
"fmt"
87
"testing"
98

@@ -14,14 +13,7 @@ import (
1413
"github.com/tarantool/go-tarantool/v2/crud"
1514
)
1615

17-
const invalidSpaceMsg = "invalid space"
18-
const invalidIndexMsg = "invalid index"
19-
20-
const invalidSpace = 2
21-
const invalidIndex = 2
2216
const validSpace = "test" // Any valid value != default.
23-
const defaultSpace = 0 // And valid too.
24-
const defaultIndex = 0 // And valid too.
2517

2618
const CrudRequestType = iproto.IPROTO_CALL
2719

@@ -69,38 +61,11 @@ var expectedOpts = map[string]interface{}{
6961
"timeout": timeout,
7062
}
7163

72-
type ValidSchemeResolver struct {
73-
}
74-
75-
func (*ValidSchemeResolver) ResolveSpaceIndex(s, i interface{}) (uint32, uint32, error) {
76-
var spaceNo, indexNo uint32
77-
if s != nil {
78-
spaceNo = uint32(s.(int))
79-
} else {
80-
spaceNo = defaultSpace
81-
}
82-
if i != nil {
83-
indexNo = uint32(i.(int))
84-
} else {
85-
indexNo = defaultIndex
86-
}
87-
if spaceNo == invalidSpace {
88-
return 0, 0, errors.New(invalidSpaceMsg)
89-
}
90-
if indexNo == invalidIndex {
91-
return 0, 0, errors.New(invalidIndexMsg)
92-
}
93-
return spaceNo, indexNo, nil
94-
}
95-
96-
var resolver ValidSchemeResolver
97-
98-
func extractRequestBody(req tarantool.Request,
99-
resolver tarantool.SchemaResolver) ([]byte, error) {
64+
func extractRequestBody(req tarantool.Request) ([]byte, error) {
10065
var reqBuf bytes.Buffer
10166
reqEnc := msgpack.NewEncoder(&reqBuf)
10267

103-
err := req.Body(resolver, reqEnc)
68+
err := req.Body(nil, reqEnc)
10469
if err != nil {
10570
return nil, fmt.Errorf("An unexpected Response.Body() error: %q", err.Error())
10671
}
@@ -111,12 +76,12 @@ func extractRequestBody(req tarantool.Request,
11176
func assertBodyEqual(t testing.TB, reference tarantool.Request, req tarantool.Request) {
11277
t.Helper()
11378

114-
reqBody, err := extractRequestBody(req, &resolver)
79+
reqBody, err := extractRequestBody(req)
11580
if err != nil {
11681
t.Fatalf("An unexpected Response.Body() error: %q", err.Error())
11782
}
11883

119-
refBody, err := extractRequestBody(reference, &resolver)
84+
refBody, err := extractRequestBody(reference)
12085
if err != nil {
12186
t.Fatalf("An unexpected Response.Body() error: %q", err.Error())
12287
}

example_test.go

+88
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,21 @@ func ExampleSelectRequest() {
231231
// response is [{{} 1111 hello world}]
232232
}
233233

234+
func ExampleSelectRequest_spaceAndIndexNames() {
235+
conn := exampleConnect(opts)
236+
defer conn.Close()
237+
238+
req := tarantool.NewSelectRequest(spaceName)
239+
req.Index(indexName)
240+
resp, err := conn.Do(req).Get()
241+
242+
if err != nil {
243+
fmt.Printf("Failed to execute the request: %s\n", err)
244+
} else {
245+
fmt.Println(resp.Data)
246+
}
247+
}
248+
234249
func ExampleInsertRequest() {
235250
conn := exampleConnect(opts)
236251
defer conn.Close()
@@ -273,6 +288,20 @@ func ExampleInsertRequest() {
273288
// Data [[32 test one]]
274289
}
275290

291+
func ExampleInsertRequest_spaceAndIndexNames() {
292+
conn := exampleConnect(opts)
293+
defer conn.Close()
294+
295+
req := tarantool.NewInsertRequest(spaceName)
296+
resp, err := conn.Do(req).Get()
297+
298+
if err != nil {
299+
fmt.Printf("Failed to execute the request: %s\n", err)
300+
} else {
301+
fmt.Println(resp.Data)
302+
}
303+
}
304+
276305
func ExampleDeleteRequest() {
277306
conn := exampleConnect(opts)
278307
defer conn.Close()
@@ -316,6 +345,21 @@ func ExampleDeleteRequest() {
316345
// Data [[36 test one]]
317346
}
318347

348+
func ExampleDeleteRequest_spaceAndIndexNames() {
349+
conn := exampleConnect(opts)
350+
defer conn.Close()
351+
352+
req := tarantool.NewDeleteRequest(spaceName)
353+
req.Index(indexName)
354+
resp, err := conn.Do(req).Get()
355+
356+
if err != nil {
357+
fmt.Printf("Failed to execute the request: %s\n", err)
358+
} else {
359+
fmt.Println(resp.Data)
360+
}
361+
}
362+
319363
func ExampleReplaceRequest() {
320364
conn := exampleConnect(opts)
321365
defer conn.Close()
@@ -375,6 +419,20 @@ func ExampleReplaceRequest() {
375419
// Data [[13 test twelve]]
376420
}
377421

422+
func ExampleReplaceRequest_spaceAndIndexNames() {
423+
conn := exampleConnect(opts)
424+
defer conn.Close()
425+
426+
req := tarantool.NewReplaceRequest(spaceName)
427+
resp, err := conn.Do(req).Get()
428+
429+
if err != nil {
430+
fmt.Printf("Failed to execute the request: %s\n", err)
431+
} else {
432+
fmt.Println(resp.Data)
433+
}
434+
}
435+
378436
func ExampleUpdateRequest() {
379437
conn := exampleConnect(opts)
380438
defer conn.Close()
@@ -411,6 +469,21 @@ func ExampleUpdateRequest() {
411469
// response is []interface {}{[]interface {}{0x457, "hello", "world"}}
412470
}
413471

472+
func ExampleUpdateRequest_spaceAndIndexNames() {
473+
conn := exampleConnect(opts)
474+
defer conn.Close()
475+
476+
req := tarantool.NewUpdateRequest(spaceName)
477+
req.Index(indexName)
478+
resp, err := conn.Do(req).Get()
479+
480+
if err != nil {
481+
fmt.Printf("Failed to execute the request: %s\n", err)
482+
} else {
483+
fmt.Println(resp.Data)
484+
}
485+
}
486+
414487
func ExampleUpsertRequest() {
415488
conn := exampleConnect(opts)
416489
defer conn.Close()
@@ -452,6 +525,20 @@ func ExampleUpsertRequest() {
452525
// response is []interface {}{[]interface {}{0x459, "first", "updated"}}
453526
}
454527

528+
func ExampleUpsertRequest_spaceAndIndexNames() {
529+
conn := exampleConnect(opts)
530+
defer conn.Close()
531+
532+
req := tarantool.NewUpsertRequest(spaceName)
533+
resp, err := conn.Do(req).Get()
534+
535+
if err != nil {
536+
fmt.Printf("Failed to execute the request: %s\n", err)
537+
} else {
538+
fmt.Println(resp.Data)
539+
}
540+
}
541+
455542
func ExampleCallRequest() {
456543
conn := exampleConnect(opts)
457544
defer conn.Close()
@@ -634,6 +721,7 @@ func ExampleProtocolVersion() {
634721
// Connector client protocol feature: IPROTO_FEATURE_ERROR_EXTENSION
635722
// Connector client protocol feature: IPROTO_FEATURE_WATCHERS
636723
// Connector client protocol feature: IPROTO_FEATURE_PAGINATION
724+
// Connector client protocol feature: IPROTO_FEATURE_SPACE_AND_INDEX_NAMES
637725
// Connector client protocol feature: IPROTO_FEATURE_WATCH_ONCE
638726
}
639727

export_test.go

+54-13
Original file line numberDiff line numberDiff line change
@@ -25,39 +25,80 @@ func RefImplPingBody(enc *msgpack.Encoder) error {
2525

2626
// RefImplSelectBody is reference implementation for filling of a select
2727
// request's body.
28-
func RefImplSelectBody(enc *msgpack.Encoder, space, index, offset, limit uint32, iterator Iter,
29-
key, after interface{}, fetchPos bool) error {
30-
return fillSelect(enc, space, index, offset, limit, iterator, key, after, fetchPos)
28+
func RefImplSelectBody(enc *msgpack.Encoder, res SchemaResolver, space, index interface{},
29+
offset, limit uint32, iterator Iter, key, after interface{}, fetchPos bool) error {
30+
spaceEnc, err := newSpaceEncoder(res, space)
31+
if err != nil {
32+
return err
33+
}
34+
indexEnc, err := newIndexEncoder(res, index, spaceEnc.Id)
35+
if err != nil {
36+
return err
37+
}
38+
return fillSelect(enc, spaceEnc, indexEnc, offset, limit, iterator, key, after, fetchPos)
3139
}
3240

3341
// RefImplInsertBody is reference implementation for filling of an insert
3442
// request's body.
35-
func RefImplInsertBody(enc *msgpack.Encoder, space uint32, tuple interface{}) error {
36-
return fillInsert(enc, space, tuple)
43+
func RefImplInsertBody(enc *msgpack.Encoder, res SchemaResolver, space,
44+
tuple interface{}) error {
45+
spaceEnc, err := newSpaceEncoder(res, space)
46+
if err != nil {
47+
return err
48+
}
49+
return fillInsert(enc, spaceEnc, tuple)
3750
}
3851

3952
// RefImplReplaceBody is reference implementation for filling of a replace
4053
// request's body.
41-
func RefImplReplaceBody(enc *msgpack.Encoder, space uint32, tuple interface{}) error {
42-
return fillInsert(enc, space, tuple)
54+
func RefImplReplaceBody(enc *msgpack.Encoder, res SchemaResolver, space,
55+
tuple interface{}) error {
56+
spaceEnc, err := newSpaceEncoder(res, space)
57+
if err != nil {
58+
return err
59+
}
60+
return fillInsert(enc, spaceEnc, tuple)
4361
}
4462

4563
// RefImplDeleteBody is reference implementation for filling of a delete
4664
// request's body.
47-
func RefImplDeleteBody(enc *msgpack.Encoder, space, index uint32, key interface{}) error {
48-
return fillDelete(enc, space, index, key)
65+
func RefImplDeleteBody(enc *msgpack.Encoder, res SchemaResolver, space, index,
66+
key interface{}) error {
67+
spaceEnc, err := newSpaceEncoder(res, space)
68+
if err != nil {
69+
return err
70+
}
71+
indexEnc, err := newIndexEncoder(res, index, spaceEnc.Id)
72+
if err != nil {
73+
return err
74+
}
75+
return fillDelete(enc, spaceEnc, indexEnc, key)
4976
}
5077

5178
// RefImplUpdateBody is reference implementation for filling of an update
5279
// request's body.
53-
func RefImplUpdateBody(enc *msgpack.Encoder, space, index uint32, key, ops interface{}) error {
54-
return fillUpdate(enc, space, index, key, ops)
80+
func RefImplUpdateBody(enc *msgpack.Encoder, res SchemaResolver, space, index,
81+
key, ops interface{}) error {
82+
spaceEnc, err := newSpaceEncoder(res, space)
83+
if err != nil {
84+
return err
85+
}
86+
indexEnc, err := newIndexEncoder(res, index, spaceEnc.Id)
87+
if err != nil {
88+
return err
89+
}
90+
return fillUpdate(enc, spaceEnc, indexEnc, key, ops)
5591
}
5692

5793
// RefImplUpsertBody is reference implementation for filling of an upsert
5894
// request's body.
59-
func RefImplUpsertBody(enc *msgpack.Encoder, space uint32, tuple, ops interface{}) error {
60-
return fillUpsert(enc, space, tuple, ops)
95+
func RefImplUpsertBody(enc *msgpack.Encoder, res SchemaResolver, space,
96+
tuple, ops interface{}) error {
97+
spaceEnc, err := newSpaceEncoder(res, space)
98+
if err != nil {
99+
return err
100+
}
101+
return fillUpsert(enc, spaceEnc, tuple, ops)
61102
}
62103

63104
// RefImplCallBody is reference implementation for filling of a call or call17

protocol.go

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ var clientProtocolInfo ProtocolInfo = ProtocolInfo{
5656
iproto.IPROTO_FEATURE_ERROR_EXTENSION,
5757
iproto.IPROTO_FEATURE_WATCHERS,
5858
iproto.IPROTO_FEATURE_PAGINATION,
59+
iproto.IPROTO_FEATURE_SPACE_AND_INDEX_NAMES,
5960
iproto.IPROTO_FEATURE_WATCH_ONCE,
6061
},
6162
}

0 commit comments

Comments
 (0)