Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.

### Changed

* All top-level `New*Request()` constructors now return values instead of
pointers. All methods on request types use value receivers and return
values, enabling immutable builder-style chaining.
* Renamed value constructors `Make*` to `New*` for naming consistency across
the connector. Affects `crud.Make*Request` (now `crud.New*Request`),
`datetime.MakeDatetime` (now `datetime.NewDatetime`), `decimal.MakeDecimal`
and `decimal.MakeDecimalFromString` (now `decimal.NewDecimal` and
`decimal.NewDecimalFromString`), `decimal.MustMakeDecimal` (now
`decimal.MustNewDecimal`), `arrow.MakeArrow` (now `arrow.NewArrow`), and
`crud.MakeResult` (now `crud.NewResult`).
* Removed intermediate `spaceRequest`, `spaceIndexRequest` types — `space`
and `index` fields are now inlined directly into each request struct.
The same flattening was applied to `crud.spaceRequest`.
* Required Go version is `1.24` now (#456).
* `test_helpers.MockDoer` is now an interface instead of a struct. The
`Requests` field became a method `Requests()`. The `NewMockDoer()`
Expand Down
48 changes: 47 additions & 1 deletion MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,51 @@ TODO
stream, _ := conn.NewStream()
log.Printf("opened stream on %v", conn)
```
* All request types (`PingRequest`, `SelectRequest`, `CallRequest`, etc.) now
use value receivers and constructors return values instead of pointers.
Builder methods return modified copies instead of mutating in place.

**Breaking**: calling a builder method without using its return value silently
discards the change:
```Go
// Before (pointer receivers, mutation in place):
req := NewSelectRequest("space")
req.Index("idx") // mutated req directly
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
req.Index("idx") // mutated req directly
req.Index("idx") // Mutated req directly.

conn.Do(req)

// After (value receivers, must use return value):
req := NewSelectRequest("space")
req = req.Index("idx") // must reassign
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

etc

Suggested change
req = req.Index("idx") // must reassign
req = req.Index("idx") // Must reassign.

conn.Do(req)

// Or chain directly:
conn.Do(NewSelectRequest("space").Index("idx"))
```

The same value-receiver pattern was applied to `arrow.InsertRequest` and
`settings.SetRequest`/`settings.GetRequest`.

In the `box` subpackage, request types (`InfoRequest`, `UserExistsRequest`,
`UserCreateRequest`, `SessionSuRequest`, etc.) no longer embed
`tarantool.CallRequest`. They store it as a private field and implement
their own `Context()` method returning the wrapper type. Usage stays clean:
```Go
req := box.NewUserExistsRequest(username).Context(ctx)
```
* Renamed value constructors from `Make*` to `New*` for naming consistency
across the connector. Previously, the main package used `New*Request` while
the `crud` package and value-type constructors used `Make*`. They now all
use the `New*` prefix.

| Before | After |
|---|---|
| `datetime.MakeDatetime` | `datetime.NewDatetime` |
| `decimal.MakeDecimal` | `decimal.NewDecimal` |
| `decimal.MakeDecimalFromString` | `decimal.NewDecimalFromString` |
| `decimal.MustMakeDecimal` | `decimal.MustNewDecimal` |
| `arrow.MakeArrow` | `arrow.NewArrow` |
| `crud.MakeResult` | `crud.NewResult` |
| `crud.Make*Request` (all of them) | `crud.New*Request` |

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

Expand Down Expand Up @@ -440,12 +485,13 @@ is supported.

Now you need to use objects of the Datetime type instead of pointers to it. A
new constructor `MakeDatetime` returns an object. `NewDatetime` has been
removed.
removed. (`MakeDatetime` was later renamed back to `NewDatetime` in v3.)

### decimal package

Now you need to use objects of the Decimal type instead of pointers to it. A
new constructor `MakeDecimal` returns an object. `NewDecimal` has been removed.
(`MakeDecimal` was later renamed back to `NewDecimal` in v3.)

### multi package

Expand Down
4 changes: 2 additions & 2 deletions arrow/arrow.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ type Arrow struct {
data []byte
}

// MakeArrow returns a new arrow.Arrow object that contains
// NewArrow returns a new arrow.Arrow object that contains
// wrapped a raw arrow data buffer.
func MakeArrow(arrow []byte) (Arrow, error) {
func NewArrow(arrow []byte) (Arrow, error) {
return Arrow{arrow}, nil
}

Expand Down
16 changes: 8 additions & 8 deletions arrow/arrow_gen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func TestSomeOptionalArrow(t *testing.T) {
val, err := MakeArrow([]byte{1, 2, 3})
val, err := NewArrow([]byte{1, 2, 3})
require.NoError(t, err)
opt := SomeOptionalArrow(val)

Expand All @@ -33,7 +33,7 @@ func TestNoneOptionalArrow(t *testing.T) {
}

func TestOptionalArrow_MustGet(t *testing.T) {
val, err := MakeArrow([]byte{1, 2, 3})
val, err := NewArrow([]byte{1, 2, 3})
require.NoError(t, err)
optSome := SomeOptionalArrow(val)
optNone := NoneOptionalArrow()
Expand All @@ -43,7 +43,7 @@ func TestOptionalArrow_MustGet(t *testing.T) {
}

func TestOptionalArrow_Unwrap(t *testing.T) {
val, err := MakeArrow([]byte{1, 2, 3})
val, err := NewArrow([]byte{1, 2, 3})
require.NoError(t, err)
optSome := SomeOptionalArrow(val)
optNone := NoneOptionalArrow()
Expand All @@ -53,9 +53,9 @@ func TestOptionalArrow_Unwrap(t *testing.T) {
}

func TestOptionalArrow_UnwrapOr(t *testing.T) {
val, err := MakeArrow([]byte{1, 2, 3})
val, err := NewArrow([]byte{1, 2, 3})
require.NoError(t, err)
def, err := MakeArrow([]byte{4, 5, 6})
def, err := NewArrow([]byte{4, 5, 6})
require.NoError(t, err)
optSome := SomeOptionalArrow(val)
optNone := NoneOptionalArrow()
Expand All @@ -65,9 +65,9 @@ func TestOptionalArrow_UnwrapOr(t *testing.T) {
}

func TestOptionalArrow_UnwrapOrElse(t *testing.T) {
val, err := MakeArrow([]byte{1, 2, 3})
val, err := NewArrow([]byte{1, 2, 3})
require.NoError(t, err)
def, err := MakeArrow([]byte{4, 5, 6})
def, err := NewArrow([]byte{4, 5, 6})
require.NoError(t, err)
optSome := SomeOptionalArrow(val)
optNone := NoneOptionalArrow()
Expand All @@ -77,7 +77,7 @@ func TestOptionalArrow_UnwrapOrElse(t *testing.T) {
}

func TestOptionalArrow_EncodeDecodeMsgpack_Some(t *testing.T) {
val, err := MakeArrow([]byte{1, 2, 3})
val, err := NewArrow([]byte{1, 2, 3})
require.NoError(t, err)
some := SomeOptionalArrow(val)

Expand Down
2 changes: 1 addition & 1 deletion arrow/arrow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestEncodeArrow(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
enc := msgpack.NewEncoder(buf)

arr, err := arrow.MakeArrow(tt.arr)
arr, err := arrow.NewArrow(tt.arr)
require.NoError(t, err)

err = enc.Encode(arr)
Expand Down
2 changes: 1 addition & 1 deletion arrow/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func Example() {
log.Fatalf("Failed to connect: %s", err)
}

arr, err := arrow.MakeArrow(arrowBinData)
arr, err := arrow.NewArrow(arrowBinData)
if err != nil {
log.Fatalf("Failed prepare Arrow data: %s", err)
}
Expand Down
18 changes: 9 additions & 9 deletions arrow/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@ type InsertRequest struct {
}

// NewInsertRequest returns a new InsertRequest.
func NewInsertRequest(space any, arrow Arrow) *InsertRequest {
return &InsertRequest{
func NewInsertRequest(space any, arrow Arrow) InsertRequest {
return InsertRequest{
space: space,
arrow: arrow,
}
}

// Type returns a IPROTO_INSERT_ARROW type for the request.
func (r *InsertRequest) Type() iproto.Type {
func (r InsertRequest) Type() iproto.Type {
return iproto.IPROTO_INSERT_ARROW
}

// Async returns false to the request return a response.
func (r *InsertRequest) Async() bool {
func (r InsertRequest) Async() bool {
return false
}

// Ctx returns a context of the request.
func (r *InsertRequest) Ctx() context.Context {
func (r InsertRequest) Ctx() context.Context {
return r.ctx
}

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

// Arrow sets the arrow for insertion the insert arrow request.
// Note: default value is nil.
func (r *InsertRequest) Arrow(arrow Arrow) *InsertRequest {
func (r InsertRequest) Arrow(arrow Arrow) InsertRequest {
r.arrow = arrow
return r
}

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

// Response creates a response for the InsertRequest.
func (r *InsertRequest) Response(
func (r InsertRequest) Response(
header tarantool.Header,
body io.Reader,
) (tarantool.Response, error) {
Expand Down
2 changes: 1 addition & 1 deletion arrow/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func TestInsertRequestSetters(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
enc := msgpack.NewEncoder(buf)

arr, err := arrow.MakeArrow([]byte{'a', 'b', 'c'})
arr, err := arrow.NewArrow([]byte{'a', 'b', 'c'})
require.NoError(t, err)

resolver := stubSchemeResolver{validSpace}
Expand Down
2 changes: 1 addition & 1 deletion arrow/tarantool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestInsert_invalid(t *testing.T) {
data, err := hex.DecodeString(a.arrow)
require.NoError(t, err)

arr, err := arrow.MakeArrow(data)
arr, err := arrow.NewArrow(data)
require.NoError(t, err)

req := arrow.NewInsertRequest(space, arr)
Expand Down
17 changes: 12 additions & 5 deletions box/info.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package box

import (
"context"
"fmt"

"github.com/vmihailenco/msgpack/v5"

"github.com/tarantool/go-tarantool/v3"
)

var _ tarantool.Request = (*InfoRequest)(nil)
var _ tarantool.Request = InfoRequest{}

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

// NewInfoRequest returns a new empty info request.
func NewInfoRequest() InfoRequest {
callReq := tarantool.NewCallRequest("box.info")

return InfoRequest{
callReq,
baseCallRequest: baseCallRequest{
call: tarantool.NewCallRequest("box.info"),
},
}
}

// Context sets a passed context to the request.
func (req InfoRequest) Context(ctx context.Context) InfoRequest {
req.call = req.call.Context(ctx)
return req
}
44 changes: 44 additions & 0 deletions box/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package box

import (
"context"
"io"

"github.com/tarantool/go-iproto"
"github.com/vmihailenco/msgpack/v5"

"github.com/tarantool/go-tarantool/v3"
)

// baseCallRequest wraps a tarantool.CallRequest and implements
// the tarantool.Request interface by delegation.
type baseCallRequest struct {
call tarantool.CallRequest
}

// Type returns IPROTO type for the request.
func (req baseCallRequest) Type() iproto.Type {
return req.call.Type()
}

// Body fills an encoder with the request body.
func (req baseCallRequest) Body(res tarantool.SchemaResolver,
enc *msgpack.Encoder) error {
return req.call.Body(res, enc)
}

// Ctx returns a context of the request.
func (req baseCallRequest) Ctx() context.Context {
return req.call.Ctx()
}

// Async returns whether the request expects a response.
func (req baseCallRequest) Async() bool {
return req.call.Async()
}

// Response creates a response for the request.
func (req baseCallRequest) Response(header tarantool.Header,
body io.Reader) (tarantool.Response, error) {
return req.call.Response(header, body)
}
Loading
Loading