Skip to content

Instantly share code, notes, and snippets.

@elwinar
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elwinar/79d206f12b6a97e6af43 to your computer and use it in GitHub Desktop.
Save elwinar/79d206f12b6a97e6af43 to your computer and use it in GitHub Desktop.
Proof of Concept: scan to pointer in go
package sqlx
import (
"bytes"
"database/sql"
"fmt"
"reflect"
"strconv"
"strings"
)
var (
mapper = NewMapperFunc("db", func (u string) string {
buf := bytes.NewBufferString("")
for i, v := range u {
if i > 0 && v >= 'A' && v <= 'Z' {
buf.WriteRune('_')
}
buf.WriteRune(v)
}
s := strings.ToLower(buf.String())
return s
})
)
// Scan a sql.Rows mapping NULL values to nil pointer into the destination
func NilScan(row *sql.Rows, dest interface{}) error {
destType := reflect.TypeOf(dest)
destValue := reflect.ValueOf(dest)
fieldMap := mapper.TypeMap(destType)
columns, _ := row.Columns()
values := make([]interface{}, len(columns))
for i := range values {
values[i] = &sql.NullString{}
}
err := row.Scan(values...)
if err != nil {
return err
}
for index, name := range columns {
if indexes, found := fieldMap[name]; found {
field := FieldByIndexes(destValue, indexes)
value := values[index].(*sql.NullString)
if value.Valid == false {
field.Set(reflect.Zero(field.Type()))
continue
}
switch field.Interface().(type) {
case *int64:
v, err := strconv.ParseInt(value.String, 10, 64)
if err != nil {
return fmt.Errorf("unable to parse \"%v\" as int", value.String)
}
field.Set(reflect.ValueOf(&v))
continue
case int64:
v, err := strconv.ParseInt(value.String, 10, 64)
if err != nil {
return fmt.Errorf("unable to parse \"%v\" as int", value.String)
}
field.SetInt(v)
continue
case *float64:
v, err := strconv.ParseFloat(value.String, 'f')
if err != nil {
return fmt.Errorf("unable to parse \"%v\" as float", value.String)
}
field.Set(reflect.ValueOf(&v))
continue
case float64:
v, err := strconv.ParseFloat(value.String, 'f')
if err != nil {
return fmt.Errorf("unable to parse \"%v\" as float", value.String)
}
field.SetFloat(v)
continue
case *string:
field.Set(reflect.ValueOf(&value.String))
continue
case string:
field.SetString(value.String)
continue
}
}
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment