123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- // Copyright (c) 2012-present The upper.io/db authors. All rights reserved.
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
- package sqlbuilder
-
- import (
- "reflect"
-
- "upper.io/db.v3"
- "upper.io/db.v3/lib/reflectx"
- )
-
- type hasConvertValues interface {
- ConvertValues(values []interface{}) []interface{}
- }
-
- var mapper = reflectx.NewMapper("db")
-
- // fetchRow receives a *sql.Rows value and tries to map all the rows into a
- // single struct given by the pointer `dst`.
- func fetchRow(iter *iterator, dst interface{}) error {
- var columns []string
- var err error
-
- rows := iter.cursor
-
- dstv := reflect.ValueOf(dst)
-
- if dstv.IsNil() || dstv.Kind() != reflect.Ptr {
- return ErrExpectingPointer
- }
-
- itemV := dstv.Elem()
-
- if columns, err = rows.Columns(); err != nil {
- return err
- }
-
- reset(dst)
-
- next := rows.Next()
-
- if next == false {
- if err = rows.Err(); err != nil {
- return err
- }
- return db.ErrNoMoreRows
- }
-
- itemT := itemV.Type()
- item, err := fetchResult(iter, itemT, columns)
-
- if err != nil {
- return err
- }
-
- if itemT.Kind() == reflect.Ptr {
- itemV.Set(item)
- } else {
- itemV.Set(reflect.Indirect(item))
- }
-
- return nil
- }
-
- // fetchRows receives a *sql.Rows value and tries to map all the rows into a
- // slice of structs given by the pointer `dst`.
- func fetchRows(iter *iterator, dst interface{}) error {
- var err error
- rows := iter.cursor
- defer rows.Close()
-
- // Destination.
- dstv := reflect.ValueOf(dst)
-
- if dstv.IsNil() || dstv.Kind() != reflect.Ptr {
- return ErrExpectingPointer
- }
-
- if dstv.Elem().Kind() != reflect.Slice {
- return ErrExpectingSlicePointer
- }
-
- if dstv.Kind() != reflect.Ptr || dstv.Elem().Kind() != reflect.Slice || dstv.IsNil() {
- return ErrExpectingSliceMapStruct
- }
-
- var columns []string
- if columns, err = rows.Columns(); err != nil {
- return err
- }
-
- slicev := dstv.Elem()
- itemT := slicev.Type().Elem()
-
- reset(dst)
-
- for rows.Next() {
- item, err := fetchResult(iter, itemT, columns)
- if err != nil {
- return err
- }
- if itemT.Kind() == reflect.Ptr {
- slicev = reflect.Append(slicev, item)
- } else {
- slicev = reflect.Append(slicev, reflect.Indirect(item))
- }
- }
-
- dstv.Elem().Set(slicev)
-
- return nil
- }
-
- func fetchResult(iter *iterator, itemT reflect.Type, columns []string) (reflect.Value, error) {
- var item reflect.Value
- var err error
- rows := iter.cursor
-
- objT := itemT
-
- switch objT.Kind() {
- case reflect.Map:
- item = reflect.MakeMap(objT)
- case reflect.Struct:
- item = reflect.New(objT)
- case reflect.Ptr:
- objT = itemT.Elem()
- if objT.Kind() != reflect.Struct {
- return item, ErrExpectingMapOrStruct
- }
- item = reflect.New(objT)
- default:
- return item, ErrExpectingMapOrStruct
- }
-
- switch objT.Kind() {
- case reflect.Struct:
-
- values := make([]interface{}, len(columns))
- typeMap := mapper.TypeMap(itemT)
- fieldMap := typeMap.Names
-
- for i, k := range columns {
- fi, ok := fieldMap[k]
- if !ok {
- values[i] = new(interface{})
- continue
- }
-
- // Check for deprecated jsonb tag.
- if _, hasJSONBTag := fi.Options["jsonb"]; hasJSONBTag {
- return item, errDeprecatedJSONBTag
- }
-
- f := reflectx.FieldByIndexes(item, fi.Index)
- values[i] = f.Addr().Interface()
-
- if u, ok := values[i].(db.Unmarshaler); ok {
- values[i] = scanner{u}
- }
- }
-
- if converter, ok := iter.sess.(hasConvertValues); ok {
- values = converter.ConvertValues(values)
- }
-
- if err = rows.Scan(values...); err != nil {
- return item, err
- }
- case reflect.Map:
-
- columns, err := rows.Columns()
- if err != nil {
- return item, err
- }
-
- values := make([]interface{}, len(columns))
- for i := range values {
- if itemT.Elem().Kind() == reflect.Interface {
- values[i] = new(interface{})
- } else {
- values[i] = reflect.New(itemT.Elem()).Interface()
- }
- }
-
- if err = rows.Scan(values...); err != nil {
- return item, err
- }
-
- for i, column := range columns {
- item.SetMapIndex(reflect.ValueOf(column), reflect.Indirect(reflect.ValueOf(values[i])))
- }
- }
-
- return item, nil
- }
-
- func reset(data interface{}) error {
- // Resetting element.
- v := reflect.ValueOf(data).Elem()
- t := v.Type()
-
- var z reflect.Value
-
- switch v.Kind() {
- case reflect.Slice:
- z = reflect.MakeSlice(t, 0, v.Cap())
- default:
- z = reflect.Zero(t)
- }
-
- v.Set(z)
- return nil
- }
|