diff --git a/CHANGELOG.md b/CHANGELOG.md index ea6c49f40..106143d1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release. - Support `fetch_latest_metadata` option for crud requests with metadata (#335) - Support `noreturn` option for data change crud requests (#335) - Support `crud.schema` request (#336) +- Support `IPROTO_WATCH_ONCE` request type for Tarantool version >= 3.0.0 (#337) ### Changed diff --git a/go.mod b/go.mod index 22cb7aee3..25abf59c9 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/shopspring/decimal v1.3.1 github.com/stretchr/testify v1.7.1 - github.com/tarantool/go-iproto v0.1.0 + github.com/tarantool/go-iproto v0.1.1-0.20231023131314-d13758c80c94 github.com/tarantool/go-openssl v0.0.8-0.20231004103608-336ca939d2ca github.com/vmihailenco/msgpack/v5 v5.3.5 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect diff --git a/go.sum b/go.sum index 44d00984f..65ddd71c7 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/tarantool/go-iproto v0.1.0 h1:zHN9AA8LDawT+JBD0/Nxgr/bIsWkkpDzpcMuaNPSIAQ= -github.com/tarantool/go-iproto v0.1.0/go.mod h1:LNCtdyZxojUed8SbOiYHoc3v9NvaZTB7p96hUySMlIo= +github.com/tarantool/go-iproto v0.1.1-0.20231023131314-d13758c80c94 h1:nCx9Otk7HfDllW79Uk7Nc+UcHakrIt5Nf13xfjhSv4s= +github.com/tarantool/go-iproto v0.1.1-0.20231023131314-d13758c80c94/go.mod h1:LNCtdyZxojUed8SbOiYHoc3v9NvaZTB7p96hUySMlIo= github.com/tarantool/go-openssl v0.0.8-0.20231004103608-336ca939d2ca h1:oOrBh73tDDyooIXajfr+0pfnM+89404ClAhJpTTHI7E= github.com/tarantool/go-openssl v0.0.8-0.20231004103608-336ca939d2ca/go.mod h1:M7H4xYSbzqpW/ZRBMyH0eyqQBsnhAMfsYk5mv0yid7A= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= diff --git a/request.go b/request.go index 917c1fb6a..24991307d 100644 --- a/request.go +++ b/request.go @@ -1354,3 +1354,36 @@ func (req *ExecuteRequest) Context(ctx context.Context) *ExecuteRequest { req.ctx = ctx return req } + +// WatchOnceRequest synchronously fetches the value currently associated with a +// specified notification key without subscribing to changes. +type WatchOnceRequest struct { + baseRequest + key string + ctx context.Context +} + +// NewWatchOnceRequest returns a new watchOnceRequest. +func NewWatchOnceRequest(key string) *WatchOnceRequest { + req := new(WatchOnceRequest) + req.rtype = iproto.IPROTO_WATCH_ONCE + req.key = key + return req +} + +// Body fills an msgpack.Encoder with the watchOnce request body. +func (req *WatchOnceRequest) Body(res SchemaResolver, enc *msgpack.Encoder) error { + if err := enc.EncodeMapLen(1); err != nil { + return err + } + if err := enc.EncodeUint(uint64(iproto.IPROTO_EVENT_KEY)); err != nil { + return err + } + return enc.Encode(req.key) +} + +// Context sets a passed context to the request. +func (req *WatchOnceRequest) Context(ctx context.Context) *WatchOnceRequest { + req.ctx = ctx + return req +} diff --git a/request_test.go b/request_test.go index f44b12d52..e258e1ee2 100644 --- a/request_test.go +++ b/request_test.go @@ -196,6 +196,7 @@ func TestRequestsTypes(t *testing.T) { {req: NewRollbackRequest(), rtype: iproto.IPROTO_ROLLBACK}, {req: NewIdRequest(validProtocolInfo), rtype: iproto.IPROTO_ID}, {req: NewBroadcastRequest(validKey), rtype: iproto.IPROTO_CALL}, + {req: NewWatchOnceRequest(validKey), rtype: iproto.IPROTO_WATCH_ONCE}, } for _, test := range tests { @@ -231,6 +232,7 @@ func TestRequestsAsync(t *testing.T) { {req: NewRollbackRequest(), async: false}, {req: NewIdRequest(validProtocolInfo), async: false}, {req: NewBroadcastRequest(validKey), async: false}, + {req: NewWatchOnceRequest(validKey), async: false}, } for _, test := range tests { diff --git a/tarantool_test.go b/tarantool_test.go index bde3060c7..a2badbd01 100644 --- a/tarantool_test.go +++ b/tarantool_test.go @@ -2606,6 +2606,45 @@ func TestConnectionDoSelectRequest(t *testing.T) { testConnectionDoSelectRequestCheck(t, resp, err, false, 10, 1010) } +func TestConnectionDoWatchOnceRequest(t *testing.T) { + watchOnceNotSupported, err := test_helpers.IsTarantoolVersionLess(3, 0, 0) + if err != nil { + log.Fatalf("Could not check the Tarantool version") + } + if watchOnceNotSupported { + return + } + + var req Request + + conn := test_helpers.ConnectWithValidation(t, server, opts) + defer conn.Close() + + // Insert in stream + req = NewInsertRequest(spaceName). + Tuple([]interface{}{1001, "hello", "world"}) + resp, err := conn.Do(req).Get() + if err != nil { + t.Fatalf("Failed to Insert: %s", err.Error()) + } + if resp.Code != OkCode { + t.Errorf("Failed to Insert: wrong code returned %d", resp.Code) + } + defer test_helpers.DeleteRecordByKey(t, conn, spaceNo, indexNo, []interface{}{1001}) + + req = NewWatchOnceRequest("1001") + resp, err = conn.Do(req).Get() + if err != nil { + t.Fatalf("Failed to WatchOnce: %s", err.Error()) + } + if resp.Code != OkCode { + t.Errorf("Failed to WatchOnce: wrong code returned %d", resp.Code) + } + if len(resp.Data) != 1 && resp.Data[1] != "world" { + t.Errorf("Failed to WatchOnce: wrong value returned %v", resp.Data) + } +} + func TestConnectionDoSelectRequest_fetch_pos(t *testing.T) { test_helpers.SkipIfPaginationUnsupported(t)