Because different types of databases default return column name case inconsistency, oracle default uppercase, mysql default lowercase, I want to adapt to different databases struct field mapping, try using db.MapperFunc function in oracle can not work properly, StructScan return missing destination name error
var DB *sqlx.DB
func InitDB() {
//db, err := sqlx.Connect("mysql", "xxxx")
db, err := sqlx.Connect("godror", "xxxxx")
if err != nil {
panic(err)
}
DB = db
DB.MapperFunc(DBMapper)
}
func DBMapper(s string) string {
switch DB.DriverName() {
case "mysql":
return strings.ToLower(s)
case "godror":
return strings.ToUpper(s)
case "sqlserver":
return strings.ToLower(s)
default:
return strings.ToLower(s)
}
}
type User struct {
Id int `db:"id"`
Username string `db:"username"`
Nickname string `db:"nickname"`
Password string `db:"password"`
Phone string `db:"phone"`
Email string `db:"email"`
}
func (u *User) ListByName(name string, db *sqlx.DB) (User, error) {
query := "select * from tuser where username = ?"
query = db.Rebind(query)
var user User
if err := db.QueryRowx(query, name).StructScan(&user); err != nil {
return user, err
}
return user, nil
}
I checked the source code and found that when scanning the data into the structure filed, the parseName function call mapFunc not correctly, souce code as follows:
func parseName(field reflect.StructField, tagName string, mapFunc, tagMapFunc mapf) (tag, fieldName string) {
// first, set the fieldName to the field's name
fieldName = field.Name
// if a mapFunc is set, use that to override the fieldName
if mapFunc != nil {
fieldName = mapFunc(fieldName)
}
// if there's no tag to look for, return the field name
if tagName == "" {
return "", fieldName
}
// if this tag is not set using the normal convention in the tag,
// then return the fieldname.. this check is done because according
// to the reflect documentation:
// If the tag does not have the conventional format,
// the value returned by Get is unspecified.
// which doesn't sound great.
if !strings.Contains(string(field.Tag), tagName+":") {
return "", fieldName
}
// at this point we're fairly sure that we have a tag, so lets pull it out
tag = field.Tag.Get(tagName)
// if we have a mapper function, call it on the whole tag
// XXX: this is a change from the old version, which pulled out the name
// before the tagMapFunc could be run, but I think this is the right way
if tagMapFunc != nil {
tag = tagMapFunc(tag)
}
// finally, split the options from the name
parts := strings.Split(tag, ",")
@ fieldName = parts[0] //here mapFunc is not called
return tag, fieldName
}
Because different types of databases default return column name case inconsistency, oracle default uppercase, mysql default lowercase, I want to adapt to different databases struct field mapping, try using db.MapperFunc function in oracle can not work properly, StructScan return missing destination name error
I checked the source code and found that when scanning the data into the structure filed, the parseName function call mapFunc not correctly, souce code as follows: