mirror of https://github.com/go-gorm/gorm.git
Add AutoMigrate Support
This commit is contained in:
parent
5da8461161
commit
9b27735464
13
README.md
13
README.md
|
@ -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
|
||||||
|
|
6
chain.go
6
chain.go
|
@ -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
26
do.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
39
gorm_test.go
39
gorm_test.go
|
@ -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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue