From eb26dcc5972cbb62fc989924aa8d5c22ce16f16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vytautas=20=C5=A0altenis?= Date: Wed, 30 Jul 2014 22:43:24 +0300 Subject: [PATCH] Add support for custom column names Fixes issue #26. --- README.md | 20 ++++++++++++++++++++ callback_query.go | 19 ++++++++++++++++++- main_test.go | 37 +++++++++++++++++++++++++++++++++++++ migration_test.go | 5 +++++ scope.go | 4 ++++ utils.go | 3 +++ 6 files changed, 87 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fdb86396..34317498 100644 --- a/README.md +++ b/README.md @@ -974,6 +974,26 @@ type Animal struct { } ``` +If your column names differ from the struct fields, you can specify them like this: + +```go +type Animal struct { // animals + AnimalId int64 `gorm:"column:beast_id; primary_key:yes"` + Birthday time.Time `gorm:"column:day_of_the_beast"` + Age int64 `gorm:"column:age_of_the_beast"` +} +``` + +Note that if your primary key has a custom column name, you will still have to +specify `primary_key`, even if your struct field is named `Id`: + +```go +type Foo struct { + Id int64 `gorm:"column:foo_id; primary_key:yes"` +} +``` + + ## More examples with query chain ```go diff --git a/callback_query.go b/callback_query.go index acdbde20..87a7f07c 100644 --- a/callback_query.go +++ b/callback_query.go @@ -41,6 +41,19 @@ func Query(scope *Scope) { return } + colToFieldMap := make(map[string]string) + if destType != nil && destType.Kind() == reflect.Struct { + for i := 0; i < destType.NumField(); i++ { + fieldName := destType.Field(i).Name + dbColumnName := ToSnake(fieldName) + settings := parseTagSetting(destType.Field(i).Tag.Get("gorm")) + if colName, ok := settings["COLUMN"]; ok && colName != "" { + dbColumnName = colName + } + colToFieldMap[dbColumnName] = fieldName + } + } + defer rows.Close() for rows.Next() { anyRecordFound = true @@ -52,7 +65,11 @@ func Query(scope *Scope) { columns, _ := rows.Columns() var values []interface{} for _, value := range columns { - field := elem.FieldByName(SnakeToUpperCamel(strings.ToLower(value))) + fieldName, ok := colToFieldMap[value] + if !ok { + fieldName = SnakeToUpperCamel(strings.ToLower(value)) + } + field := elem.FieldByName(fieldName) if field.IsValid() { values = append(values, field.Addr().Interface()) } else { diff --git a/main_test.go b/main_test.go index 10cd022b..8583a385 100644 --- a/main_test.go +++ b/main_test.go @@ -553,3 +553,40 @@ func BenchmarkRawSql(b *testing.B) { db.Exec(delete_sql, id) } } + +type MappedFields struct { + Id int64 `gorm:"column:mapped_id; primary_key:yes"` + Name string `gorm:"column:mapped_name"` + Date time.Time `gorm:"column:mapped_time"` +} + +func TestMappedFields(t *testing.T) { + col := "mapped_name" + db := db.Model("") + scope := db.NewScope(&MappedFields{}) + if !scope.Dialect().HasColumn(scope, "mapped_fields", col) { + t.Errorf("MappedFields should have column %s", col) + } + col = "mapped_id" + if scope.PrimaryKey() != col { + t.Errorf("MappedFields should have primary key %s, but got %q", col, scope.PrimaryKey()) + } + + expected := "foo" + mf := MappedFields{Id: 666, Name: expected, Date: time.Now()} + if !db.NewRecord(mf) || !db.NewRecord(&mf) { + t.Error("MappedFields should be new record before create") + } + if count := db.Save(&mf).RowsAffected; count != 1 { + t.Error("There should be one record be affected when create record") + } + + var mfs []MappedFields + db.Table("mapped_fields").Find(&mfs) + if len(mfs) != 1 { + t.Errorf("Query from specified table") + } + if len(mfs) > 0 && mfs[0].Name != expected { + t.Errorf("Failed to query MappedFields, expected %q, got %q", expected, mfs[0].Name) + } +} diff --git a/migration_test.go b/migration_test.go index 008329ae..49f33ced 100644 --- a/migration_test.go +++ b/migration_test.go @@ -20,6 +20,7 @@ func runMigration() { db.Exec("drop table animals") db.Exec("drop table user_languages") db.Exec("drop table languages") + db.Exec("drop table mapped_fields") if err := db.CreateTable(&Animal{}).Error; err != nil { panic(fmt.Sprintf("No error should happen when create table, but got %+v", err)) @@ -37,6 +38,10 @@ func runMigration() { panic(fmt.Sprintf("No error should happen when create table, but got %+v", err)) } + if err := db.CreateTable(MappedFields{}).Error; err != nil { + panic(fmt.Sprintf("No error should happen when create table, but got %+v", err)) + } + if err := db.AutoMigrate(Address{}).Error; err != nil { panic(fmt.Sprintf("No error should happen when create table, but got %+v", err)) } diff --git a/scope.go b/scope.go index ae203d1d..a7daea96 100644 --- a/scope.go +++ b/scope.go @@ -258,6 +258,10 @@ func (scope *Scope) fieldFromStruct(fieldStruct reflect.StructField) *Field { // Search for primary key tag identifier settings := parseTagSetting(fieldStruct.Tag.Get("gorm")) + if colName, ok := settings["COLUMN"]; ok && colName != "" { + field.DBName = colName + } + if scope.PrimaryKey() == field.DBName { field.IsPrimaryKey = true } diff --git a/utils.go b/utils.go index 50512143..2a10fa62 100644 --- a/utils.go +++ b/utils.go @@ -109,6 +109,9 @@ func GetPrimaryKey(value interface{}) string { settings := parseTagSetting(fieldStruct.Tag.Get("gorm")) if _, ok := settings["PRIMARY_KEY"]; ok { + if colName, ok2 := settings["COLUMN"]; ok2 { + return colName + } return fieldStruct.Name } else if fieldStruct.Name == "Id" { hasId = true