mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 02:22:26 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			340 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			340 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package migrate
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 
 | |
| 	"github.com/uptrace/bun/migrate/sqlschema"
 | |
| )
 | |
| 
 | |
| // Operation encapsulates the request to change a database definition
 | |
| // and knowns which operation can revert it.
 | |
| //
 | |
| // It is useful to define "monolith" Operations whenever possible,
 | |
| // even though they a dialect may require several distinct steps to apply them.
 | |
| // For example, changing a primary key involves first dropping the old constraint
 | |
| // before generating the new one. Yet, this is only an implementation detail and
 | |
| // passing a higher-level ChangePrimaryKeyOp will give the dialect more information
 | |
| // about the applied change.
 | |
| //
 | |
| // Some operations might be irreversible due to technical limitations. Returning
 | |
| // a *comment from GetReverse() will add an explanatory note to the generate migation file.
 | |
| //
 | |
| // To declare dependency on another Operation, operations should implement
 | |
| // { DependsOn(Operation) bool } interface, which Changeset will use to resolve dependencies.
 | |
| type Operation interface {
 | |
| 	GetReverse() Operation
 | |
| }
 | |
| 
 | |
| // CreateTableOp creates a new table in the schema.
 | |
| //
 | |
| // It does not report dependency on any other migration and may be executed first.
 | |
| // Make sure the dialect does not include FOREIGN KEY constraints in the CREATE TABLE
 | |
| // statement, as those may potentially reference not-yet-existing columns/tables.
 | |
| type CreateTableOp struct {
 | |
| 	TableName string
 | |
| 	Model     interface{}
 | |
| }
 | |
| 
 | |
| var _ Operation = (*CreateTableOp)(nil)
 | |
| 
 | |
| func (op *CreateTableOp) GetReverse() Operation {
 | |
| 	return &DropTableOp{TableName: op.TableName}
 | |
| }
 | |
| 
 | |
| // DropTableOp drops a database table. This operation is not reversible.
 | |
| type DropTableOp struct {
 | |
| 	TableName string
 | |
| }
 | |
| 
 | |
| var _ Operation = (*DropTableOp)(nil)
 | |
| 
 | |
| func (op *DropTableOp) DependsOn(another Operation) bool {
 | |
| 	drop, ok := another.(*DropForeignKeyOp)
 | |
| 	return ok && drop.ForeignKey.DependsOnTable(op.TableName)
 | |
| }
 | |
| 
 | |
| // GetReverse for a DropTable returns a no-op migration. Logically, CreateTable is the reverse,
 | |
| // but DropTable does not have the table's definition to create one.
 | |
| func (op *DropTableOp) GetReverse() Operation {
 | |
| 	c := comment(fmt.Sprintf("WARNING: \"DROP TABLE %s\" cannot be reversed automatically because table definition is not available", op.TableName))
 | |
| 	return &c
 | |
| }
 | |
| 
 | |
| // RenameTableOp renames the table. Changing the "schema" part of the table's FQN (moving tables between schemas) is not allowed.
 | |
| type RenameTableOp struct {
 | |
| 	TableName string
 | |
| 	NewName   string
 | |
| }
 | |
| 
 | |
| var _ Operation = (*RenameTableOp)(nil)
 | |
| 
 | |
