Skip to content

Commit fe3d5e3

Browse files
committed
Add public API with a request object 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. Part of #126
1 parent 1d06618 commit fe3d5e3

File tree

11 files changed

+996
-158
lines changed

11 files changed

+996
-158
lines changed

CHANGELOG.md

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

1313
- Coveralls support (#149)
14+
- Add public API with a request object for Select/Update/Upstream (#126)
1415
- Reusable testing workflow (integration testing with latest Tarantool) (#123)
1516
- Simple CI based on GitHub actions (#114)
1617
- Support UUID type in msgpack (#90)

client_tools.go

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

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

connection.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ func (conn *Connection) dial() (err error) {
431431
func (conn *Connection) writeAuthRequest(w *bufio.Writer, scramble []byte) (err error) {
432432
request := &Future{
433433
requestId: 0,
434-
requestCode: AuthRequest,
434+
requestCode: AuthRequestCode,
435435
}
436436
var packet smallWBuf
437437
err = request.pack(&packet, msgpack.NewEncoder(&packet), func(enc *msgpack.Encoder) error {
@@ -874,6 +874,43 @@ func (conn *Connection) nextRequestId() (requestId uint32) {
874874
return atomic.AddUint32(&conn.requestId, 1)
875875
}
876876

877+
// Do verifies, sends the request and returns a response.
878+
//
879+
// An error is returned if the request was formed incorrectly, or failure to
880+
// communicate by the connection, or unable to decode the response.
881+
func (conn *Connection) Do(req Request) (*Response, error) {
882+
fut, err := conn.DoAsync(req)
883+
if err != nil {
884+
return nil, err
885+
}
886+
return fut.Get()
887+
}
888+
889+
// DoTyped verifies, sends the request and fills the typed result.
890+
//
891+
// An error is returned if the request was formed incorrectly, or failure to
892+
// communicate by the connection, or unable to decode the response.
893+
func (conn *Connection) DoTyped(req Request, result interface{}) error {
894+
fut, err := conn.DoAsync(req)
895+
if err != nil {
896+
return err
897+
}
898+
return fut.GetTyped(result)
899+
}
900+
901+
// DoAsync verifies, sends the request and returns a future.
902+
//
903+
// An error is returned if the request was formed incorrectly, or failure to
904+
// create the future.
905+
func (conn *Connection) DoAsync(req Request) (*Future, error) {
906+
bodyFunc, err := req.BodyFunc(conn.Schema)
907+
if err != nil {
908+
return nil, err
909+
}
910+
future := conn.newFuture(req.Code())
911+
return future.send(conn, bodyFunc), nil
912+
}
913+
877914
// ConfiguredTimeout returns a timeout from connection config.
878915
func (conn *Connection) ConfiguredTimeout() time.Duration {
879916
return conn.opts.Timeout

const.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
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-
PingRequest = 64
15-
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+
PingRequestCode = 64
15+
SubscribeRequestCode = 66
1616

1717
KeyCode = 0x00
1818
KeySync = 0x01

example_test.go

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

106+
func ExampleSelectRequest() {
107+
conn := example_connect()
108+
defer conn.Close()
109+
110+
req := tarantool.NewSelectRequest(512).
111+
Limit(100).
112+
Key(tarantool.IntKey{1111})
113+
resp, err := conn.Do(req)
114+
if err != nil {
115+
fmt.Printf("error in do select request is %v", err)
116+
return
117+
}
118+
fmt.Printf("response is %#v\n", resp.Data)
119+
120+
req = tarantool.NewSelectRequest("test").
121+
Index("primary").
122+
Limit(100).
123+
Key(tarantool.IntKey{1111})
124+
fut, err := conn.DoAsync(req)
125+
if err != nil {
126+
fmt.Printf("error in do async select request is %v", err)
127+
}
128+
resp, err = fut.Get()
129+
if err != nil {
130+
fmt.Printf("error in do async select request is %v", err)
131+
return
132+
}
133+
fmt.Printf("response is %#v\n", resp.Data)
134+
// Output:
135+
// response is []interface {}{[]interface {}{0x457, "hello", "world"}}
136+
// response is []interface {}{[]interface {}{0x457, "hello", "world"}}
137+
}
138+
139+
func ExampleUpdateRequest() {
140+
conn := example_connect()
141+
defer conn.Close()
142+
143+
req := tarantool.NewUpdateRequest(512).
144+
Key(tarantool.IntKey{1111}).
145+
Operations(tarantool.NewOperations().Assign(1, "bye"))
146+
resp, err := conn.Do(req)
147+
if err != nil {
148+
fmt.Printf("error in do update request is %v", err)
149+
return
150+
}
151+
fmt.Printf("response is %#v\n", resp.Data)
152+
153+
req = tarantool.NewUpdateRequest("test").
154+
Index("primary").
155+
Key(tarantool.IntKey{1111}).
156+
Operations(tarantool.NewOperations().Assign(1, "hello"))
157+
fut, err := conn.DoAsync(req)
158+
if err != nil {
159+
fmt.Printf("error in do async update request is %v", err)
160+
}
161+
resp, err = fut.Get()
162+
if err != nil {
163+
fmt.Printf("error in do async update request is %v", err)
164+
return
165+
}
166+
fmt.Printf("response is %#v\n", resp.Data)
167+
// Output:
168+
// response is []interface {}{[]interface {}{0x457, "bye", "world"}}
169+
// response is []interface {}{[]interface {}{0x457, "hello", "world"}}
170+
}
171+
172+
func ExampleUpsertRequest() {
173+
conn := example_connect()
174+
defer conn.Close()
175+
176+
var req tarantool.Request
177+
req = tarantool.NewUpsertRequest(512).
178+
Tuple([]interface{}{uint(1113), "first", "first"}).
179+
Operations(tarantool.NewOperations().Assign(1, "updated"))
180+
resp, err := conn.Do(req)
181+
if err != nil {
182+
fmt.Printf("error in do select upsert is %v", err)
183+
return
184+
}
185+
fmt.Printf("response is %#v\n", resp.Data)
186+
187+
req = tarantool.NewUpsertRequest("test").
188+
Tuple([]interface{}{uint(1113), "second", "second"}).
189+
Operations(tarantool.NewOperations().Assign(2, "updated"))
190+
fut, err := conn.DoAsync(req)
191+
if err != nil {
192+
fmt.Printf("error in do async upsert request is %v", err)
193+
}
194+
resp, err = fut.Get()
195+
if err != nil {
196+
fmt.Printf("error in do async upsert request is %v", err)
197+
return
198+
}
199+
fmt.Printf("response is %#v\n", resp.Data)
200+
201+
req = tarantool.NewSelectRequest(512).
202+
Limit(100).
203+
Key(tarantool.IntKey{1113})
204+
resp, err = conn.Do(req)
205+
if err != nil {
206+
fmt.Printf("error in do select request is %v", err)
207+
return
208+
}
209+
fmt.Printf("response is %#v\n", resp.Data)
210+
// Output:
211+
// response is []interface {}{}
212+
// response is []interface {}{}
213+
// response is []interface {}{[]interface {}{0x459, "first", "updated"}}
214+
}
215+
106216
func ExampleConnection_Ping() {
107217
conn := example_connect()
108218
defer conn.Close()

export_test.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
package tarantool
22

3-
func (schema *Schema) ResolveSpaceIndex(s interface{}, i interface{}) (spaceNo, indexNo uint32, err error) {
4-
return schema.resolveSpaceIndex(s, i)
3+
import (
4+
"gopkg.in/vmihailenco/msgpack.v2"
5+
)
6+
7+
// RefImplSelectBody is reference implementation for filling of a select
8+
// request's body.
9+
func RefImplSelectBody(enc *msgpack.Encoder, space, index, offset, limit, iterator uint32, key interface{}) error {
10+
return fillSelect(enc, space, index, offset, limit, iterator, key)
11+
}
12+
13+
// RefImplUpdateBody is reference implementation for filling of an update
14+
// request's body.
15+
func RefImplUpdateBody(enc *msgpack.Encoder, space, index uint32, key, ops interface{}) error {
16+
return fillUpdate(enc, space, index, key, ops)
17+
}
18+
19+
// RefImplUpsertBody is reference implementation for filling of an upsert
20+
// request's body.
21+
func RefImplUpsertBody(enc *msgpack.Encoder, space uint32, tuple, ops interface{}) error {
22+
return fillUpsert(enc, space, tuple, ops)
523
}

0 commit comments

Comments
 (0)