|
- // Copyright 2019 The Xorm Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
-
- package core
-
- import (
- "database/sql"
- "errors"
- "reflect"
- "sync"
- )
-
- type Rows struct {
- *sql.Rows
- db *DB
- }
-
- 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.db.Mapper.Table2Obj(name))
- if f.IsValid() {
- newDest[j] = f.Addr().Interface()
- } else {
- newDest[j] = &v
- }
- }
-
- return rs.Rows.Scan(newDest...)
- }
-
- // 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] = rs.db.reflectNew(vvv.Type().Elem()).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
- }
-
- type Row struct {
- rows *Rows
- // One of these two will be non-nil:
- err error // deferred error for easy chaining
- }
-
- // ErrorRow return an error row
- func ErrorRow(err error) *Row {
- return &Row{
- err: err,
- }
- }
-
- // NewRow from rows
- func NewRow(rows *Rows, err error) *Row {
- return &Row{rows, err}
- }
-
- 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
- }
|