@@ -2,6 +2,8 @@ package tarantool
22
33import (
44 "errors"
5+ "reflect"
6+ "strings"
57 "time"
68
79 "gopkg.in/vmihailenco/msgpack.v2"
@@ -120,6 +122,16 @@ func (conn *Connection) Eval(expr string, args interface{}) (resp *Response, err
120122 return conn .EvalAsync (expr , args ).Get ()
121123}
122124
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+
123135// single used for conn.GetTyped for decode one tuple
124136type single struct {
125137 res interface {}
@@ -346,9 +358,82 @@ func (conn *Connection) EvalAsync(expr string, args interface{}) *Future {
346358 })
347359}
348360
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+
349373//
350374// private
351375//
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+ }
352437
353438func (fut * Future ) pack (h * smallWBuf , enc * msgpack.Encoder , body func (* msgpack.Encoder ) error ) (err error ) {
354439 rid := fut .requestId
0 commit comments