From b6000f5324c89106ab0cb6f6448117e6ecaadf64 Mon Sep 17 00:00:00 2001 From: black Date: Fri, 24 Feb 2023 17:14:34 +0800 Subject: [PATCH] check param and add comment --- errors.go | 2 ++ migrator.go | 6 +++--- migrator/migrator.go | 19 +++++++++++++++++-- tests/migrate_test.go | 12 ++++++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/errors.go b/errors.go index 0f486c5e..5bfd0f82 100644 --- a/errors.go +++ b/errors.go @@ -23,6 +23,8 @@ var ( ErrModelValueRequired = errors.New("model value required") // ErrModelAccessibleFieldsRequired 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 = errors.New("unsupported data") // ErrUnsupportedDriver unsupported driver diff --git a/migrator.go b/migrator.go index 6c4dc874..9c7cc2c4 100644 --- a/migrator.go +++ b/migrator.go @@ -30,9 +30,9 @@ func (db *DB) AutoMigrate(dst ...interface{}) error { // ViewOption view option type ViewOption struct { - Replace bool // CREATE [ OR REPLACE ] - CheckOption string // WITH [ CASCADED | LOCAL ] CHECK OPTION - Query *DB + Replace bool // If true, exec `CREATE`. If false, exec `CREATE OR REPLACE` + CheckOption string // optional. e.g. `WITH [ CASCADED | LOCAL ] CHECK OPTION` + Query *DB // required subquery. } // ColumnType column type interface diff --git a/migrator/migrator.go b/migrator/migrator.go index 0e7a99ab..389ce008 100644 --- a/migrator/migrator.go +++ b/migrator/migrator.go @@ -557,8 +557,23 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) { 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 { + if option.Query == nil { + return gorm.ErrSubQueryRequired + } + sql := new(strings.Builder) sql.WriteString("CREATE ") if option.Replace { @@ -574,7 +589,7 @@ func (m Migrator) CreateView(name string, option gorm.ViewOption) error { sql.WriteString(" ") sql.WriteString(option.CheckOption) } - return m.DB.Exec(sql.String()).Error + return m.DB.Exec(m.Explain(sql.String(), m.DB.Statement.Vars...)).Error } // DropView drop view diff --git a/tests/migrate_test.go b/tests/migrate_test.go index cf87cdf4..11a0afda 100644 --- a/tests/migrate_test.go +++ b/tests/migrate_test.go @@ -1513,6 +1513,10 @@ func TestMigrateIgnoreRelations(t *testing.T) { 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") @@ -1529,4 +1533,12 @@ func TestMigrateView(t *testing.T) { 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) + } }