| func (op *RenameTableOp) GetReverse() Operation {
 | |
| 	return &RenameTableOp{
 | |
| 		TableName: op.NewName,
 | |
| 		NewName:   op.TableName,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // RenameColumnOp renames a column in the table. If the changeset includes a rename operation
 | |
| // for the column's table, it should be executed first.
 | |
| type RenameColumnOp struct {
 | |
| 	TableName string
 | |
| 	OldName   string
 | |
| 	NewName   string
 | |
| }
 | |
| 
 | |
| var _ Operation = (*RenameColumnOp)(nil)
 | |
| 
 | |
| func (op *RenameColumnOp) GetReverse() Operation {
 | |
| 	return &RenameColumnOp{
 | |
| 		TableName: op.TableName,
 | |
| 		OldName:   op.NewName,
 | |
| 		NewName:   op.OldName,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (op *RenameColumnOp) DependsOn(another Operation) bool {
 | |
| 	rename, ok := another.(*RenameTableOp)
 | |
| 	return ok && op.TableName == rename.NewName
 | |
| }
 | |
| 
 | |
| // AddColumnOp adds a new column to the table.
 | |
| type AddColumnOp struct {
 | |
| 	TableName  string
 | |
| 	ColumnName string
 | |
| 	Column     sqlschema.Column
 | |
| }
 | |
| 
 | |
| var _ Operation = (*AddColumnOp)(nil)
 | |
| 
 | |
| func (op *AddColumnOp) GetReverse() Operation {
 | |
| 	return &DropColumnOp{
 | |
| 		TableName:  op.TableName,
 | |
| 		ColumnName: op.ColumnName,
 | |
| 		Column:     op.Column,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // DropColumnOp drop a column from the table.
 | |
| //
 | |
| // While some dialects allow DROP CASCADE to drop dependent constraints,
 | |
| // explicit handling on constraints is preferred for transparency and debugging.
 | |
| // DropColumnOp depends on DropForeignKeyOp, DropPrimaryKeyOp, and ChangePrimaryKeyOp
 | |
| // if any of the constraints is defined on this table.
 | |
| type DropColumnOp struct {
 | |
| 	TableName  string
 | |
| 	ColumnName string
 | |
| 	Column     sqlschema.Column
 | |
| }
 | |
| 
 | |
| var _ Operation = (*DropColumnOp)(nil)
 | |
| 
 | |
| func (op *DropColumnOp) GetReverse() Operation {
 | |
| 	return &AddColumnOp{
 | |
| 		TableName:  op.TableName,
 | |
| 		ColumnName: op.ColumnName,
 | |
| 		Column:     op.Column,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (op *DropColumnOp) DependsOn(another Operation) bool {
 | |
| 	switch drop := another.(type) {
 | |
| 	case *DropForeignKeyOp:
 | |
| 		return drop.ForeignKey.DependsOnColumn(op.TableName, op.ColumnName)
 | |
| 	case *DropPrimaryKeyOp:
 | |
| 		return op.TableName == drop.TableName && drop.PrimaryKey.Columns.Contains(op.ColumnName)
 | |
| 	case *ChangePrimaryKeyOp:
 | |
| 		return op.TableName == drop.TableName && drop.Old.Columns.Contains(op.ColumnName)
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // AddForeignKey adds a new FOREIGN KEY constraint.
 | |
| type AddForeignKeyOp struct {
 | |
| 	ForeignKey     sqlschema.ForeignKey
 | |
| 	ConstraintName string
 | |
| }
 | |
| 
 | |
| var _ Operation = (*AddForeignKeyOp)(nil)
 | |
| 
 | |
| func (op *AddForeignKeyOp) TableName() string {
 | |
| 	return op.ForeignKey.From.TableName
 | |
| }
 | |
| 
 | |
| func (op *AddForeignKeyOp) DependsOn(another Operation) bool {
 | |
| 	switch another := another.(type) {
 | |
| 	case *RenameTableOp:
 | |
| 		return op.ForeignKey.DependsOnTable(another.TableName) || op.ForeignKey.DependsOnTable(another.NewName)
 | |
| 	case *CreateTableOp:
 | |
| 		return op.ForeignKey.DependsOnTable(another.TableName)
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (op *AddForeignKeyOp) GetReverse() Operation {
 | |
| 	return &DropForeignKeyOp{
 | |
| 		ForeignKey:     op.ForeignKey,
 | |
| 		ConstraintName: op.ConstraintName,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // DropForeignKeyOp drops a FOREIGN KEY constraint.
 | |
| type DropForeignKeyOp struct {
 | |
| 	ForeignKey     sqlschema.ForeignKey
 | |
| 	ConstraintName string
 | |
| }
 | |
| 
 | |
| var _ Operation = (*DropForeignKeyOp)(nil)
 | |
| 
 | |
| func (op *DropForeignKeyOp) TableName() string {
 | |
| 	return op.ForeignKey.From.TableName
 | |
| }
 | |
| 
 | |
| func (op *DropForeignKeyOp) GetReverse() Operation {
 | |
| 	return &AddForeignKeyOp{
 | |
| 		ForeignKey:     op.ForeignKey,
 | |
| 		ConstraintName: op.ConstraintName,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // AddUniqueConstraintOp adds new UNIQUE constraint to the table.
 | |
| type AddUniqueConstraintOp struct {
 | |
| 	TableName string
 | |
| 	Unique    sqlschema.Unique
 | |
| }
 | |
| 
 | |
| var _ Operation = (*AddUniqueConstraintOp)(nil)
 | |
| 
 | |
| func (op *AddUniqueConstraintOp) GetReverse() Operation {
 | |
| 	return &DropUniqueConstraintOp{
 | |
| 		TableName: op.TableName,
 | |
| 		Unique:    op.Unique,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (op *AddUniqueConstraintOp) DependsOn(another Operation) bool {
 | |
| 	switch another := another.(type) {
 | |
| 	case *AddColumnOp:
 | |
| 		return op.TableName == another.TableName && op.Unique.Columns.Contains(another.ColumnName)
 | |
| 	case *RenameTableOp:
 | |
| 		return op.TableName == another.NewName
 | |
| 	case *DropUniqueConstraintOp:
 | |
| 		// We want to drop the constraint with the same name before adding this one.
 | |
| 		return op.TableName == another.TableName && op.Unique.Name == another.Unique.Name
 | |
| 	default:
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| // DropUniqueConstraintOp drops a UNIQUE constraint.
 | |
| type DropUniqueConstraintOp struct {
 | |
| 	TableName string
 | |
| 	Unique    sqlschema.Unique
 | |
| }
 | |
| 
 | |
| var _ Operation = (*DropUniqueConstraintOp)(nil)
 | |
| 
 | |
| func (op *DropUniqueConstraintOp) DependsOn(another Operation) bool {
 | |
| 	if rename, ok := another.(*RenameTableOp); ok {
 | |
| 		return op.TableName == rename.NewName
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func (op *DropUniqueConstraintOp) GetReverse() Operation {
 | |
| 	return &AddUniqueConstraintOp{
 | |
| 		TableName: op.TableName,
 | |
| 		Unique:    op.Unique,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // ChangeColumnTypeOp set a new data type for the column.
 | |
| // The two types should be such that the data can be auto-casted from one to another.
 | |
| // E.g. reducing VARCHAR lenght is not possible in most dialects.
 | |
| // AutoMigrator does not enforce or validate these rules.
 | |
| type ChangeColumnTypeOp struct {
 | |
| 	TableName string
 | |
| 	Column    string
 | |
| 	From      sqlschema.Column
 | |
| 	To        sqlschema.Column
 | |
| }
 | |
| 
 | |
| var _ Operation = (*ChangeColumnTypeOp)(nil)
 | |
| 
 | |
| func (op *ChangeColumnTypeOp) GetReverse() Operation {
 | |
| 	return &ChangeColumnTypeOp{
 | |
| 		TableName: op.TableName,
 | |
| 		Column:    op.Column,
 | |
| 		From:      op.To,
 | |
| 		To:        op.From,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // DropPrimaryKeyOp drops the table's PRIMARY KEY.
 | |
| type DropPrimaryKeyOp struct {
 | |
| 	TableName  string
 | |
| 	PrimaryKey sqlschema.PrimaryKey
 | |
| }
 | |
| 
 | |
| var _ Operation = (*DropPrimaryKeyOp)(nil)
 | |
| 
 | |
| func (op *DropPrimaryKeyOp) GetReverse() Operation {
 | |
| 	return &AddPrimaryKeyOp{
 | |
| 		TableName:  op.TableName,
 | |
| 		PrimaryKey: op.PrimaryKey,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // AddPrimaryKeyOp adds a new PRIMARY KEY to the table.
 | |
| type AddPrimaryKeyOp struct {
 | |
| 	TableName  string
 | |
| 	PrimaryKey sqlschema.PrimaryKey
 | |
| }
 | |
| 
 | |
| var _ Operation = (*AddPrimaryKeyOp)(nil)
 | |
| 
 | |
| func (op *AddPrimaryKeyOp) GetReverse() Operation {
 | |
| 	return &DropPrimaryKeyOp{
 | |
| 		TableName:  op.TableName,
 | |
| 		PrimaryKey: op.PrimaryKey,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (op *AddPrimaryKeyOp) DependsOn(another Operation) bool {
 | |
| 	switch another := another.(type) {
 | |
| 	case *AddColumnOp:
 | |
| 		return op.TableName == another.TableName && op.PrimaryKey.Columns.Contains(another.ColumnName)
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // ChangePrimaryKeyOp changes the PRIMARY KEY of the table.
 | |
| type ChangePrimaryKeyOp struct {
 | |
| 	TableName string
 | |
| 	Old       sqlschema.PrimaryKey
 | |
| 	New       sqlschema.PrimaryKey
 | |
| }
 | |
| 
 | |
| var _ Operation = (*AddPrimaryKeyOp)(nil)
 | |
| 
 | |
| func (op *ChangePrimaryKeyOp) GetReverse() Operation {
 | |
| 	return &ChangePrimaryKeyOp{
 | |
| 		TableName: op.TableName,
 | |
| 		Old:       op.New,
 | |
| 		New:       op.Old,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // comment denotes an Operation that cannot be executed.
 | |
| //
 | |
| // Operations, which cannot be reversed due to current technical limitations,
 | |
| // may return &comment with a helpful message from their GetReverse() method.
 | |
| //
 | |
| // Chnagelog should skip it when applying operations or output as log message,
 | |
| // and write it as an SQL comment when creating migration files.
 | |
| type comment string
 | |
| 
 | |
| var _ Operation = (*comment)(nil)
 | |
| 
 | |
| func (c *comment) GetReverse() Operation { return c }
 |