From cbebcf6d6fe4961d6f0ce4115f97301a942bd9ce Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Fri, 22 May 2015 11:13:14 +0800 Subject: [PATCH 01/10] Quote db name when create primary keys --- scope_private.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scope_private.go b/scope_private.go index 4ecefe3a..63fcea46 100644 --- a/scope_private.go +++ b/scope_private.go @@ -475,7 +475,7 @@ func (scope *Scope) createTable() *Scope { } if field.IsPrimaryKey { - primaryKeys = append(primaryKeys, field.DBName) + primaryKeys = append(primaryKeys, scope.Quote(field.DBName)) } scope.createJoinTable(field) } From b96ca76e5924c4f83d9bac72415dfe754e2812bd Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Wed, 27 May 2015 12:19:48 +0800 Subject: [PATCH 02/10] Set table name handler --- main.go | 4 ---- model_struct.go | 36 +++++++++++++++++++++--------------- scope.go | 7 +------ 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/main.go b/main.go index bf8acbae..181722fd 100644 --- a/main.go +++ b/main.go @@ -485,7 +485,3 @@ func (s *DB) SetJoinTableHandler(source interface{}, column string, handler Join } } } - -func (s *DB) SetTableNameHandler(source interface{}, handler func(*DB) string) { - s.NewScope(source).GetModelStruct().TableName = handler -} diff --git a/model_struct.go b/model_struct.go index a70489fc..10423ae2 100644 --- a/model_struct.go +++ b/model_struct.go @@ -13,11 +13,19 @@ import ( var modelStructs = map[reflect.Type]*ModelStruct{} +var DefaultTableNameHandler = func(db *DB, defaultTableName string) string { + return defaultTableName +} + type ModelStruct struct { - PrimaryFields []*StructField - StructFields []*StructField - ModelType reflect.Type - TableName func(*DB) string + PrimaryFields []*StructField + StructFields []*StructField + ModelType reflect.Type + defaultTableName string +} + +func (s ModelStruct) TableName(db *DB) string { + return DefaultTableNameHandler(db, s.defaultTableName) } type StructField struct { @@ -94,14 +102,14 @@ func (scope *Scope) GetModelStruct() *ModelStruct { } // Set tablename - if fm := reflect.New(scopeType).MethodByName("TableName"); fm.IsValid() { - if results := fm.Call([]reflect.Value{}); len(results) > 0 { - if name, ok := results[0].Interface().(string); ok { - modelStruct.TableName = func(*DB) string { - return name - } - } - } + type tabler interface { + TableName() string + } + + if tabler, ok := reflect.New(scopeType).Interface().(interface { + TableName() string + }); ok { + modelStruct.defaultTableName = tabler.TableName() } else { name := ToDBName(scopeType.Name()) if scope.db == nil || !scope.db.parent.singularTable { @@ -112,9 +120,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct { } } - modelStruct.TableName = func(*DB) string { - return name - } + modelStruct.defaultTableName = name } // Get all fields diff --git a/scope.go b/scope.go index 54bf5c84..960a653c 100644 --- a/scope.go +++ b/scope.go @@ -251,12 +251,7 @@ func (scope *Scope) TableName() string { return tabler.TableName(scope.db) } - if scope.GetModelStruct().TableName != nil { - return scope.GetModelStruct().TableName(scope.db) - } - - scope.Err(errors.New("wrong table name")) - return "" + return scope.GetModelStruct().TableName(scope.db) } func (scope *Scope) QuotedTableName() (name string) { From 331d8ceabdff5ebf4dc2aba2ccc19772ba2db17f Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Mon, 1 Jun 2015 11:04:11 +0800 Subject: [PATCH 03/10] Don't overwrite primary key if already it is already exist --- callback_create.go | 2 +- main_test.go | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/callback_create.go b/callback_create.go index b21df08b..e7ec40bb 100644 --- a/callback_create.go +++ b/callback_create.go @@ -70,7 +70,7 @@ func Create(scope *Scope) { id, err := result.LastInsertId() if scope.Err(err) == nil { scope.db.RowsAffected, _ = result.RowsAffected() - if primaryField != nil { + if primaryField != nil && primaryField.IsBlank { scope.Err(scope.SetColumn(primaryField, id)) } } diff --git a/main_test.go b/main_test.go index b547534c..666ba564 100644 --- a/main_test.go +++ b/main_test.go @@ -61,6 +61,18 @@ func init() { runMigration() } +func TestStringPrimaryKey(t *testing.T) { + type UUIDStruct struct { + ID string `gorm:"primary_key"` + Name string + } + + data := UUIDStruct{ID: "uuid", Name: "hello"} + if err := DB.Save(&data).Error; err != nil || data.ID != "uuid" { + t.Errorf("string primary key should not be populated") + } +} + func TestExceptionsWithInvalidSql(t *testing.T) { var columns []string if DB.Where("sdsd.zaaa = ?", "sd;;;aa").Pluck("aaa", &columns).Error == nil { From 58f379b098dfaa2614b5705ed97dc7ed5d01d26e Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Mon, 1 Jun 2015 11:17:51 +0800 Subject: [PATCH 04/10] Add auto migration --- main_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/main_test.go b/main_test.go index 666ba564..0dc5e337 100644 --- a/main_test.go +++ b/main_test.go @@ -66,6 +66,7 @@ func TestStringPrimaryKey(t *testing.T) { ID string `gorm:"primary_key"` Name string } + DB.AutoMigrate(&UUIDStruct{}) data := UUIDStruct{ID: "uuid", Name: "hello"} if err := DB.Save(&data).Error; err != nil || data.ID != "uuid" { From 4fd6e62a022815853eecdd556add706ffd005b54 Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Mon, 1 Jun 2015 14:02:15 +0800 Subject: [PATCH 05/10] Add unsigned support for mysql --- mysql.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mysql.go b/mysql.go index e37a23e0..a5e4a459 100644 --- a/mysql.go +++ b/mysql.go @@ -14,16 +14,26 @@ func (mysql) SqlTag(value reflect.Value, size int, autoIncrease bool) string { switch value.Kind() { case reflect.Bool: return "boolean" - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: if autoIncrease { return "int AUTO_INCREMENT" } return "int" - case reflect.Int64, reflect.Uint64: + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr: + if autoIncrease { + return "int unsigned AUTO_INCREMENT" + } + return "int unsigned" + case reflect.Int64: if autoIncrease { return "bigint AUTO_INCREMENT" } return "bigint" + case reflect.Uint64: + if autoIncrease { + return "bigint unsigned AUTO_INCREMENT" + } + return "bigint unsigned" case reflect.Float32, reflect.Float64: return "double" case reflect.String: From 65b42ad6f3fe491bc4ead1ab6439997419d7053b Mon Sep 17 00:00:00 2001 From: Soroush Mirzaei Date: Mon, 1 Jun 2015 14:20:23 +0430 Subject: [PATCH 06/10] Fixed the "Query callbacks" URL. Changed it to point to `callback_query.go` instead of `callback_create.go`. --- doc/development.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development.md b/doc/development.md index 674cfc43..08166661 100644 --- a/doc/development.md +++ b/doc/development.md @@ -61,7 +61,7 @@ Gorm is powered by callbacks, so you could refer below links to learn how to wri [Update callbacks](https://github.com/jinzhu/gorm/blob/master/callback_update.go) -[Query callbacks](https://github.com/jinzhu/gorm/blob/master/callback_create.go) +[Query callbacks](https://github.com/jinzhu/gorm/blob/master/callback_query.go) [Delete callbacks](https://github.com/jinzhu/gorm/blob/master/callback_delete.go) From 0b8c9f29a9e28708c17e0ef1aed71487e8bd356c Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Thu, 4 Jun 2015 12:10:09 +0800 Subject: [PATCH 07/10] Find Field by db name also --- scope.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scope.go b/scope.go index 960a653c..11bad777 100644 --- a/scope.go +++ b/scope.go @@ -273,7 +273,7 @@ func (scope *Scope) CombinedConditionSql() string { func (scope *Scope) FieldByName(name string) (field *Field, ok bool) { for _, field := range scope.Fields() { - if field.Name == name { + if field.Name == name || field.DBName == name { return field, true } } From 94f56e646bb69d8128545a1b0cee90eb783bafca Mon Sep 17 00:00:00 2001 From: Bojan Petrovic Date: Thu, 4 Jun 2015 13:47:25 +0200 Subject: [PATCH 08/10] Fix Create when dialect does not support last inserted id --- callback_create.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/callback_create.go b/callback_create.go index e7ec40bb..9f0c9bc2 100644 --- a/callback_create.go +++ b/callback_create.go @@ -77,7 +77,7 @@ func Create(scope *Scope) { } } else { if primaryField == nil { - if results, err := scope.SqlDB().Exec(scope.Sql, scope.SqlVars...); err != nil { + if results, err := scope.SqlDB().Exec(scope.Sql, scope.SqlVars...); err == nil { scope.db.RowsAffected, _ = results.RowsAffected() } } else if scope.Err(scope.SqlDB().QueryRow(scope.Sql, scope.SqlVars...).Scan(primaryField.Field.Addr().Interface())) == nil { From d9faa4949cf3cc73602389ba5bbf95ea012ca9eb Mon Sep 17 00:00:00 2001 From: Bojan Petrovic Date: Thu, 4 Jun 2015 14:23:57 +0200 Subject: [PATCH 09/10] Fix Create error reporting. --- callback_create.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/callback_create.go b/callback_create.go index 9f0c9bc2..7f21ed6a 100644 --- a/callback_create.go +++ b/callback_create.go @@ -79,9 +79,15 @@ func Create(scope *Scope) { if primaryField == nil { if results, err := scope.SqlDB().Exec(scope.Sql, scope.SqlVars...); err == nil { scope.db.RowsAffected, _ = results.RowsAffected() + } else { + scope.Err(err) + } + } else { + if err := scope.Err(scope.SqlDB().QueryRow(scope.Sql, scope.SqlVars...).Scan(primaryField.Field.Addr().Interface())); err == nil { + scope.db.RowsAffected = 1 + } else { + scope.Err(err) } - } else if scope.Err(scope.SqlDB().QueryRow(scope.Sql, scope.SqlVars...).Scan(primaryField.Field.Addr().Interface())) == nil { - scope.db.RowsAffected = 1 } } } From f05a6b37949f3a28f07debeaa25c14792323c7a8 Mon Sep 17 00:00:00 2001 From: crystalin Date: Fri, 5 Jun 2015 12:54:52 +0200 Subject: [PATCH 10/10] Support for preload of Struct Ptr This fixes the issue when preloading .Preload("Project.Repositories").Find(&[]User{}) with type User struct { Project *Project } type Project struct { Repositories []Repository } type Repository struct { ... } --- preload.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/preload.go b/preload.go index add077ab..f1c0fae5 100644 --- a/preload.go +++ b/preload.go @@ -216,13 +216,16 @@ func (scope *Scope) getColumnsAsScope(column string) *Scope { } fieldStruct, _ := modelType.FieldByName(column) var columns reflect.Value - if fieldStruct.Type.Kind() == reflect.Slice { + if fieldStruct.Type.Kind() == reflect.Slice || fieldStruct.Type.Kind() == reflect.Ptr { columns = reflect.New(reflect.SliceOf(reflect.PtrTo(fieldStruct.Type.Elem()))).Elem() } else { columns = reflect.New(reflect.SliceOf(reflect.PtrTo(fieldStruct.Type))).Elem() } for i := 0; i < values.Len(); i++ { column := reflect.Indirect(values.Index(i)).FieldByName(column) + if column.Kind() == reflect.Ptr { + column = column.Elem() + } if column.Kind() == reflect.Slice { for i := 0; i < column.Len(); i++ { columns = reflect.Append(columns, column.Index(i).Addr())