Add AutoMigrate Support

This commit is contained in:
Jinzhu 2013-11-07 11:42:36 +08:00
parent 5da8461161
commit 9b27735464
4 changed files with 71 additions and 13 deletions

View File

@ -14,6 +14,7 @@ Yet Another ORM library for Go, aims for developer friendly
* Automatically CreatedAt, UpdatedAt * Automatically CreatedAt, UpdatedAt
* Soft Delete * Soft Delete
* Create/Drop table from struct * Create/Drop table from struct
* Automating Migrations
* Dynamically set table name when search, create, update, delete... * Dynamically set table name when search, create, update, delete...
* Prevent SQL Injection * Prevent SQL Injection
* Goroutines friendly * Goroutines friendly
@ -97,6 +98,18 @@ db.CreateTable(User{})
db.DropTable(User{}) db.DropTable(User{})
``` ```
### Automating Migrations
Feel Free to update your struct, AutoMigrate will keep your database update to date.
FYI, AutoMigrate will only add new columns, won't change column's type or delete unused columns, to make sure gorm won't harm your data.
If table doesn't exist when AutoMigrate, it will run create table automatically.
```go
db.AutoMigrate(User{})
```
## Create ## Create
```go ```go

View File

@ -236,17 +236,17 @@ func (s *Chain) Or(querystring interface{}, args ...interface{}) *Chain {
} }
func (s *Chain) CreateTable(value interface{}) *Chain { func (s *Chain) CreateTable(value interface{}) *Chain {
s.do(value).createTable().exec() s.do(value).createTable()
return s return s
} }
func (s *Chain) DropTable(value interface{}) *Chain { func (s *Chain) DropTable(value interface{}) *Chain {
s.do(value).dropTable().exec() s.do(value).dropTable()
return s return s
} }
func (s *Chain) AutoMigrate(value interface{}) *Chain { func (s *Chain) AutoMigrate(value interface{}) *Chain {
s.do(value).autoMigrate().exec() s.do(value).autoMigrate()
return s return s
} }

26
do.go
View File

@ -715,6 +715,7 @@ func (s *Do) createTable() *Do {
s.tableName(), s.tableName(),
strings.Join(sqls, ","), strings.Join(sqls, ","),
) )
s.exec()
return s return s
} }
@ -723,13 +724,32 @@ func (s *Do) dropTable() *Do {
"DROP TABLE %v", "DROP TABLE %v",
s.tableName(), s.tableName(),
) )
s.exec()
return s return s
} }
func (s *Do) autoMigrate() *Do { func (s *Do) autoMigrate() *Do {
sql := fmt.Sprintf("SELECT column_name, data_type FROM information_schema.columns WHERE table_name = %v", s.tableName()) var table_name string
for _, field := range s.model.fields("other") { sql := fmt.Sprintf("SELECT table_name FROM INFORMATION_SCHEMA.tables where table_name = %v", s.addToVars(s.tableName()))
s.sql = fmt.Sprintf(sql+"and column_name = %v", field.DbName) s.db.QueryRow(sql, s.sqlVars...).Scan(&table_name)
s.sqlVars = []interface{}{}
// If table doesn't exist
if len(table_name) == 0 {
s.createTable()
} else {
for _, field := range s.model.fields("other") {
var column_name, data_type string
sql := fmt.Sprintf("SELECT column_name, data_type FROM information_schema.columns WHERE table_name = %v", s.addToVars(s.tableName()))
s.db.QueryRow(fmt.Sprintf(sql+" and column_name = %v", s.addToVars(field.DbName)), s.sqlVars...).Scan(&column_name, &data_type)
s.sqlVars = []interface{}{}
// If column doesn't exist
if len(column_name) == 0 {
s.sql = fmt.Sprintf("ALTER TABLE %v ADD %v %v", s.tableName(), field.DbName, field.SqlType)
s.exec()
}
}
} }
return s return s
} }

View File

@ -38,13 +38,12 @@ type CreditCard struct {
} }
type Email struct { type Email struct {
Id int64 Id int64
UserId int64 UserId int64
Email string Email string
Subscribed bool CreatedAt time.Time
CreatedAt time.Time UpdatedAt time.Time
UpdatedAt time.Time DeletedAt time.Time
DeletedAt time.Time
} }
type Address struct { type Address struct {
@ -1236,6 +1235,32 @@ func TestTableName(t *testing.T) {
} }
} }
type BigEmail struct {
Id int64
UserId int64
Email string
UserAgent string
RegisteredAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt time.Time
}
func (b BigEmail) TableName() string {
return "emails"
}
func TestAutoMigration(t *testing.T) { func TestAutoMigration(t *testing.T) {
db.AutoMigrate(Address{}) db.AutoMigrate(Address{})
if err := db.Table("emails").AutoMigrate(BigEmail{}).Error; err != nil {
t.Errorf("Auto Migrate should not raise any error", err)
}
db.Save(&BigEmail{Email: "jinzhu@example.org", UserAgent: "pc", RegisteredAt: time.Now()})
var big_email BigEmail
db.First(&big_email, "user_agent = ?", "pc")
if big_email.Email != "jinzhu@example.org" || big_email.UserAgent != "pc" || big_email.RegisteredAt.IsZero() {
t.Error("Big Emails should be saved and fetched correctly")
}
} }