Skip to content

Commit 0b7ec01

Browse files
committed
api: add a public API with request types
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 1a1fe7b commit 0b7ec01

10 files changed

+1743
-85
lines changed

CHANGELOG.md

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

1313
- SSL support (#155)
1414
- IPROTO_PUSH messages support (#67)
15+
- Public API with request object types (#126)
1516

1617
### Changed
1718

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

2024
## [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
@@ -471,7 +471,7 @@ func (conn *Connection) dial() (err error) {
471471
func (conn *Connection) writeAuthRequest(w *bufio.Writer, scramble []byte) (err error) {
472472
request := &Future{
473473
requestId: 0,
474-
requestCode: AuthRequest,
474+
requestCode: AuthRequestCode,
475475
}
476476
var packet smallWBuf
477477
err = request.pack(&packet, msgpack.NewEncoder(&packet), func(enc *msgpack.Encoder) error {
@@ -978,6 +978,43 @@ func (conn *Connection) nextRequestId() (requestId uint32) {
978978
return atomic.AddUint32(&conn.requestId, 1)
979979
}
980980

981+
// Do verifies, sends the request and returns a response.
982+
//
983+
// An error is returned if the request was formed incorrectly, or failure to
984+
// communicate by the connection, or unable to decode the response.
985+
func (conn *Connection) Do(req Request) (*Response, error) {
986+
fut, err := conn.DoAsync(req)
987+
if err != nil {
988+
return nil, err
989+
}
990+
return fut.Get()
991+
}
992+
993+
// DoTyped verifies, sends the request and fills the typed result.
994+
//
995+
// An error is returned if the request was formed incorrectly, or failure to
996+
// communicate by the connection, or unable to decode the response.
997+
func (conn *Connection) DoTyped(req Request, result interface{}) error {
998+
fut, err := conn.DoAsync(req)
999+
if err != nil {
1000+
return err
1001+
}
1002+
return fut.GetTyped(result)
1003+
}
1004+
1005+
// DoAsync verifies, sends the request and returns a future.
1006+
//
1007+
// An error is returned if the request was formed incorrectly, or failure to
1008+
// create the future.
1009+
func (conn *Connection) DoAsync(req Request) (*Future, error) {
1010+
bodyFunc, err := req.BodyFunc(conn.Schema)
1011+
if err != nil {
1012+
return nil, err
1013+
}
1014+
future := conn.newFuture(req.Code())
1015+
return conn.sendFuture(future, bodyFunc), nil
1016+
}
1017+
9811018
// ConfiguredTimeout returns a timeout from connection config.
9821019
func (conn *Connection) ConfiguredTimeout() time.Duration {
9831020
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 ExampleFuture_GetIterator() {
130240
conn := example_connect()
131241
defer conn.Close()

export_test.go

Lines changed: 62 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,63 @@ func SslDialTimeout(network, address string, timeout time.Duration,
1715
func SslCreateContext(opts SslOpts) (ctx interface{}, err error) {
1816
return sslCreateContext(opts)
1917
}
18+
19+
// RefImplPingBody is reference implementation for filling of a ping
20+
// request's body.
21+
func RefImplPingBody(enc *msgpack.Encoder) error {
22+
return fillPing(enc)
23+
}
24+
25+
// RefImplSelectBody is reference implementation for filling of a select
26+
// request's body.
27+
func RefImplSelectBody(enc *msgpack.Encoder, space, index, offset, limit, iterator uint32, key interface{}) error {
28+
return fillSelect(enc, space, index, offset, limit, iterator, key)
29+
}
30+
31+
// RefImplInsertBody is reference implementation for filling of an insert
32+
// request's body.
33+
func RefImplInsertBody(enc *msgpack.Encoder, space uint32, tuple interface{}) error {
34+
return fillInsert(enc, space, tuple)
35+
}
36+
37+
// RefImplReplaceBody is reference implementation for filling of a replace
38+
// request's body.
39+
func RefImplReplaceBody(enc *msgpack.Encoder, space uint32, tuple interface{}) error {
40+
return fillInsert(enc, space, tuple)
41+
}
42+
43+
// RefImplDeleteBody is reference implementation for filling of a delete
44+
// request's body.
45+
func RefImplDeleteBody(enc *msgpack.Encoder, space, index uint32, key interface{}) error {
46+
return fillDelete(enc, space, index, key)
47+
}
48+
49+
// RefImplUpdateBody is reference implementation for filling of an update
50+
// request's body.
51+
func RefImplUpdateBody(enc *msgpack.Encoder, space, index uint32, key, ops interface{}) error {
52+
return fillUpdate(enc, space, index, key, ops)
53+
}
54+
55+
// RefImplUpsertBody is reference implementation for filling of an upsert
56+
// request's body.
57+
func RefImplUpsertBody(enc *msgpack.Encoder, space uint32, tuple, ops interface{}) error {
58+
return fillUpsert(enc, space, tuple, ops)
59+
}
60+
61+
// RefImplCallBody is reference implementation for filling of a call or call17
62+
// request's body.
63+
func RefImplCallBody(enc *msgpack.Encoder, function string, args interface{}) error {
64+
return fillCall(enc, function, args)
65+
}
66+
67+
// RefImplEvalBody is reference implementation for filling of an eval
68+
// request's body.
69+
func RefImplEvalBody(enc *msgpack.Encoder, expr string, args interface{}) error {
70+
return fillEval(enc, expr, args)
71+
}
72+
73+
// RefImplExecuteBody is reference implementation for filling of an execute
74+
// request's body.
75+
func RefImplExecuteBody(enc *msgpack.Encoder, expr string, args interface{}) error {
76+
return fillExecute(enc, expr, args)
77+
}

0 commit comments

Comments
 (0)