瀏覽代碼

add ToMapString method for rows and row

xormplus 9 年之前
父節點
當前提交
2750e9842a
共有 2 個文件被更改,包括 380 次插入315 次删除
  1. 0 315
      db.go
  2. 380 0
      rows.go

+ 0 - 315
db.go

@@ -7,7 +7,6 @@ import (
 	"fmt"
 	"reflect"
 	"regexp"
-	"sync"
 )
 
 func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
@@ -103,103 +102,6 @@ func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) {
 	return db.Query(query, args...)
 }
 
-type Row struct {
-	rows *Rows
-	// One of these two will be non-nil:
-	err error // deferred error for easy chaining
-}
-
-func (row *Row) Columns() ([]string, error) {
-	if row.err != nil {
-		return nil, row.err
-	}
-	return row.rows.Columns()
-}
-
-func (row *Row) Scan(dest ...interface{}) error {
-	if row.err != nil {
-		return row.err
-	}
-	defer row.rows.Close()
-
-	for _, dp := range dest {
-		if _, ok := dp.(*sql.RawBytes); ok {
-			return errors.New("sql: RawBytes isn't allowed on Row.Scan")
-		}
-	}
-
-	if !row.rows.Next() {
-		if err := row.rows.Err(); err != nil {
-			return err
-		}
-		return sql.ErrNoRows
-	}
-	err := row.rows.Scan(dest...)
-	if err != nil {
-		return err
-	}
-	// Make sure the query can be processed to completion with no errors.
-	if err := row.rows.Close(); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func (row *Row) ScanStructByName(dest interface{}) error {
-	if row.err != nil {
-		return row.err
-	}
-	if !row.rows.Next() {
-		if err := row.rows.Err(); err != nil {
-			return err
-		}
-		return sql.ErrNoRows
-	}
-	return row.rows.ScanStructByName(dest)
-}
-
-func (row *Row) ScanStructByIndex(dest interface{}) error {
-	if row.err != nil {
-		return row.err
-	}
-	if !row.rows.Next() {
-		if err := row.rows.Err(); err != nil {
-			return err
-		}
-		return sql.ErrNoRows
-	}
-	return row.rows.ScanStructByIndex(dest)
-}
-
-// scan data to a slice's pointer, slice's length should equal to columns' number
-func (row *Row) ScanSlice(dest interface{}) error {
-	if row.err != nil {
-		return row.err
-	}
-	if !row.rows.Next() {
-		if err := row.rows.Err(); err != nil {
-			return err
-		}
-		return sql.ErrNoRows
-	}
-	return row.rows.ScanSlice(dest)
-}
-
-// scan data to a map's pointer
-func (row *Row) ScanMap(dest interface{}) error {
-	if row.err != nil {
-		return row.err
-	}
-	if !row.rows.Next() {
-		if err := row.rows.Err(); err != nil {
-			return err
-		}
-		return sql.ErrNoRows
-	}
-	return row.rows.ScanMap(dest)
-}
-
 func (db *DB) QueryRow(query string, args ...interface{}) *Row {
 	rows, err := db.Query(query, args...)
 	if err != nil {
@@ -363,44 +265,6 @@ func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) {
 	return db.DB.Exec(query, args...)
 }
 
-type Rows struct {
-	*sql.Rows
-	Mapper IMapper
-}
-
-// scan data to a struct's pointer according field index
-func (rs *Rows) ScanStructByIndex(dest ...interface{}) error {
-	if len(dest) == 0 {
-		return errors.New("at least one struct")
-	}
-
-	vvvs := make([]reflect.Value, len(dest))
-	for i, s := range dest {
-		vv := reflect.ValueOf(s)
-		if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
-			return errors.New("dest should be a struct's pointer")
-		}
-
-		vvvs[i] = vv.Elem()
-	}
-
-	cols, err := rs.Columns()
-	if err != nil {
-		return err
-	}
-	newDest := make([]interface{}, len(cols))
-
-	var i = 0
-	for _, vvv := range vvvs {
-		for j := 0; j < vvv.NumField(); j++ {
-			newDest[i] = vvv.Field(j).Addr().Interface()
-			i = i + 1
-		}
-	}
-
-	return rs.Rows.Scan(newDest...)
-}
-
 type EmptyScanner struct {
 }
 
@@ -408,185 +272,6 @@ func (EmptyScanner) Scan(src interface{}) error {
 	return nil
 }
 
-var (
-	fieldCache      = make(map[reflect.Type]map[string]int)
-	fieldCacheMutex sync.RWMutex
-)
-
-func fieldByName(v reflect.Value, name string) reflect.Value {
-	t := v.Type()
-	fieldCacheMutex.RLock()
-	cache, ok := fieldCache[t]
-	fieldCacheMutex.RUnlock()
-	if !ok {
-		cache = make(map[string]int)
-		for i := 0; i < v.NumField(); i++ {
-			cache[t.Field(i).Name] = i
-		}
-		fieldCacheMutex.Lock()
-		fieldCache[t] = cache
-		fieldCacheMutex.Unlock()
-	}
-
-	if i, ok := cache[name]; ok {
-		return v.Field(i)
-	}
-
-	return reflect.Zero(t)
-}
-
-// scan data to a struct's pointer according field name
-func (rs *Rows) ScanStructByName(dest interface{}) error {
-	vv := reflect.ValueOf(dest)
-	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
-		return errors.New("dest should be a struct's pointer")
-	}
-
-	cols, err := rs.Columns()
-	if err != nil {
-		return err
-	}
-
-	newDest := make([]interface{}, len(cols))
-	var v EmptyScanner
-	for j, name := range cols {
-		f := fieldByName(vv.Elem(), rs.Mapper.Table2Obj(name))
-		if f.IsValid() {
-			newDest[j] = f.Addr().Interface()
-		} else {
-			newDest[j] = &v
-		}
-	}
-
-	return rs.Rows.Scan(newDest...)
-}
-
-type cacheStruct struct {
-	value reflect.Value
-	idx   int
-}
-
-var (
-	reflectCache      = make(map[reflect.Type]*cacheStruct)
-	reflectCacheMutex sync.RWMutex
-)
-
-func ReflectNew(typ reflect.Type) reflect.Value {
-	reflectCacheMutex.RLock()
-	cs, ok := reflectCache[typ]
-	reflectCacheMutex.RUnlock()
-
-	const newSize = 200
-
-	if !ok || cs.idx+1 > newSize-1 {
-		cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), newSize, newSize), 0}
-		reflectCacheMutex.Lock()
-		reflectCache[typ] = cs
-		reflectCacheMutex.Unlock()
-	} else {
-		reflectCacheMutex.Lock()
-		cs.idx = cs.idx + 1
-		reflectCacheMutex.Unlock()
-	}
-	return cs.value.Index(cs.idx).Addr()
-}
-
-// scan data to a slice's pointer, slice's length should equal to columns' number
-func (rs *Rows) ScanSlice(dest interface{}) error {
-	vv := reflect.ValueOf(dest)
-	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Slice {
-		return errors.New("dest should be a slice's pointer")
-	}
-
-	vvv := vv.Elem()
-	cols, err := rs.Columns()
-	if err != nil {
-		return err
-	}
-
-	newDest := make([]interface{}, len(cols))
-
-	for j := 0; j < len(cols); j++ {
-		if j >= vvv.Len() {
-			newDest[j] = reflect.New(vvv.Type().Elem()).Interface()
-		} else {
-			newDest[j] = vvv.Index(j).Addr().Interface()
-		}
-	}
-
-	err = rs.Rows.Scan(newDest...)
-	if err != nil {
-		return err
-	}
-
-	srcLen := vvv.Len()
-	for i := srcLen; i < len(cols); i++ {
-		vvv = reflect.Append(vvv, reflect.ValueOf(newDest[i]).Elem())
-	}
-	return nil
-}
-
-// scan data to a map's pointer
-func (rs *Rows) ScanMap(dest interface{}) error {
-	vv := reflect.ValueOf(dest)
-	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
-		return errors.New("dest should be a map's pointer")
-	}
-
-	cols, err := rs.Columns()
-	if err != nil {
-		return err
-	}
-
-	newDest := make([]interface{}, len(cols))
-	vvv := vv.Elem()
-
-	for i, _ := range cols {
-		newDest[i] = ReflectNew(vvv.Type().Elem()).Interface()
-		//v := reflect.New(vvv.Type().Elem())
-		//newDest[i] = v.Interface()
-	}
-
-	err = rs.Rows.Scan(newDest...)
-	if err != nil {
-		return err
-	}
-
-	for i, name := range cols {
-		vname := reflect.ValueOf(name)
-		vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
-	}
-
-	return nil
-}
-
-/*func (rs *Rows) ScanMap(dest interface{}) error {
-	vv := reflect.ValueOf(dest)
-	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
-		return errors.New("dest should be a map's pointer")
-	}
-
-	cols, err := rs.Columns()
-	if err != nil {
-		return err
-	}
-
-	newDest := make([]interface{}, len(cols))
-	err = rs.ScanSlice(newDest)
-	if err != nil {
-		return err
-	}
-
-	vvv := vv.Elem()
-
-	for i, name := range cols {
-		vname := reflect.ValueOf(name)
-		vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
-	}
-
-	return nil
-}*/
-
 type Tx struct {
 	*sql.Tx
 	Mapper IMapper

+ 380 - 0
rows.go

@@ -0,0 +1,380 @@
+package core
+
+import (
+	"database/sql"
+	"errors"
+	"reflect"
+	"sync"
+)
+
+type Rows struct {
+	*sql.Rows
+	Mapper IMapper
+}
+
+func (rs *Rows) ToMapString() ([]map[string]string, error) {
+	cols, err := rs.Columns()
+	if err != nil {
+		return nil, err
+	}
+
+	var results = make([]map[string]string, 0, 10)
+	for rs.Next() {
+		var record = make(map[string]string, len(cols))
+		err = rs.ScanMap(&record)
+		if err != nil {
+			return nil, err
+		}
+		results = append(results, record)
+	}
+	return results, nil
+}
+
+// scan data to a struct's pointer according field index
+func (rs *Rows) ScanStructByIndex(dest ...interface{}) error {
+	if len(dest) == 0 {
+		return errors.New("at least one struct")
+	}
+
+	vvvs := make([]reflect.Value, len(dest))
+	for i, s := range dest {
+		vv := reflect.ValueOf(s)
+		if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
+			return errors.New("dest should be a struct's pointer")
+		}
+
+		vvvs[i] = vv.Elem()
+	}
+
+	cols, err := rs.Columns()
+	if err != nil {
+		return err
+	}
+	newDest := make([]interface{}, len(cols))
+
+	var i = 0
+	for _, vvv := range vvvs {
+		for j := 0; j < vvv.NumField(); j++ {
+			newDest[i] = vvv.Field(j).Addr().Interface()
+			i = i + 1
+		}
+	}
+
+	return rs.Rows.Scan(newDest...)
+}
+
+var (
+	fieldCache      = make(map[reflect.Type]map[string]int)
+	fieldCacheMutex sync.RWMutex
+)
+
+func fieldByName(v reflect.Value, name string) reflect.Value {
+	t := v.Type()
+	fieldCacheMutex.RLock()
+	cache, ok := fieldCache[t]
+	fieldCacheMutex.RUnlock()
+	if !ok {
+		cache = make(map[string]int)
+		for i := 0; i < v.NumField(); i++ {
+			cache[t.Field(i).Name] = i
+		}
+		fieldCacheMutex.Lock()
+		fieldCache[t] = cache
+		fieldCacheMutex.Unlock()
+	}
+
+	if i, ok := cache[name]; ok {
+		return v.Field(i)
+	}
+
+	return reflect.Zero(t)
+}
+
+// scan data to a struct's pointer according field name
+func (rs *Rows) ScanStructByName(dest interface{}) error {
+	vv := reflect.ValueOf(dest)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
+		return errors.New("dest should be a struct's pointer")
+	}
+
+	cols, err := rs.Columns()
+	if err != nil {
+		return err
+	}
+
+	newDest := make([]interface{}, len(cols))
+	var v EmptyScanner
+	for j, name := range cols {
+		f := fieldByName(vv.Elem(), rs.Mapper.Table2Obj(name))
+		if f.IsValid() {
+			newDest[j] = f.Addr().Interface()
+		} else {
+			newDest[j] = &v
+		}
+	}
+
+	return rs.Rows.Scan(newDest...)
+}
+
+type cacheStruct struct {
+	value reflect.Value
+	idx   int
+}
+
+var (
+	reflectCache      = make(map[reflect.Type]*cacheStruct)
+	reflectCacheMutex sync.RWMutex
+)
+
+func ReflectNew(typ reflect.Type) reflect.Value {
+	reflectCacheMutex.RLock()
+	cs, ok := reflectCache[typ]
+	reflectCacheMutex.RUnlock()
+
+	const newSize = 200
+
+	if !ok || cs.idx+1 > newSize-1 {
+		cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), newSize, newSize), 0}
+		reflectCacheMutex.Lock()
+		reflectCache[typ] = cs
+		reflectCacheMutex.Unlock()
+	} else {
+		reflectCacheMutex.Lock()
+		cs.idx = cs.idx + 1
+		reflectCacheMutex.Unlock()
+	}
+	return cs.value.Index(cs.idx).Addr()
+}
+
+// scan data to a slice's pointer, slice's length should equal to columns' number
+func (rs *Rows) ScanSlice(dest interface{}) error {
+	vv := reflect.ValueOf(dest)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Slice {
+		return errors.New("dest should be a slice's pointer")
+	}
+
+	vvv := vv.Elem()
+	cols, err := rs.Columns()
+	if err != nil {
+		return err
+	}
+
+	newDest := make([]interface{}, len(cols))
+
+	for j := 0; j < len(cols); j++ {
+		if j >= vvv.Len() {
+			newDest[j] = reflect.New(vvv.Type().Elem()).Interface()
+		} else {
+			newDest[j] = vvv.Index(j).Addr().Interface()
+		}
+	}
+
+	err = rs.Rows.Scan(newDest...)
+	if err != nil {
+		return err
+	}
+
+	srcLen := vvv.Len()
+	for i := srcLen; i < len(cols); i++ {
+		vvv = reflect.Append(vvv, reflect.ValueOf(newDest[i]).Elem())
+	}
+	return nil
+}
+
+// scan data to a map's pointer
+func (rs *Rows) ScanMap(dest interface{}) error {
+	vv := reflect.ValueOf(dest)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
+		return errors.New("dest should be a map's pointer")
+	}
+
+	cols, err := rs.Columns()
+	if err != nil {
+		return err
+	}
+
+	newDest := make([]interface{}, len(cols))
+	vvv := vv.Elem()
+
+	for i, _ := range cols {
+		newDest[i] = ReflectNew(vvv.Type().Elem()).Interface()
+		//v := reflect.New(vvv.Type().Elem())
+		//newDest[i] = v.Interface()
+	}
+
+	err = rs.Rows.Scan(newDest...)
+	if err != nil {
+		return err
+	}
+
+	for i, name := range cols {
+		vname := reflect.ValueOf(name)
+		vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
+	}
+
+	return nil
+}
+
+/*func (rs *Rows) ScanMap(dest interface{}) error {
+	vv := reflect.ValueOf(dest)
+	if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
+		return errors.New("dest should be a map's pointer")
+	}
+
+	cols, err := rs.Columns()
+	if err != nil {
+		return err
+	}
+
+	newDest := make([]interface{}, len(cols))
+	err = rs.ScanSlice(newDest)
+	if err != nil {
+		return err
+	}
+
+	vvv := vv.Elem()
+
+	for i, name := range cols {
+		vname := reflect.ValueOf(name)
+		vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
+	}
+
+	return nil
+}*/
+type Row struct {
+	rows *Rows
+	// One of these two will be non-nil:
+	err error // deferred error for easy chaining
+}
+
+func (row *Row) Columns() ([]string, error) {
+	if row.err != nil {
+		return nil, row.err
+	}
+	return row.rows.Columns()
+}
+
+func (row *Row) Scan(dest ...interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	defer row.rows.Close()
+
+	for _, dp := range dest {
+		if _, ok := dp.(*sql.RawBytes); ok {
+			return errors.New("sql: RawBytes isn't allowed on Row.Scan")
+		}
+	}
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.Scan(dest...)
+	if err != nil {
+		return err
+	}
+	// Make sure the query can be processed to completion with no errors.
+	return row.rows.Close()
+}
+
+func (row *Row) ScanStructByName(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	defer row.rows.Close()
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.ScanStructByName(dest)
+	if err != nil {
+		return err
+	}
+	// Make sure the query can be processed to completion with no errors.
+	return row.rows.Close()
+}
+
+func (row *Row) ScanStructByIndex(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	defer row.rows.Close()
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.ScanStructByIndex(dest)
+	if err != nil {
+		return err
+	}
+	// Make sure the query can be processed to completion with no errors.
+	return row.rows.Close()
+}
+
+// scan data to a slice's pointer, slice's length should equal to columns' number
+func (row *Row) ScanSlice(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	defer row.rows.Close()
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.ScanSlice(dest)
+	if err != nil {
+		return err
+	}
+
+	// Make sure the query can be processed to completion with no errors.
+	return row.rows.Close()
+}
+
+// scan data to a map's pointer
+func (row *Row) ScanMap(dest interface{}) error {
+	if row.err != nil {
+		return row.err
+	}
+	defer row.rows.Close()
+
+	if !row.rows.Next() {
+		if err := row.rows.Err(); err != nil {
+			return err
+		}
+		return sql.ErrNoRows
+	}
+	err := row.rows.ScanMap(dest)
+	if err != nil {
+		return err
+	}
+
+	// Make sure the query can be processed to completion with no errors.
+	return row.rows.Close()
+}
+
+func (row *Row) ToMapString() (map[string]string, error) {
+	cols, err := row.Columns()
+	if err != nil {
+		return nil, err
+	}
+
+	var record = make(map[string]string, len(cols))
+	err = row.ScanMap(&record)
+	if err != nil {
+		return nil, err
+	}
+
+	return record, nil
+}