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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 black-06
						black-06