Skip to content

Commit 0581fc0

Browse files
committed
request: switch all request types to value receivers and value returns
All New*Request()/Make*Request() constructors now return values instead of pointers. All methods on request types use value receivers and return values, enabling immutable builder-style chaining. Removed intermediate spaceRequest, spaceIndexRequest types from the tarantool package and spaceRequest from the crud package — space and index fields are inlined directly into each request struct. Converted all constructors to composite literal style. Applied the same pattern to arrow/ and settings/ packages. In the box/ subpackage, request types no longer embed tarantool.CallRequest. They store it as a private field via baseCallRequest and implement their own Context() method returning the wrapper type.
1 parent 6bef431 commit 0581fc0

36 files changed

Lines changed: 615 additions & 476 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
2626

2727
### Changed
2828

29+
* All top-level `New*Request()` constructors now return values instead of
30+
pointers. All methods on request types use value receivers and return
31+
values, enabling immutable builder-style chaining.
32+
* Removed intermediate `spaceRequest`, `spaceIndexRequest` types — `space`
33+
and `index` fields are now inlined directly into each request struct.
34+
The same flattening was applied to `crud.spaceRequest`.
2935
* Required Go version is `1.24` now (#456).
3036
* `box.New` returns an error instead of panic (#448).
3137
* Now cases of `<-ctx.Done()` returns wrapped error provided by `ctx.Cause()`.

MIGRATION.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,37 @@ TODO
3636
* `ConnectionPool.Close()` returns a single error value, combining multiple errors using errors.Join()
3737
* `Future.Release()` call could be used to free resources allocated for the
3838
`Future` object created by a `Connection` object.
39+
* All request types (`PingRequest`, `SelectRequest`, `CallRequest`, etc.) now
40+
use value receivers and constructors return values instead of pointers.
41+
Builder methods return modified copies instead of mutating in place.
42+
43+
**Breaking**: calling a builder method without using its return value silently
44+
discards the change:
45+
```Go
46+
// Before (pointer receivers, mutation in place):
47+
req := NewSelectRequest("space")
48+
req.Index("idx") // mutated req directly
49+
conn.Do(req)
50+
51+
// After (value receivers, must use return value):
52+
req := NewSelectRequest("space")
53+
req = req.Index("idx") // must reassign
54+
conn.Do(req)
55+
56+
// Or chain directly:
57+
conn.Do(NewSelectRequest("space").Index("idx"))
58+
```
59+
60+
The same value-receiver pattern was applied to `arrow.InsertRequest` and
61+
`settings.SetRequest`/`settings.GetRequest`.
62+
63+
In the `box` subpackage, request types (`InfoRequest`, `UserExistsRequest`,
64+
`UserCreateRequest`, `SessionSuRequest`, etc.) no longer embed
65+
`tarantool.CallRequest`. They store it as a private field and implement
66+
their own `Context()` method returning the wrapper type. Usage stays clean:
67+
```Go
68+
req := box.NewUserExistsRequest(username).Context(ctx)
69+
```
3970

4071
## Migration from v1.x.x to v2.x.x
4172

arrow/request.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,25 @@ type InsertRequest struct {
1919
}
2020

2121
// NewInsertRequest returns a new InsertRequest.
22-
func NewInsertRequest(space interface{}, arrow Arrow) *InsertRequest {
23-
return &InsertRequest{
22+
func NewInsertRequest(space interface{}, arrow Arrow) InsertRequest {
23+
return InsertRequest{
2424
space: space,
2525
arrow: arrow,
2626
}
2727
}
2828

2929
// Type returns a IPROTO_INSERT_ARROW type for the request.
30-
func (r *InsertRequest) Type() iproto.Type {
30+
func (r InsertRequest) Type() iproto.Type {
3131
return iproto.IPROTO_INSERT_ARROW
3232
}
3333

3434
// Async returns false to the request return a response.
35-
func (r *InsertRequest) Async() bool {
35+
func (r InsertRequest) Async() bool {
3636
return false
3737
}
3838

3939
// Ctx returns a context of the request.
40-
func (r *InsertRequest) Ctx() context.Context {
40+
func (r InsertRequest) Ctx() context.Context {
4141
return r.ctx
4242
}
4343

@@ -47,20 +47,20 @@ func (r *InsertRequest) Ctx() context.Context {
4747
// the timeout option for Connection does not affect the lifetime
4848
// of the request. For those purposes use context.WithTimeout() as
4949
// the root context.
50-
func (r *InsertRequest) Context(ctx context.Context) *InsertRequest {
50+
func (r InsertRequest) Context(ctx context.Context) InsertRequest {
5151
r.ctx = ctx
5252
return r
5353
}
5454

5555
// Arrow sets the arrow for insertion the insert arrow request.
5656
// Note: default value is nil.
57-
func (r *InsertRequest) Arrow(arrow Arrow) *InsertRequest {
57+
func (r InsertRequest) Arrow(arrow Arrow) InsertRequest {
5858
r.arrow = arrow
5959
return r
6060
}
6161

6262
// Body fills an msgpack.Encoder with the insert arrow request body.
63-
func (r *InsertRequest) Body(res tarantool.SchemaResolver, enc *msgpack.Encoder) error {
63+
func (r InsertRequest) Body(res tarantool.SchemaResolver, enc *msgpack.Encoder) error {
6464
if err := enc.EncodeMapLen(2); err != nil {
6565
return err
6666
}
@@ -74,7 +74,7 @@ func (r *InsertRequest) Body(res tarantool.SchemaResolver, enc *msgpack.Encoder)
7474
}
7575

7676
// Response creates a response for the InsertRequest.
77-
func (r *InsertRequest) Response(
77+
func (r InsertRequest) Response(
7878
header tarantool.Header,
7979
body io.Reader,
8080
) (tarantool.Response, error) {

box/info.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package box
22

33
import (
4+
"context"
45
"fmt"
56

67
"github.com/vmihailenco/msgpack/v5"
78

89
"github.com/tarantool/go-tarantool/v3"
910
)
1011

11-
var _ tarantool.Request = (*InfoRequest)(nil)
12+
var _ tarantool.Request = InfoRequest{}
1213

1314
// Info represents detailed information about the Tarantool instance.
1415
// It includes version, node ID, read-only status, process ID, cluster information, and more.
@@ -112,14 +113,20 @@ func (ir *InfoResponse) DecodeMsgpack(d *msgpack.Decoder) error {
112113
// InfoRequest represents a request to retrieve information about the Tarantool instance.
113114
// It implements the tarantool.Request interface.
114115
type InfoRequest struct {
115-
*tarantool.CallRequest // Underlying Tarantool call request.
116+
baseCallRequest
116117
}
117118

118119
// NewInfoRequest returns a new empty info request.
119120
func NewInfoRequest() InfoRequest {
120-
callReq := tarantool.NewCallRequest("box.info")
121-
122121
return InfoRequest{
123-
callReq,
122+
baseCallRequest: baseCallRequest{
123+
call: tarantool.NewCallRequest("box.info"),
124+
},
124125
}
125126
}
127+
128+
// Context sets a passed context to the request.
129+
func (req InfoRequest) Context(ctx context.Context) InfoRequest {
130+
req.call = req.call.Context(ctx)
131+
return req
132+
}

box/request.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package box
2+
3+
import (
4+
"context"
5+
"io"
6+
7+
"github.com/tarantool/go-iproto"
8+
"github.com/vmihailenco/msgpack/v5"
9+
10+
"github.com/tarantool/go-tarantool/v3"
11+
)
12+
13+
// baseCallRequest wraps a tarantool.CallRequest and implements
14+
// the tarantool.Request interface by delegation.
15+
type baseCallRequest struct {
16+
call tarantool.CallRequest
17+
}
18+
19+
// Type returns IPROTO type for the request.
20+
func (req baseCallRequest) Type() iproto.Type {
21+
return req.call.Type()
22+
}
23+
24+
// Body fills an encoder with the request body.
25+
func (req baseCallRequest) Body(res tarantool.SchemaResolver,
26+
enc *msgpack.Encoder) error {
27+
return req.call.Body(res, enc)
28+
}
29+
30+
// Ctx returns a context of the request.
31+
func (req baseCallRequest) Ctx() context.Context {
32+
return req.call.Ctx()
33+
}
34+
35+
// Async returns whether the request expects a response.
36+
func (req baseCallRequest) Async() bool {
37+
return req.call.Async()
38+
}
39+
40+
// Response creates a response for the request.
41+
func (req baseCallRequest) Response(header tarantool.Header,
42+
body io.Reader) (tarantool.Response, error) {
43+
return req.call.Response(header, body)
44+
}

0 commit comments

Comments
 (0)