Skip to content

Commit 08d91c5

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 7897baf commit 08d91c5

11 files changed

+1011
-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
@@ -430,7 +430,7 @@ func (conn *Connection) dial() (err error) {
430430
func (conn *Connection) writeAuthRequest(w *bufio.Writer, scramble []byte) (err error) {
431431
request := &Future{
432432
requestId: 0,
433-
requestCode: AuthRequest,
433+
requestCode: AuthRequestCode,
434434
}
435435
var packet smallWBuf
436436
err = request.pack(&packet, msgpack.NewEncoder(&packet), func(enc *msgpack.Encoder) error {
@@ -873,6 +873,43 @@ func (conn *Connection) nextRequestId() (requestId uint32) {
873873
return atomic.AddUint32(&conn.requestId, 1)
874874
}
875875

876+
// Do verifies, sends the request and returns a response.
877+
//
878+
// An error is returned if the request was formed incorrectly, or failure to
879+
// communicate by the connection, or unable to decode the response.
880+
func (conn *Connection) Do(req Request) (*Response, error) {
881+
fut, err := conn.DoAsync(req)
882+
if err != nil {
883+
return nil, err
884+
}
885+
return fut.Get()
886+
}
887+
888+
// DoTyped verifies, sends the request and fills the typed result.
889+
//
890+
// An error is returned if the request was formed incorrectly, or failure to
891+
// communicate by the connection, or unable to decode the response.
892+
func (conn *Connection) DoTyped(req Request, result interface{}) error {
893+
fut, err := conn.DoAsync(req)
894+
if err != nil {
895+
return err
896+
}
897+
return fut.GetTyped(result)
898+
}
899+
900+
// DoAsync verifies, sends the request and returns a future.
901+
//
902+
// An error is returned if the request was formed incorrectly, or failure to
903+
// create the future.
904+
func (conn *Connection) DoAsync(req Request) (*Future, error) {
905+
bodyFunc, err := req.BodyFunc(conn.Schema)
906+
if err != nil {
907+
return nil, err
908+
}
909+
future := conn.newFuture(req.Code())
910+
return future.send(conn, bodyFunc), nil
911+
}
912+
876913
// ConfiguredTimeout returns timeout from connection config
877914
func (conn *Connection) ConfiguredTimeout() time.Duration {
878915
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: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,131 @@ func ExampleConnection_SelectTyped() {
8585
// response is [{{} 1111 hello world}]
8686
}
8787

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

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)