package util import ( "database/sql" "errors" "fmt" "reflect" "strconv" "strings" ) func ScanStruct(rows *sql.Rows, dest interface{}) error { rv := reflect.ValueOf(dest) if rv.Kind() != reflect.Ptr { return errors.New("must pass a pointer, not a value, to StructScan destination") } if rv.IsNil() { return errors.New("nil pointer passed to StructScan destination") } direct := rv.Elem() dtype := direct.Type() if dtype.Kind() != reflect.Slice { return fmt.Errorf("expected %s but got %s", reflect.Slice, dtype.Kind()) } elemType := dtype.Elem() var ( field reflect.StructField fmap = map[string]TagIndex{} dbtagVal string tagSplits []string fimap = map[TagIndex]int{} ) cols, _ := rows.Columns() for i := 0; i < elemType.NumField(); i++ { field = elemType.Field(i) dbtagVal = field.Tag.Get("db") if dbtagVal == "null" { continue } tagIdx := TagIndex{} tagSplits = strings.Split(dbtagVal, ",") if len(tagSplits) > 1 { dbtagVal = tagSplits[0] if tagSplits[1] == "omitempty" { tagIdx.IsOmitEmpty = true } } if dbtagVal == "" { dbtagVal = field.Name } tagIdx.Idx = i fmap[dbtagVal] = tagIdx } var ( tempStr sql.NullString valArr []interface{} ) for rows.Next() { nelemVal := reflect.New(elemType) valArr = make([]interface{}, len(cols)) for i, col := range cols { if fieldIdx, ok := fmap[col]; !ok { valArr[i] = new(interface{}) } else { field = elemType.Field(fieldIdx.Idx) if fieldIdx.IsOmitEmpty { valArr[i] = &sql.NullString{} fimap[fieldIdx] = i } else { valArr[i] = nelemVal.Elem().Field(fieldIdx.Idx).Addr().Interface() } } } rows.Scan(valArr...) for k, v := range fimap { fval := reflect.ValueOf(valArr[v]) if fval.IsValid() { field := elemType.Field(k.Idx) dstFval := reflect.New(field.Type) tempStr = fval.Elem().Interface().(sql.NullString) if !tempStr.Valid { continue } switch field.Type.Kind() { case reflect.Float64: float, _ := strconv.ParseFloat(tempStr.String, 64) float = ToFix(float, 2) dstFval.Elem().Set(reflect.ValueOf(float)) case reflect.String: dstFval.Elem().Set(reflect.ValueOf(tempStr.String)) case reflect.Int: intVal, _ := strconv.ParseInt(tempStr.String, 10, 0) dstFval.Elem().Set(reflect.ValueOf(int(intVal))) } //fmt.Println(dstFval.Elem().Interface()) nelemVal.Elem().Field(k.Idx).Set(dstFval.Elem()) } } direct.Set(reflect.Append(direct, nelemVal.Elem())) } return nil }