@@ -2,6 +2,8 @@ package tarantool
2
2
3
3
import (
4
4
"errors"
5
+ "reflect"
6
+ "strings"
5
7
"time"
6
8
7
9
"gopkg.in/vmihailenco/msgpack.v2"
@@ -120,6 +122,16 @@ func (conn *Connection) Eval(expr string, args interface{}) (resp *Response, err
120
122
return conn .EvalAsync (expr , args ).Get ()
121
123
}
122
124
125
+ // Execute passes sql expression to Tarantool for execution.
126
+ //
127
+ // It is equal to conn.ExecuteAsync(expr, args).Get().
128
+ func (conn * Connection ) Execute (expr string , args ... interface {}) (resp * Response , err error ) {
129
+ if len (args ) > 1 {
130
+ return conn .ExecuteAsync (expr , args ).Get ()
131
+ }
132
+ return conn .ExecuteAsync (expr , args [0 ]).Get ()
133
+ }
134
+
123
135
// single used for conn.GetTyped for decode one tuple
124
136
type single struct {
125
137
res interface {}
@@ -346,9 +358,82 @@ func (conn *Connection) EvalAsync(expr string, args interface{}) *Future {
346
358
})
347
359
}
348
360
361
+ // ExecuteAsync sends a sql expression for execution and returns Future.
362
+ func (conn * Connection ) ExecuteAsync (expr string , args interface {}) * Future {
363
+ future := conn .newFuture (ExecuteRequest )
364
+ return future .send (conn , func (enc * msgpack.Encoder ) error {
365
+ enc .EncodeMapLen (2 )
366
+ enc .EncodeUint64 (KeySQLText )
367
+ enc .EncodeString (expr )
368
+ enc .EncodeUint64 (KeySQLBind )
369
+ return encodeSQLBind (enc , args )
370
+ })
371
+ }
372
+
349
373
//
350
374
// private
351
375
//
376
+ func encodeSQLBind (enc * msgpack.Encoder , from interface {}) error {
377
+ // internal function for encoding single map in msgpack
378
+ encodeKeyVal := func (enc * msgpack.Encoder , key , val reflect.Value ) error {
379
+ if err := enc .EncodeMapLen (1 ); err != nil {
380
+ return err
381
+ }
382
+ if err := enc .EncodeValue (key ); err != nil {
383
+ return err
384
+ }
385
+ if err := enc .EncodeValue (val ); err != nil {
386
+ return err
387
+ }
388
+ return nil
389
+ }
390
+
391
+ val := reflect .ValueOf (from )
392
+ switch val .Kind () {
393
+ case reflect .Map :
394
+ if err := enc .EncodeSliceLen (val .Len ()); err != nil {
395
+ return err
396
+ }
397
+ it := val .MapRange ()
398
+ for it .Next () {
399
+ k := reflect .ValueOf (":" + it .Key ().String ())
400
+ v := it .Value ()
401
+ if err := encodeKeyVal (enc , k , v ); err != nil {
402
+ return err
403
+ }
404
+ }
405
+ case reflect .Struct :
406
+ if err := enc .EncodeSliceLen (val .NumField ()); err != nil {
407
+ return err
408
+ }
409
+ for i := 0 ; i < val .NumField (); i ++ {
410
+ key := val .Type ().Field (i ).Name
411
+ k := reflect .ValueOf (":" + strings .ToLower (key ))
412
+ v := reflect .ValueOf (from ).FieldByName (key )
413
+ if err := encodeKeyVal (enc , k , v ); err != nil {
414
+ return err
415
+ }
416
+ }
417
+ case reflect .Slice , reflect .Array :
418
+ if val .Len () > 0 {
419
+ sliceType := reflect .ValueOf (val .Index (0 ).Interface ()).Kind ()
420
+ if sliceType != reflect .Struct {
421
+ return enc .Encode (from )
422
+ }
423
+ }
424
+ if err := enc .EncodeSliceLen (val .Len ()); err != nil {
425
+ return err
426
+ }
427
+ for i := 0 ; i < val .Len (); i ++ {
428
+ k := ":" + val .Index (i ).Field (0 ).String ()
429
+ v := val .Index (i ).Field (1 )
430
+ if err := encodeKeyVal (enc , reflect .ValueOf (k ), v ); err != nil {
431
+ return err
432
+ }
433
+ }
434
+ }
435
+ return nil
436
+ }
352
437
353
438
func (fut * Future ) pack (h * smallWBuf , enc * msgpack.Encoder , body func (* msgpack.Encoder ) error ) (err error ) {
354
439
rid := fut .requestId
0 commit comments