Skip to content

Commit 1a3c4fd

Browse files
committed
api: add a public API with request types for Select/Update/Upsert
This patch provides request types for part of space operations: Select, Update and Upstream. It allows to create requests step by step. The main idea here is too provide more extensible approach to create requests. It renames IPROTO constants that identify requests from `NameRequest` to `NameRequestCode` to provide names for request types. Part of #126
1 parent 3b7b31a commit 1a3c4fd

10 files changed

+933
-61
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
1111
### Added
1212

1313
- SSL support (#155)
14+
- Public API with a request object for Select/Update/Upstream (#126)
1415

1516
### Changed
1617

18+
- IPROTO constants that identify requests renamed from `NameRequest` to
19+
`NameRequestCode` (#126)
20+
1721
### Fixed
1822

1923
## [1.6.0] - 2022-06-01

client_tools.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,79 @@ func (o Op) EncodeMsgpack(enc *msgpack.Encoder) error {
6767
return enc.Encode(o.Arg)
6868
}
6969

70+
const (
71+
appendOperator = "+"
72+
subtractionOperator = "-"
73+
bitwiseAndOperator = "&"
74+
bitwiseOrOperator = "|"
75+
bitwiseXorOperator = "^"
76+
spliceOperator = ":"
77+
insertOperator = "!"
78+
deleteOperator = "#"
79+
assignOperator = "="
80+
)
81+
82+
// Operations is a collection of update operations.
83+
type Operations struct {
84+
ops []Op
85+
}
86+
87+
// NewOperations returns a new empty collection of update operations.
88+
func NewOperations() *Operations {
89+
ops := new(Operations)
90+
return ops
91+
}
92+
93+
func (ops *Operations) append(op string, field int, arg interface{}) *Operations {
94+
ops.ops = append(ops.ops, Op{op, field, arg})
95+
return ops
96+
}
97+
98+
// Add adds an additional operation to the collection of update operations.
99+
func (ops *Operations) Add(field int, arg interface{}) *Operations {
100+
return ops.append(appendOperator, field, arg)
101+
}
102+
103+
// Subtract adds a subtraction operation to the collection of update operations.
104+
func (ops *Operations) Subtract(field int, arg interface{}) *Operations {
105+
return ops.append(subtractionOperator, field, arg)
106+
}
107+
108+
// BitwiseAnd adds a bitwise AND operation to the collection of update operations.
109+
func (ops *Operations) BitwiseAnd(field int, arg interface{}) *Operations {
110+
return ops.append(bitwiseAndOperator, field, arg)
111+
}
112+
113+
// BitwiseOr adds a bitwise OR operation to the collection of update operations.
114+
func (ops *Operations) BitwiseOr(field int, arg interface{}) *Operations {
115+
return ops.append(bitwiseOrOperator, field, arg)
116+
}
117+
118+
// BitwiseXor adds a bitwise XOR operation to the collection of update operations.
119+
func (ops *Operations) BitwiseXor(field int, arg interface{}) *Operations {
120+
return ops.append(bitwiseXorOperator, field, arg)
121+
}
122+
123+
// Splice adds a splice operation to the collection of update operations.
124+
func (ops *Operations) Splice(field int, arg interface{}) *Operations {
125+
return ops.append(spliceOperator, field, arg)
126+
}
127+
128+
// Insert adds an insert operation to the collection of update operations.
129+
func (ops *Operations) Insert(field int, arg interface{}) *Operations {
130+
return ops.append(insertOperator, field, arg)
131+
}
132+
133+
// Delete adds a delete operation to the collection of update operations.
134+
func (ops *Operations) Delete(field int, arg interface{}) *Operations {
135+
return ops.append(deleteOperator, field, arg)
136+
}
137+
138+
// Assign adds an assign operation to the collection of update operations.
139+
func (ops *Operations) Assign(field int, arg interface{}) *Operations {
140+
return ops.append(assignOperator, field, arg)
141+
}
142+
70143
type OpSplice struct {
71144
Op string
72145
Field int

connection.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ func (conn *Connection) dial() (err error) {
470470
func (conn *Connection) writeAuthRequest(w *bufio.Writer, scramble []byte) (err error) {
471471
request := &Future{
472472
requestId: 0,
473-
requestCode: AuthRequest,
473+
requestCode: AuthRequestCode,
474474
}
475475
var packet smallWBuf
476476
err = request.pack(&packet, msgpack.NewEncoder(&packet), func(enc *msgpack.Encoder) error {
@@ -913,6 +913,43 @@ func (conn *Connection) nextRequestId() (requestId uint32) {
913913
return atomic.AddUint32(&conn.requestId, 1)
914914
}
915915

916+
// Do verifies, sends the request and returns a response.
917+
//
918+
// An error is returned if the request was formed incorrectly, or failure to
919+
// communicate by the connection, or unable to decode the response.
920+
func (conn *Connection) Do(req Request) (*Response, error) {
921+
fut, err := conn.DoAsync(req)
922+
if err != nil {
923+
return nil, err
924+
}
925+
return fut.Get()
926+
}
927+
928+
// DoTyped verifies, sends the request and fills the typed result.
929+
//
930+
// An error is returned if the request was formed incorrectly, or failure to
931+
// communicate by the connection, or unable to decode the response.
932+
func (conn *Connection) DoTyped(req Request, result interface{}) error {
933+
fut, err := conn.DoAsync(req)
934+
if err != nil {
935+
return err
936+
}
937+
return fut.GetTyped(result)
938+
}
939+
940+
// DoAsync verifies, sends the request and returns a future.
941+
//
942+
// An error is returned if the request was formed incorrectly, or failure to
943+
// create the future.
944+
func (conn *Connection) DoAsync(req Request) (*Future, error) {
945+
bodyFunc, err := req.BodyFunc(conn.Schema)
946+
if err != nil {
947+
return nil, err
948+
}
949+
future := conn.newFuture(req.Code())
950+
return future.send(conn, bodyFunc), nil
951+
}
952+
916953
// ConfiguredTimeout returns a timeout from connection config.
917954
func (conn *Connection) ConfiguredTimeout() time.Duration {
918955
return conn.opts.Timeout

const.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
package tarantool
22

33
const (
4-
SelectRequest = 1
5-
InsertRequest = 2
6-
ReplaceRequest = 3
7-
UpdateRequest = 4
8-
DeleteRequest = 5
9-
CallRequest = 6 /* call in 1.6 format */
10-
AuthRequest = 7
11-
EvalRequest = 8
12-
UpsertRequest = 9
13-
Call17Request = 10
14-
ExecuteRequest = 11
15-
PingRequest = 64
16-
SubscribeRequest = 66
4+
SelectRequestCode = 1
5+
InsertRequestCode = 2
6+
ReplaceRequestCode = 3
7+
UpdateRequestCode = 4
8+
DeleteRequestCode = 5
9+
CallRequestCode = 6 /* call in 1.6 format */
10+
AuthRequestCode = 7
11+
EvalRequestCode = 8
12+
UpsertRequestCode = 9
13+
Call17RequestCode = 10
14+
ExecuteRequestCode = 11
15+
PingRequestCode = 64
16+
SubscribeRequestCode = 66
1717

1818
KeyCode = 0x00
1919
KeySync = 0x01

example_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,116 @@ func ExampleConnection_SelectAsync() {
126126
// Future 2 Data [[18 val 18 bla]]
127127
}
128128

129+
func ExampleSelectRequest() {
130+
conn := example_connect()
131+
defer conn.Close()
132+
133+
req := tarantool.NewSelectRequest(517).
134+
Limit(100).
135+
Key(tarantool.IntKey{1111})
136+
resp, err := conn.Do(req)
137+
if err != nil {
138+
fmt.Printf("error in do select request is %v", err)
139+
return
140+
}
141+
fmt.Printf("response is %#v\n", resp.Data)
142+
143+
req = tarantool.NewSelectRequest("test").
144+
Index("primary").
145+
Limit(100).
146+
Key(tarantool.IntKey{1111})
147+
fut, err := conn.DoAsync(req)
148+
if err != nil {
149+
fmt.Printf("error in do async select request is %v", err)
150+
}
151+
resp, err = fut.Get()
152+
if err != nil {
153+
fmt.Printf("error in do async select request is %v", err)
154+
return
155+
}
156+
fmt.Printf("response is %#v\n", resp.Data)
157+
// Output:
158+
// response is []interface {}{[]interface {}{0x457, "hello", "world"}}
159+
// response is []interface {}{[]interface {}{0x457, "hello", "world"}}
160+
}
161+
162+
func ExampleUpdateRequest() {
163+
conn := example_connect()
164+
defer conn.Close()
165+
166+
req := tarantool.NewUpdateRequest(517).
167+
Key(tarantool.IntKey{1111}).
168+
Operations(tarantool.NewOperations().Assign(1, "bye"))
169+
resp, err := conn.Do(req)
170+
if err != nil {
171+
fmt.Printf("error in do update request is %v", err)
172+
return
173+
}
174+
fmt.Printf("response is %#v\n", resp.Data)
175+
176+
req = tarantool.NewUpdateRequest("test").
177+
Index("primary").
178+
Key(tarantool.IntKey{1111}).
179+
Operations(tarantool.NewOperations().Assign(1, "hello"))
180+
fut, err := conn.DoAsync(req)
181+
if err != nil {
182+
fmt.Printf("error in do async update request is %v", err)
183+
}
184+
resp, err = fut.Get()
185+
if err != nil {
186+
fmt.Printf("error in do async update request is %v", err)
187+
return
188+
}
189+
fmt.Printf("response is %#v\n", resp.Data)
190+
// Output:
191+
// response is []interface {}{[]interface {}{0x457, "bye", "world"}}
192+
// response is []interface {}{[]interface {}{0x457, "hello", "world"}}
193+
}
194+
195+
func ExampleUpsertRequest() {
196+
conn := example_connect()
197+
defer conn.Close()
198+
199+
var req tarantool.Request
200+
req = tarantool.NewUpsertRequest(517).
201+
Tuple([]interface{}{uint(1113), "first", "first"}).
202+
Operations(tarantool.NewOperations().Assign(1, "updated"))
203+
resp, err := conn.Do(req)
204+
if err != nil {
205+
fmt.Printf("error in do select upsert is %v", err)
206+
return
207+
}
208+
fmt.Printf("response is %#v\n", resp.Data)
209+
210+
req = tarantool.NewUpsertRequest("test").
211+
Tuple([]interface{}{uint(1113), "second", "second"}).
212+
Operations(tarantool.NewOperations().Assign(2, "updated"))
213+
fut, err := conn.DoAsync(req)
214+
if err != nil {
215+
fmt.Printf("error in do async upsert request is %v", err)
216+
}
217+
resp, err = fut.Get()
218+
if err != nil {
219+
fmt.Printf("error in do async upsert request is %v", err)
220+
return
221+
}
222+
fmt.Printf("response is %#v\n", resp.Data)
223+
224+
req = tarantool.NewSelectRequest(517).
225+
Limit(100).
226+
Key(tarantool.IntKey{1113})
227+
resp, err = conn.Do(req)
228+
if err != nil {
229+
fmt.Printf("error in do select request is %v", err)
230+
return
231+
}
232+
fmt.Printf("response is %#v\n", resp.Data)
233+
// Output:
234+
// response is []interface {}{}
235+
// response is []interface {}{}
236+
// response is []interface {}{[]interface {}{0x459, "first", "updated"}}
237+
}
238+
129239
func ExampleConnection_Ping() {
130240
conn := example_connect()
131241
defer conn.Close()

export_test.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ package tarantool
33
import (
44
"net"
55
"time"
6-
)
76

8-
func (schema *Schema) ResolveSpaceIndex(s interface{}, i interface{}) (spaceNo, indexNo uint32, err error) {
9-
return schema.resolveSpaceIndex(s, i)
10-
}
7+
"gopkg.in/vmihailenco/msgpack.v2"
8+
)
119

1210
func SslDialTimeout(network, address string, timeout time.Duration,
1311
opts SslOpts) (connection net.Conn, err error) {
@@ -17,3 +15,21 @@ func SslDialTimeout(network, address string, timeout time.Duration,
1715
func SslCreateContext(opts SslOpts) (ctx interface{}, err error) {
1816
return sslCreateContext(opts)
1917
}
18+
19+
// RefImplSelectBody is reference implementation for filling of a select
20+
// request's body.
21+
func RefImplSelectBody(enc *msgpack.Encoder, space, index, offset, limit, iterator uint32, key interface{}) error {
22+
return fillSelect(enc, space, index, offset, limit, iterator, key)
23+
}
24+
25+
// RefImplUpdateBody is reference implementation for filling of an update
26+
// request's body.
27+
func RefImplUpdateBody(enc *msgpack.Encoder, space, index uint32, key, ops interface{}) error {
28+
return fillUpdate(enc, space, index, key, ops)
29+
}
30+
31+
// RefImplUpsertBody is reference implementation for filling of an upsert
32+
// request's body.
33+
func RefImplUpsertBody(enc *msgpack.Encoder, space uint32, tuple, ops interface{}) error {
34+
return fillUpsert(enc, space, tuple, ops)
35+
}

0 commit comments

Comments
 (0)