func selectOne(arg interface{}) (sql []byte, params []interface{}, err error) {
if arg == nil {
err = errors.New("expected a pointer to a struct")
return
}
paramsMap, tableName, kIdcolumn, _ := elem(arg)
var sqlWhere string
sql = append(sql, []byte("SELECT ")...)
for colum, v := range paramsMap {
sql = append(sql, []byte(" "+colum+" ,")...)
if colum == kIdcolumn {
sqlWhere = " WHERE " + colum + " = ? "
params = append(params, v)
}
}
sql = sql[:len(sql)-1]
sql = append(sql, []byte("FROM "+tableName)...)
sql = append(sql, []byte(sqlWhere)...)
log.Println("===>", string(sql), params)
return
}
func (this *Mysql) selectOne(obj interface{}, query string, params ...interface{}) (*sql.Rows, error) {
if len(params) == 0 {
return nil, fmt.Errorf("params is nil")
}
tx, err := this.DB.Begin()
if err != nil {
return nil, err
}
rows, err := tx.Query(query, params...)
if err != nil {
return nil, err
}
filedCMap := filedColumnMapper(obj)
setFiled(obj, rows, filedCMap)
err = tx.Commit()
if err != nil {
return nil, err
}
return rows, nil
}
func filedColumnMapper(obj interface{}) map[string]string {
t := reflect.TypeOf(obj).Elem()
v := reflect.ValueOf(obj).Elem()
num := t.NumField()
filedCMap := make(map[string]string, num)
for i := 0; i < num; i++ {
if v.Field(i).CanInterface() {
var tn string
tf := t.Field(i)
kC := tf.Tag.Get(dbColumn)
if kC == "" {
kC = tf.Tag.Get(dbColumn)
if kC == "" {
tn = tf.Name
} else {
tn = kC
}
} else {
tn = kC
}
filedCMap[tn] = tf.Name
} else {
}
}
return filedCMap
}
func setFiled(obj interface{}, rows *sql.Rows, filedCMap map[string]string) {
cols, _ := rows.Columns()
buff := make([]interface{}, len(cols))
data := make([]string, len(cols))
for i, _ := range buff {
buff[i] = &data[i]
}
for rows.Next() {
rows.Scan(buff...)
}
t := reflect.TypeOf(obj).Elem()
v := reflect.ValueOf(obj).Elem()
for k, values := range data {
filedName := filedCMap[cols[k]]
if _, ok := t.FieldByName(filedName); ok {
vft := v.FieldByName(filedName)
switch vft.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
val, err := strconv.ParseInt(values, 10, 64)
if err == nil {
vft.SetInt(val)
}
case reflect.String:
vft.SetString(values)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
val, err := strconv.ParseUint(values, 10, 64)
if err == nil {
vft.SetUint(val)
}
case reflect.Float32, reflect.Float64:
val, err := strconv.ParseFloat(values, 64)
if err == nil {
vft.SetFloat(val)
}
case reflect.Bool:
val, err := strconv.ParseBool(values)
if err == nil {
vft.SetBool(val)
}
}
}
}
}
func (this *Mysql) SelectOne(obj interface{}) error {
query, param, err := selectOne(obj)
if err != nil {
return err
}
_, err = this.selectOne(obj, string(query), param...)
if err != nil {
return err
}
return nil
}