瀏覽代碼

add QueryValue function

xormplus 7 年之前
父節點
當前提交
7f4583b077
共有 6 個文件被更改,包括 621 次插入42 次删除
  1. 26 10
      README.md
  2. 442 0
      convert.go
  3. 7 0
      engine.go
  4. 70 32
      session_plus.go
  5. 14 0
      session_query.go
  6. 62 0
      session_raw.go

+ 26 - 10
README.md

@@ -126,7 +126,7 @@ if err != nil {
 sql_1_1 := "select * from user"
 results, err := engine.QueryBytes(sql_1_1)
 
-//SqlMapClient和SqlTemplateClient传参方式类同如下2种,具体参见第4种方式和第5种方式
+//SqlMapClient和SqlTemplateClient传参方式类同如下2种,具体参见第5种方式和第6种方式
 sql_1_2 := "select id,userid,title,createdatetime,content from Article where id=?"
 results, err := db.SQL(sql_1_2, 2).QueryBytes()
 
@@ -140,7 +140,7 @@ results, err := db.SQL(sql_1_3, &paramMap_1_3).QueryBytes()
 sql_2_1 := "select * from user"
 results, err := engine.QueryString(sql_2_1)
 
-//SqlMapClient和SqlTemplateClient传参方式类同如下2种,具体参见第种方式和第种方式
+//SqlMapClient和SqlTemplateClient传参方式类同如下2种,具体参见第5种方式和第6种方式
 sql_2_2 := "select id,userid,title,createdatetime,content from Article where id=?"
 results, err := db.SQL(sql_2_2, 2).QueryString()
 
@@ -149,12 +149,28 @@ paramMap_2_3 := map[string]interface{}{"id": 2}
 results, err := db.SQL(sql_2_3, &paramMap_2_3).QueryString()
 
 /*-------------------------------------------------------------------------------------
- * 第3种方式:返回的结果类型为 []map[string]interface{}
+ * 第3种方式:返回的结果类型为 []map[string]Value
+-------------------------------------------------------------------------------------*/
+//Value类型本质是[]byte,但具有一系列类型转换函数
+sql_2_1 := "select * from user"
+results, err := engine.QueryValue(sql_2_1)
+
+//SqlMapClient和SqlTemplateClient传参方式类同如下2种,具体参见第5种方式和第6种方式
+sql_2_2 := "select id,userid,title,createdatetime,content from Article where id=?"
+results, err := db.SQL(sql_2_2, 2).QueryValue()
+title := results[0]["title"].String()
+
+sql_2_3 := "select id,userid,title,createdatetime,content from Article where id=?id"
+paramMap_2_3 := map[string]interface{}{"id": 2}
+results, err := db.SQL(sql_2_3, &paramMap_2_3).QueryValue()
+
+/*-------------------------------------------------------------------------------------
+ * 第4种方式:返回的结果类型为 []map[string]interface{}
 -------------------------------------------------------------------------------------*/
 sql_3_1 := "select * from user"
 results, err := engine.QueryInterface(sql_3_1)
 
-//SqlMapClient和SqlTemplateClient传参方式类同如下2种,具体参见第种方式和第种方式
+//SqlMapClient和SqlTemplateClient传参方式类同如下2种,具体参见第5种方式和第6种方式
 sql_3_2 := "select id,userid,title,createdatetime,content from Article where id=?"
 results, err := db.SQL(sql_3_2, 2).QueryInterface()
 
@@ -192,7 +208,7 @@ results, err := engine.Sql(sql_3_5, 7, 17).Query().ListPage(13,28)
 count, err := engine.Sql(sql_3_5, 7, 17).Query().Count()
 
 /*-------------------------------------------------------------------------------------
-  第4种方式:执行SqlMap配置文件中的Sql语句,返回的结果类型为 []map[string]interface{}
+  第5种方式:执行SqlMap配置文件中的Sql语句,返回的结果类型为 []map[string]interface{}
 -------------------------------------------------------------------------------------*/
 sql_id_4_1 := "sql_4_1" //配置文件中sql标签的id属性,SqlMap的key
 results, err := engine.SqlMapClient(sql_id_4_1).Query().List()
@@ -205,7 +221,7 @@ paramMap_4_3 := map[string]interface{}{"id": 7, "name": "xormplus"}
 results1, err := engine.SqlMapClient(sql_id_4_3, &paramMap_4_3).Query().List()
 
 /*-------------------------------------------------------------------------------------
- * 第5种方式:执行SqlTemplate配置文件中的Sql语句,返回的结果类型为 []map[string]interface{}
+ * 第6种方式:执行SqlTemplate配置文件中的Sql语句,返回的结果类型为 []map[string]interface{}
 -------------------------------------------------------------------------------------*/
 sql_key_5_1 := "select.example.stpl" //配置文件名,SqlTemplate的key
 
@@ -220,7 +236,7 @@ paramMap_5_2 := map[string]interface{}{"id": 0, "count": 2, "name": "xormplus"}
 results, err := engine.SqlTemplateClient(sql_key_5_1, &paramMap_5_2).Query().List()
 
 /*-------------------------------------------------------------------------------------
- * 第6种方式:返回的结果类型为对应的[]interface{}
+ * 第7种方式:返回的结果类型为对应的[]interface{}
 -------------------------------------------------------------------------------------*/
 var categories []Category
 err := engine.Sql("select * from category where id =?", 16).Find(&categories)
@@ -229,7 +245,7 @@ paramMap_6 := map[string]interface{}{"id": 2}
 err := engine.Sql("select * from category where id =?id", &paramMap_6).Find(&categories)
 
 /*-------------------------------------------------------------------------------------
- * 第7种方式:返回的结果类型为对应的[]interface{}
+ * 第8种方式:返回的结果类型为对应的[]interface{}
 -------------------------------------------------------------------------------------*/
 sql_id_7_1 := "sql_7_1"
 var categories []Category
@@ -241,7 +257,7 @@ paramMap_7_2 := map[string]interface{}{"id": 25}
 err := engine.SqlMapClient(sql_id_7_2, &paramMap_7_2).Find(&categories)
 
 /*-------------------------------------------------------------------------------------
- * 第8种方式:返回的结果类型为对应的[]interface{}
+ * 第9种方式:返回的结果类型为对应的[]interface{}
 -------------------------------------------------------------------------------------*/
 //执行的 sql:select * from user where name='xormplus'
 sql_key_8_1 := "select.example.stpl" //配置文件名,SqlTemplate的key
@@ -251,7 +267,7 @@ err := engine.SqlTemplateClient(sql_key_8_1, &paramMap_8_1).Find(&users)
 
 
 /*-------------------------------------------------------------------------------------
- * 第9种方式:查询单条数据
+ * 第10种方式:查询单条数据
  * 使用Sql,SqlMapClient,SqlTemplateClient函数与Get函数组合可以查询单条数据,以Sql与Get函数组合为例:
 -------------------------------------------------------------------------------------*/
 //获得单条数据的值,并存为结构体

+ 442 - 0
convert.go

@@ -5,9 +5,12 @@
 package xorm
 
 import (
+	"bytes"
 	"database/sql/driver"
+	"encoding/binary"
 	"errors"
 	"fmt"
+	"math"
 	"reflect"
 	"strconv"
 	"time"
@@ -346,3 +349,442 @@ func asBool(bs []byte) (bool, error) {
 	}
 	return strconv.ParseBool(string(bs))
 }
+
+func EncodeString(s string) []byte {
+	return []byte(s)
+}
+
+func DecodeToString(b []byte) string {
+	return string(b)
+}
+
+func EncodeBool(b bool) []byte {
+	if b == true {
+		return []byte{1}
+	} else {
+		return []byte{0}
+	}
+}
+
+func EncodeInt(i int) []byte {
+	if i <= math.MaxInt8 {
+		return EncodeInt8(int8(i))
+	} else if i <= math.MaxInt16 {
+		return EncodeInt16(int16(i))
+	} else if i <= math.MaxInt32 {
+		return EncodeInt32(int32(i))
+	} else {
+		return EncodeInt64(int64(i))
+	}
+}
+
+func EncodeUint(i uint) []byte {
+	if i <= math.MaxUint8 {
+		return EncodeUint8(uint8(i))
+	} else if i <= math.MaxUint16 {
+		return EncodeUint16(uint16(i))
+	} else if i <= math.MaxUint32 {
+		return EncodeUint32(uint32(i))
+	} else {
+		return EncodeUint64(uint64(i))
+	}
+}
+
+func EncodeInt8(i int8) []byte {
+	return []byte{byte(i)}
+}
+
+func EncodeUint8(i uint8) []byte {
+	return []byte{byte(i)}
+}
+
+func EncodeInt16(i int16) []byte {
+	bytes := make([]byte, 2)
+	binary.LittleEndian.PutUint16(bytes, uint16(i))
+	return bytes
+}
+
+func EncodeUint16(i uint16) []byte {
+	bytes := make([]byte, 2)
+	binary.LittleEndian.PutUint16(bytes, i)
+	return bytes
+}
+
+func EncodeInt32(i int32) []byte {
+	bytes := make([]byte, 4)
+	binary.LittleEndian.PutUint32(bytes, uint32(i))
+	return bytes
+}
+
+func EncodeUint32(i uint32) []byte {
+	bytes := make([]byte, 4)
+	binary.LittleEndian.PutUint32(bytes, i)
+	return bytes
+}
+
+func EncodeInt64(i int64) []byte {
+	bytes := make([]byte, 8)
+	binary.LittleEndian.PutUint64(bytes, uint64(i))
+	return bytes
+}
+
+func EncodeUint64(i uint64) []byte {
+	bytes := make([]byte, 8)
+	binary.LittleEndian.PutUint64(bytes, i)
+	return bytes
+}
+
+func EncodeFloat32(f float32) []byte {
+	bits := math.Float32bits(f)
+	bytes := make([]byte, 4)
+	binary.LittleEndian.PutUint32(bytes, bits)
+	return bytes
+}
+
+func EncodeFloat64(f float64) []byte {
+	bits := math.Float64bits(f)
+	bytes := make([]byte, 8)
+	binary.LittleEndian.PutUint64(bytes, bits)
+	return bytes
+}
+
+func Encode(vs ...interface{}) []byte {
+	buf := new(bytes.Buffer)
+	for i := 0; i < len(vs); i++ {
+		switch value := vs[i].(type) {
+		case int:
+			buf.Write(EncodeInt(value))
+		case int8:
+			buf.Write(EncodeInt8(value))
+		case int16:
+			buf.Write(EncodeInt16(value))
+		case int32:
+			buf.Write(EncodeInt32(value))
+		case int64:
+			buf.Write(EncodeInt64(value))
+		case uint:
+			buf.Write(EncodeUint(value))
+		case uint8:
+			buf.Write(EncodeUint8(value))
+		case uint16:
+			buf.Write(EncodeUint16(value))
+		case uint32:
+			buf.Write(EncodeUint32(value))
+		case uint64:
+			buf.Write(EncodeUint64(value))
+		case bool:
+			buf.Write(EncodeBool(value))
+		case string:
+			buf.Write(EncodeString(value))
+		case []byte:
+			buf.Write(value)
+		case float32:
+			buf.Write(EncodeFloat32(value))
+		case float64:
+			buf.Write(EncodeFloat64(value))
+		default:
+			if err := binary.Write(buf, binary.LittleEndian, value); err != nil {
+				buf.Write(EncodeString(fmt.Sprintf("%v", value)))
+			}
+		}
+	}
+	return buf.Bytes()
+}
+
+func IsNumeric(s string) bool {
+	for i := 0; i < len(s); i++ {
+		if s[i] < byte('0') || s[i] > byte('9') {
+			return false
+		}
+	}
+	return true
+}
+
+func Time(i interface{}, format string, TZLocation ...*time.Location) time.Time {
+	s := String(i)
+	t, _ := StrToTime(s, format, TZLocation...)
+	return t
+}
+
+func StrToTime(str string, format string, TZLocation ...*time.Location) (time.Time, error) {
+	if len(TZLocation) > 0 {
+		if t, err := time.ParseInLocation(format, str, TZLocation[0]); err == nil {
+			return t, nil
+		} else {
+			return time.Time{}, err
+		}
+	} else {
+		if t, err := time.ParseInLocation(format, str, time.Local); err == nil {
+			return t, nil
+		} else {
+			return time.Time{}, err
+		}
+	}
+}
+
+func TimeDuration(i interface{}) time.Duration {
+	return time.Duration(Int64(i))
+}
+
+func Bytes(i interface{}) []byte {
+	if i == nil {
+		return nil
+	}
+	if r, ok := i.([]byte); ok {
+		return r
+	} else {
+		return Encode(i)
+	}
+}
+
+func String(i interface{}) string {
+	if i == nil {
+		return ""
+	}
+	switch value := i.(type) {
+	case int:
+		return strconv.Itoa(value)
+	case int8:
+		return strconv.Itoa(int(value))
+	case int16:
+		return strconv.Itoa(int(value))
+	case int32:
+		return strconv.Itoa(int(value))
+	case int64:
+		return strconv.Itoa(int(value))
+	case uint:
+		return strconv.FormatUint(uint64(value), 10)
+	case uint8:
+		return strconv.FormatUint(uint64(value), 10)
+	case uint16:
+		return strconv.FormatUint(uint64(value), 10)
+	case uint32:
+		return strconv.FormatUint(uint64(value), 10)
+	case uint64:
+		return strconv.FormatUint(uint64(value), 10)
+	case float32:
+		return strconv.FormatFloat(float64(value), 'f', -1, 64)
+	case float64:
+		return strconv.FormatFloat(value, 'f', -1, 64)
+	case bool:
+		return strconv.FormatBool(value)
+	case string:
+		return value
+	case []byte:
+		return string(value)
+	default:
+		return fmt.Sprintf("%v", value)
+	}
+}
+
+func Strings(i interface{}) []string {
+	if i == nil {
+		return nil
+	}
+	if r, ok := i.([]string); ok {
+		return r
+	} else if r, ok := i.([]interface{}); ok {
+		strs := make([]string, len(r))
+		for k, v := range r {
+			strs[k] = String(v)
+		}
+		return strs
+	}
+	return []string{fmt.Sprintf("%v", i)}
+}
+
+//false: "", 0, false, off
+func Bool(i interface{}) bool {
+	if i == nil {
+		return false
+	}
+	if v, ok := i.(bool); ok {
+		return v
+	}
+	if s := String(i); s != "" && s != "0" && s != "false" && s != "off" {
+		return true
+	}
+	return false
+}
+
+func Int(i interface{}) int {
+	if i == nil {
+		return 0
+	}
+	switch value := i.(type) {
+	case int:
+		return value
+	case int8:
+		return int(value)
+	case int16:
+		return int(value)
+	case int32:
+		return int(value)
+	case int64:
+		return int(value)
+	case uint:
+		return int(value)
+	case uint8:
+		return int(value)
+	case uint16:
+		return int(value)
+	case uint32:
+		return int(value)
+	case uint64:
+		return int(value)
+	case float32:
+		return int(value)
+	case float64:
+		return int(value)
+	case bool:
+		if value {
+			return 1
+		}
+		return 0
+	default:
+		v, _ := strconv.Atoi(String(value))
+		return v
+	}
+}
+
+func Int8(i interface{}) int8 {
+	if i == nil {
+		return 0
+	}
+	if v, ok := i.(int8); ok {
+		return v
+	}
+	return int8(Int(i))
+}
+
+func Int16(i interface{}) int16 {
+	if i == nil {
+		return 0
+	}
+	if v, ok := i.(int16); ok {
+		return v
+	}
+	return int16(Int(i))
+}
+
+func Int32(i interface{}) int32 {
+	if i == nil {
+		return 0
+	}
+	if v, ok := i.(int32); ok {
+		return v
+	}
+	return int32(Int(i))
+}
+
+func Int64(i interface{}) int64 {
+	if i == nil {
+		return 0
+	}
+	if v, ok := i.(int64); ok {
+		return v
+	}
+	return int64(Int(i))
+}
+
+func Uint(i interface{}) uint {
+	if i == nil {
+		return 0
+	}
+	switch value := i.(type) {
+	case int:
+		return uint(value)
+	case int8:
+		return uint(value)
+	case int16:
+		return uint(value)
+	case int32:
+		return uint(value)
+	case int64:
+		return uint(value)
+	case uint:
+		return value
+	case uint8:
+		return uint(value)
+	case uint16:
+		return uint(value)
+	case uint32:
+		return uint(value)
+	case uint64:
+		return uint(value)
+	case float32:
+		return uint(value)
+	case float64:
+		return uint(value)
+	case bool:
+		if value {
+			return 1
+		}
+		return 0
+	default:
+		v, _ := strconv.ParseUint(String(value), 10, 64)
+		return uint(v)
+	}
+}
+
+func Uint8(i interface{}) uint8 {
+	if i == nil {
+		return 0
+	}
+	if v, ok := i.(uint8); ok {
+		return v
+	}
+	return uint8(Uint(i))
+}
+
+func Uint16(i interface{}) uint16 {
+	if i == nil {
+		return 0
+	}
+	if v, ok := i.(uint16); ok {
+		return v
+	}
+	return uint16(Uint(i))
+}
+
+func Uint32(i interface{}) uint32 {
+	if i == nil {
+		return 0
+	}
+	if v, ok := i.(uint32); ok {
+		return v
+	}
+	return uint32(Uint(i))
+}
+
+func Uint64(i interface{}) uint64 {
+	if i == nil {
+		return 0
+	}
+	if v, ok := i.(uint64); ok {
+		return v
+	}
+	return uint64(Uint(i))
+}
+
+func Float32(i interface{}) float32 {
+	if i == nil {
+		return 0
+	}
+	if v, ok := i.(float32); ok {
+		return v
+	}
+	v, _ := strconv.ParseFloat(String(i), 32)
+	return float32(v)
+}
+
+func Float64(i interface{}) float64 {
+	if i == nil {
+		return 0
+	}
+	if v, ok := i.(float64); ok {
+		return v
+	}
+	v, _ := strconv.ParseFloat(String(i), 64)
+	return v
+}

+ 7 - 0
engine.go

@@ -1355,6 +1355,13 @@ func (engine *Engine) QueryBytes(sqlorArgs ...interface{}) (resultsSlice []map[s
 	return session.QueryBytes(sqlorArgs...)
 }
 
+// Query a raw sql and return records as []map[string]Value
+func (engine *Engine) QueryValue(sqlorArgs ...interface{}) (resultsSlice []map[string]Value, err error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.QueryValue(sqlorArgs...)
+}
+
 // QueryString runs a raw sql and return records as []map[string]string
 func (engine *Engine) QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) {
 	session := engine.NewSession()

+ 70 - 32
session_plus.go

@@ -12,10 +12,10 @@ import (
 	"reflect"
 	"regexp"
 	"strings"
+	"time"
 
 	"github.com/Chronokeeper/anyxml"
 	"github.com/xormplus/core"
-	//	"gopkg.in/flosch/pongo2.v3"
 )
 
 type ResultBean struct {
@@ -102,6 +102,75 @@ func (resultBean *ResultBean) XmlIndent(prefix string, indent string, recordTag
 	return resultBean.Has, string(resultByte), err
 }
 
+type Value []byte
+
+func (v Value) Bytes() []byte {
+	return []byte(v)
+}
+
+func (v Value) String() string {
+	return string(v)
+}
+
+func (v Value) Bool() bool {
+	return Bool(v)
+}
+
+func (v Value) Int() int {
+	return Int(v)
+}
+
+func (v Value) Int8() int8 {
+	return Int8(v)
+}
+
+func (v Value) Int16() int16 {
+	return Int16(v)
+}
+
+func (v Value) Int32() int32 {
+	return Int32(v)
+}
+
+func (v Value) Int64() int64 {
+	return Int64(v)
+}
+
+func (v Value) Uint() uint {
+	return Uint(v)
+}
+
+func (v Value) Uint8() uint8 {
+	return Uint8(v)
+}
+
+func (v Value) Uint16() uint16 {
+	return Uint16(v)
+}
+
+func (v Value) Uint32() uint32 {
+	return Uint32(v)
+}
+
+func (v Value) Uint64() uint64 {
+	return Uint64(v)
+}
+
+func (v Value) Float32() float32 {
+	return Float32(v)
+}
+
+func (v Value) Float64() float64 {
+	return Float64(v)
+}
+
+func (v Value) Time(format string, TZLocation ...*time.Location) time.Time {
+	return Time(v, format, TZLocation...)
+}
+func (v Value) TimeDuration() time.Duration {
+	return TimeDuration(v)
+}
+
 type ResultMap struct {
 	Results []map[string]interface{}
 	Error   error
@@ -380,37 +449,6 @@ func (session *Session) SqlMapClient(sqlTagName string, args ...interface{}) *Se
 	return session.Sql(session.engine.SqlMap.Sql[sqlTagName], args...)
 }
 
-//func (session *Session) SqlTemplateClient(sqlTagName string, args ...interface{}) *Session {
-//	session.isSqlFunc = true
-//	if session.engine.sqlTemplate.Template[sqlTagName] == nil {
-//		if len(args) == 0 {
-//			return session.Sql("")
-//		} else {
-//			map1 := args[0].(*map[string]interface{})
-//			return session.Sql("", map1)
-//		}
-//	}
-
-//	if len(args) == 0 {
-//		parmap := &pongo2.Context{"1": 1}
-//		sql, err := session.engine.sqlTemplate.Template[sqlTagName].Execute(*parmap)
-//		if err != nil {
-//			session.engine.logger.Error(err)
-
-//		}
-//		return session.Sql(sql)
-//	} else {
-//		map1 := args[0].(*map[string]interface{})
-//		sql, err := session.engine.sqlTemplate.Template[sqlTagName].Execute(*map1)
-//		if err != nil {
-//			session.engine.logger.Error(err)
-
-//		}
-//		return session.Sql(sql, map1)
-//	}
-
-//}
-
 func (session *Session) SqlTemplateClient(sqlTagName string, args ...interface{}) *Session {
 	session.isSqlFunc = true
 	sql, err := session.engine.SqlTemplate.Execute(sqlTagName, args...)

+ 14 - 0
session_query.go

@@ -107,6 +107,20 @@ func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interfa
 	return sqlStr, args, nil
 }
 
+func (session *Session) QueryValue(sqlorArgs ...interface{}) ([]map[string]Value, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	sqlStr, args, err := session.genQuerySQL(sqlorArgs...)
+	if err != nil {
+		return nil, err
+	}
+
+	return session.queryValue(sqlStr, args...)
+
+}
+
 // Query runs a raw sql and return records as []map[string][]byte
 func (session *Session) QueryBytes(sqlorArgs ...interface{}) ([]map[string][]byte, error) {
 	if session.isAutoClose {

+ 62 - 0
session_raw.go

@@ -95,6 +95,14 @@ func value2Bytes(rawValue *reflect.Value) ([]byte, error) {
 	return []byte(str), nil
 }
 
+func value2Value(rawValue *reflect.Value) (Value, error) {
+	str, err := value2String(rawValue)
+	if err != nil {
+		return nil, err
+	}
+	return Value(str), nil
+}
+
 func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) {
 	result := make(map[string][]byte)
 	scanResultContainers := make([]interface{}, len(fields))
@@ -123,6 +131,34 @@ func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, er
 	return result, nil
 }
 
+func row2mapValue(rows *core.Rows, fields []string) (resultsMap map[string]Value, err error) {
+	result := make(map[string]Value)
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for ii, key := range fields {
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
+		//if row is null then ignore
+		if rawValue.Interface() == nil {
+			result[key] = []byte{}
+			continue
+		}
+
+		if data, err := value2Value(&rawValue); err == nil {
+			result[key] = data
+		} else {
+			return nil, err // !nashtsai! REVIEW, should return err or just error log?
+		}
+	}
+	return result, nil
+}
+
 func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
 	fields, err := rows.Columns()
 	if err != nil {
@@ -139,6 +175,22 @@ func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
 	return resultsSlice, nil
 }
 
+func rows2mapsValue(rows *core.Rows) (resultsSlice []map[string]Value, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		result, err := row2mapValue(rows, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, result)
+	}
+
+	return resultsSlice, nil
+}
+
 func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) {
 	rows, err := session.queryRows(sqlStr, args...)
 	if err != nil {
@@ -149,6 +201,16 @@ func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[st
 	return rows2maps(rows)
 }
 
+func (session *Session) queryValue(sqlStr string, args ...interface{}) ([]map[string]Value, error) {
+	rows, err := session.queryRows(sqlStr, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2mapsValue(rows)
+}
+
 func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
 	defer session.resetStatement()