mirror of https://github.com/go-gorm/gorm.git
Create and drop view (#6097)
* create view * add comment * fix test * check param and add comment
This commit is contained in:
parent
391c961c7f
commit
a80707de9e
|
@ -23,6 +23,8 @@ var (
|
||||||
ErrModelValueRequired = errors.New("model value required")
|
ErrModelValueRequired = errors.New("model value required")
|
||||||
// ErrModelAccessibleFieldsRequired model accessible fields required
|
// ErrModelAccessibleFieldsRequired model accessible fields required
|
||||||
ErrModelAccessibleFieldsRequired = errors.New("model accessible fields required")
|
ErrModelAccessibleFieldsRequired = errors.New("model accessible fields required")
|
||||||
|
// ErrSubQueryRequired sub query required
|
||||||
|
ErrSubQueryRequired = errors.New("sub query required")
|
||||||
// ErrInvalidData unsupported data
|
// ErrInvalidData unsupported data
|
||||||
ErrInvalidData = errors.New("unsupported data")
|
ErrInvalidData = errors.New("unsupported data")
|
||||||
// ErrUnsupportedDriver unsupported driver
|
// ErrUnsupportedDriver unsupported driver
|
||||||
|
|
|
@ -30,9 +30,9 @@ func (db *DB) AutoMigrate(dst ...interface{}) error {
|
||||||
|
|
||||||
// ViewOption view option
|
// ViewOption view option
|
||||||
type ViewOption struct {
|
type ViewOption struct {
|
||||||
Replace bool
|
Replace bool // If true, exec `CREATE`. If false, exec `CREATE OR REPLACE`
|
||||||
CheckOption string
|
CheckOption string // optional. e.g. `WITH [ CASCADED | LOCAL ] CHECK OPTION`
|
||||||
Query *DB
|
Query *DB // required subquery.
|
||||||
}
|
}
|
||||||
|
|
||||||
// ColumnType column type interface
|
// ColumnType column type interface
|
||||||
|
|
|
@ -557,14 +557,44 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
|
||||||
return columnTypes, execErr
|
return columnTypes, execErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateView create view
|
// CreateView create view from Query in gorm.ViewOption.
|
||||||
|
// Query in gorm.ViewOption is a [subquery]
|
||||||
|
//
|
||||||
|
// // CREATE VIEW `user_view` AS SELECT * FROM `users` WHERE age > 20
|
||||||
|
// q := DB.Model(&User{}).Where("age > ?", 20)
|
||||||
|
// DB.Debug().Migrator().CreateView("user_view", gorm.ViewOption{Query: q})
|
||||||
|
//
|
||||||
|
// // CREATE OR REPLACE VIEW `users_view` AS SELECT * FROM `users` WITH CHECK OPTION
|
||||||
|
// q := DB.Model(&User{})
|
||||||
|
// DB.Debug().Migrator().CreateView("user_view", gorm.ViewOption{Query: q, Replace: true, CheckOption: "WITH CHECK OPTION"})
|
||||||
|
//
|
||||||
|
// [subquery]: https://gorm.io/docs/advanced_query.html#SubQuery
|
||||||
func (m Migrator) CreateView(name string, option gorm.ViewOption) error {
|
func (m Migrator) CreateView(name string, option gorm.ViewOption) error {
|
||||||
return gorm.ErrNotImplemented
|
if option.Query == nil {
|
||||||
|
return gorm.ErrSubQueryRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
sql := new(strings.Builder)
|
||||||
|
sql.WriteString("CREATE ")
|
||||||
|
if option.Replace {
|
||||||
|
sql.WriteString("OR REPLACE ")
|
||||||
|
}
|
||||||
|
sql.WriteString("VIEW ")
|
||||||
|
m.QuoteTo(sql, name)
|
||||||
|
sql.WriteString(" AS ")
|
||||||
|
|
||||||
|
m.DB.Statement.AddVar(sql, option.Query)
|
||||||
|
|
||||||
|
if option.CheckOption != "" {
|
||||||
|
sql.WriteString(" ")
|
||||||
|
sql.WriteString(option.CheckOption)
|
||||||
|
}
|
||||||
|
return m.DB.Exec(m.Explain(sql.String(), m.DB.Statement.Vars...)).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// DropView drop view
|
// DropView drop view
|
||||||
func (m Migrator) DropView(name string) error {
|
func (m Migrator) DropView(name string) error {
|
||||||
return gorm.ErrNotImplemented
|
return m.DB.Exec("DROP VIEW IF EXISTS ?", clause.Table{Name: name}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildConstraint(constraint *schema.Constraint) (sql string, results []interface{}) {
|
func buildConstraint(constraint *schema.Constraint) (sql string, results []interface{}) {
|
||||||
|
|
|
@ -1509,3 +1509,36 @@ func TestMigrateIgnoreRelations(t *testing.T) {
|
||||||
t.Errorf("RelationModel2 should not be migrated")
|
t.Errorf("RelationModel2 should not be migrated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMigrateView(t *testing.T) {
|
||||||
|
DB.Save(GetUser("joins-args-db", Config{Pets: 2}))
|
||||||
|
|
||||||
|
if err := DB.Migrator().CreateView("invalid_users_pets", gorm.ViewOption{Query: nil}); err != gorm.ErrSubQueryRequired {
|
||||||
|
t.Fatalf("no view should be created, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
query := DB.Model(&User{}).
|
||||||
|
Select("users.id as users_id, users.name as users_name, pets.id as pets_id, pets.name as pets_name").
|
||||||
|
Joins("inner join pets on pets.user_id = users.id")
|
||||||
|
|
||||||
|
if err := DB.Migrator().CreateView("users_pets", gorm.ViewOption{Query: query}); err != nil {
|
||||||
|
t.Fatalf("Failed to crate view, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
if err := DB.Table("users_pets").Count(&count).Error; err != nil {
|
||||||
|
t.Fatalf("should found created view")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := DB.Migrator().DropView("users_pets"); err != nil {
|
||||||
|
t.Fatalf("Failed to drop view, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
query = DB.Model(&User{}).Where("age > ?", 20)
|
||||||
|
if err := DB.Migrator().CreateView("users_view", gorm.ViewOption{Query: query}); err != nil {
|
||||||
|
t.Fatalf("Failed to crate view, got %v", err)
|
||||||
|
}
|
||||||
|
if err := DB.Migrator().DropView("users_view"); err != nil {
|
||||||
|
t.Fatalf("Failed to drop view, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue