Skip to content

Commit d6a79d9

Browse files
committed
api: add a public API with request types
This patch provides request types. 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 `<Name>Request` to `<Name>RequestCode` to provide names for request types. Part of #126
1 parent 988edce commit d6a79d9

14 files changed

+1821
-93
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ 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

1819
- Add `Call16` method, support build tag `go_tarantool_call_17`
1920
to choose behavior for `Call` method (#125)
21+
- `IPROTO_*` constants that identify requests renamed from `<Name>Request` to
22+
`<Name>RequestCode` (#126)
2023

2124
### Fixed
2225

call_16_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,29 @@ func TestConnection_Call(t *testing.T) {
2525
t.Errorf("result is not {{1}} : %v", resp.Data)
2626
}
2727
}
28+
29+
func TestCallRequest(t *testing.T) {
30+
var resp *Response
31+
var err error
32+
33+
conn := connect(t, server, opts)
34+
defer conn.Close()
35+
36+
req := NewCallRequest("simple_incr").Args([]interface{}{1})
37+
resp, err = conn.Do(req)
38+
if err != nil {
39+
t.Errorf("Failed to use Call")
40+
}
41+
if resp.Data[0].([]interface{})[0].(uint64) != 2 {
42+
t.Errorf("result is not {{1}} : %v", resp.Data)
43+
}
44+
}
45+
46+
func TestCallRequestCode(t *testing.T) {
47+
req := NewCallRequest("simple_incrt")
48+
code := req.Code()
49+
expected := Call16RequestCode
50+
if code != int32(expected) {
51+
t.Errorf("CallRequest actual code %v != %v", code, expected)
52+
}
53+
}

call_17_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,29 @@ func TestConnection_Call(t *testing.T) {
2525
t.Errorf("result is not {{1}} : %v", resp.Data)
2626
}
2727
}
28+
29+
func TestCallRequest(t *testing.T) {
30+
var resp *Response
31+
var err error
32+
33+
conn := connect(t, server, opts)
34+
defer conn.Close()
35+
36+
req := NewCallRequest("simple_incr").Args([]interface{}{1})
37+
resp, err = conn.Do(req)
38+
if err != nil {
39+
t.Errorf("Failed to use Call")
40+
}
41+
if resp.Data[0].(uint64) != 2 {
42+
t.Errorf("result is not {{1}} : %v", resp.Data)
43+
}
44+
}
45+
46+
func TestCallRequestCode(t *testing.T) {
47+
req := NewCallRequest("simple_incrt")
48+
code := req.Code()
49+
expected := Call17RequestCode
50+
if code != int32(expected) {
51+
t.Errorf("CallRequest actual code %v != %v", code, expected)
52+
}
53+
}

client_tools.go

+73
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

+38-1
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 failed 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 failed 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 failed 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

+13-13
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-
Call16Request = 6 /* call in 1.6 format */
10-
AuthRequest = 7
11-
EvalRequest = 8
12-
UpsertRequest = 9
13-
Call17Request = 10 /* call in >= 1.7 format */
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+
Call16RequestCode = 6 /* call in 1.6 format */
10+
AuthRequestCode = 7
11+
EvalRequestCode = 8
12+
UpsertRequestCode = 9
13+
Call17RequestCode = 10 /* call in >= 1.7 format */
14+
ExecuteRequestCode = 11
15+
PingRequestCode = 64
16+
SubscribeRequestCode = 66
1717

1818
KeyCode = 0x00
1919
KeySync = 0x01

const_call_16.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
package tarantool
55

66
const (
7-
CallRequest = Call16Request
7+
CallRequestCode = Call16RequestCode
88
)

const_call_17.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
package tarantool
55

66
const (
7-
CallRequest = Call17Request
7+
CallRequestCode = Call17RequestCode
88
)

example_test.go

+110
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()

0 commit comments

Comments
 (0)