github.com/tobgu/qframe@v0.4.0/internal/io/sql/reader.go (about) 1 package sql 2 3 import ( 4 "database/sql" 5 6 "github.com/tobgu/qframe/qerrors" 7 "github.com/tobgu/qframe/types" 8 ) 9 10 // ReadSQL returns a named map of types.DataSlice for consumption 11 // by the qframe.New constructor. 12 func ReadSQL(rows *sql.Rows, conf SQLConfig) (map[string]types.DataSlice, []string, error) { 13 var ( 14 columns []interface{} 15 colNames []string 16 ) 17 for rows.Next() { 18 // Allocate columns for the returning query 19 if columns == nil { 20 names, err := rows.Columns() 21 if err != nil { 22 return nil, colNames, qerrors.New("ReadSQL Columns", err.Error()) 23 } 24 for _, name := range names { 25 col := &Column{precision: conf.Precision} 26 if conf.CoerceMap != nil { 27 fn, ok := conf.CoerceMap[name] 28 if ok { 29 col.coerce = fn(col) 30 } 31 } 32 columns = append(columns, col) 33 } 34 // ensure any column in the coercion map 35 // exists in the resulting columns or return 36 // an error explicitly. 37 if conf.CoerceMap != nil { 38 checkMap: 39 for name := range conf.CoerceMap { 40 for _, colName := range colNames { 41 if name == colName { 42 continue checkMap 43 } 44 return nil, colNames, qerrors.New("ReadSQL Columns", "column %s does not exist to coerce", name) 45 } 46 } 47 } 48 colNames = names 49 } 50 // Scan the result into our columns 51 err := rows.Scan(columns...) 52 if err != nil { 53 return nil, colNames, qerrors.New("ReadSQL Scan", err.Error()) 54 } 55 } 56 result := map[string]types.DataSlice{} 57 for i, column := range columns { 58 result[colNames[i]] = column.(*Column).Data() 59 } 60 return result, colNames, nil 61 }