github.com/astaxie/beego@v1.12.3/migration/ddl.go (about)

     1  // Copyright 2014 beego Author. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package migration
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/astaxie/beego/logs"
    21  )
    22  
    23  // Index struct defines the structure of Index Columns
    24  type Index struct {
    25  	Name string
    26  }
    27  
    28  // Unique struct defines a single unique key combination
    29  type Unique struct {
    30  	Definition string
    31  	Columns    []*Column
    32  }
    33  
    34  //Column struct defines a single column of a table
    35  type Column struct {
    36  	Name     string
    37  	Inc      string
    38  	Null     string
    39  	Default  string
    40  	Unsign   string
    41  	DataType string
    42  	remove   bool
    43  	Modify   bool
    44  }
    45  
    46  // Foreign struct defines a single foreign relationship
    47  type Foreign struct {
    48  	ForeignTable  string
    49  	ForeignColumn string
    50  	OnDelete      string
    51  	OnUpdate      string
    52  	Column
    53  }
    54  
    55  // RenameColumn struct allows renaming of columns
    56  type RenameColumn struct {
    57  	OldName     string
    58  	OldNull     string
    59  	OldDefault  string
    60  	OldUnsign   string
    61  	OldDataType string
    62  	NewName     string
    63  	Column
    64  }
    65  
    66  // CreateTable creates the table on system
    67  func (m *Migration) CreateTable(tablename, engine, charset string, p ...func()) {
    68  	m.TableName = tablename
    69  	m.Engine = engine
    70  	m.Charset = charset
    71  	m.ModifyType = "create"
    72  }
    73  
    74  // AlterTable set the ModifyType to alter
    75  func (m *Migration) AlterTable(tablename string) {
    76  	m.TableName = tablename
    77  	m.ModifyType = "alter"
    78  }
    79  
    80  // NewCol creates a new standard column and attaches it to m struct
    81  func (m *Migration) NewCol(name string) *Column {
    82  	col := &Column{Name: name}
    83  	m.AddColumns(col)
    84  	return col
    85  }
    86  
    87  //PriCol creates a new primary column and attaches it to m struct
    88  func (m *Migration) PriCol(name string) *Column {
    89  	col := &Column{Name: name}
    90  	m.AddColumns(col)
    91  	m.AddPrimary(col)
    92  	return col
    93  }
    94  
    95  //UniCol creates / appends columns to specified unique key and attaches it to m struct
    96  func (m *Migration) UniCol(uni, name string) *Column {
    97  	col := &Column{Name: name}
    98  	m.AddColumns(col)
    99  
   100  	uniqueOriginal := &Unique{}
   101  
   102  	for _, unique := range m.Uniques {
   103  		if unique.Definition == uni {
   104  			unique.AddColumnsToUnique(col)
   105  			uniqueOriginal = unique
   106  		}
   107  	}
   108  	if uniqueOriginal.Definition == "" {
   109  		unique := &Unique{Definition: uni}
   110  		unique.AddColumnsToUnique(col)
   111  		m.AddUnique(unique)
   112  	}
   113  
   114  	return col
   115  }
   116  
   117  //ForeignCol creates a new foreign column and returns the instance of column
   118  func (m *Migration) ForeignCol(colname, foreigncol, foreigntable string) (foreign *Foreign) {
   119  
   120  	foreign = &Foreign{ForeignColumn: foreigncol, ForeignTable: foreigntable}
   121  	foreign.Name = colname
   122  	m.AddForeign(foreign)
   123  	return foreign
   124  }
   125  
   126  //SetOnDelete sets the on delete of foreign
   127  func (foreign *Foreign) SetOnDelete(del string) *Foreign {
   128  	foreign.OnDelete = "ON DELETE" + del
   129  	return foreign
   130  }
   131  
   132  //SetOnUpdate sets the on update of foreign
   133  func (foreign *Foreign) SetOnUpdate(update string) *Foreign {
   134  	foreign.OnUpdate = "ON UPDATE" + update
   135  	return foreign
   136  }
   137  
   138  //Remove marks the columns to be removed.
   139  //it allows reverse m to create the column.
   140  func (c *Column) Remove() {
   141  	c.remove = true
   142  }
   143  
   144  //SetAuto enables auto_increment of column (can be used once)
   145  func (c *Column) SetAuto(inc bool) *Column {
   146  	if inc {
   147  		c.Inc = "auto_increment"
   148  	}
   149  	return c
   150  }
   151  
   152  //SetNullable sets the column to be null
   153  func (c *Column) SetNullable(null bool) *Column {
   154  	if null {
   155  		c.Null = ""
   156  
   157  	} else {
   158  		c.Null = "NOT NULL"
   159  	}
   160  	return c
   161  }
   162  
   163  //SetDefault sets the default value, prepend with "DEFAULT "
   164  func (c *Column) SetDefault(def string) *Column {
   165  	c.Default = "DEFAULT " + def
   166  	return c
   167  }
   168  
   169  //SetUnsigned sets the column to be unsigned int
   170  func (c *Column) SetUnsigned(unsign bool) *Column {
   171  	if unsign {
   172  		c.Unsign = "UNSIGNED"
   173  	}
   174  	return c
   175  }
   176  
   177  //SetDataType sets the dataType of the column
   178  func (c *Column) SetDataType(dataType string) *Column {
   179  	c.DataType = dataType
   180  	return c
   181  }
   182  
   183  //SetOldNullable allows reverting to previous nullable on reverse ms
   184  func (c *RenameColumn) SetOldNullable(null bool) *RenameColumn {
   185  	if null {
   186  		c.OldNull = ""
   187  
   188  	} else {
   189  		c.OldNull = "NOT NULL"
   190  	}
   191  	return c
   192  }
   193  
   194  //SetOldDefault allows reverting to previous default on reverse ms
   195  func (c *RenameColumn) SetOldDefault(def string) *RenameColumn {
   196  	c.OldDefault = def
   197  	return c
   198  }
   199  
   200  //SetOldUnsigned allows reverting to previous unsgined on reverse ms
   201  func (c *RenameColumn) SetOldUnsigned(unsign bool) *RenameColumn {
   202  	if unsign {
   203  		c.OldUnsign = "UNSIGNED"
   204  	}
   205  	return c
   206  }
   207  
   208  //SetOldDataType allows reverting to previous datatype on reverse ms
   209  func (c *RenameColumn) SetOldDataType(dataType string) *RenameColumn {
   210  	c.OldDataType = dataType
   211  	return c
   212  }
   213  
   214  //SetPrimary adds the columns to the primary key (can only be used any number of times in only one m)
   215  func (c *Column) SetPrimary(m *Migration) *Column {
   216  	m.Primary = append(m.Primary, c)
   217  	return c
   218  }
   219  
   220  //AddColumnsToUnique adds the columns to Unique Struct
   221  func (unique *Unique) AddColumnsToUnique(columns ...*Column) *Unique {
   222  
   223  	unique.Columns = append(unique.Columns, columns...)
   224  
   225  	return unique
   226  }
   227  
   228  //AddColumns adds columns to m struct
   229  func (m *Migration) AddColumns(columns ...*Column) *Migration {
   230  
   231  	m.Columns = append(m.Columns, columns...)
   232  
   233  	return m
   234  }
   235  
   236  //AddPrimary adds the column to primary in m struct
   237  func (m *Migration) AddPrimary(primary *Column) *Migration {
   238  	m.Primary = append(m.Primary, primary)
   239  	return m
   240  }
   241  
   242  //AddUnique adds the column to unique in m struct
   243  func (m *Migration) AddUnique(unique *Unique) *Migration {
   244  	m.Uniques = append(m.Uniques, unique)
   245  	return m
   246  }
   247  
   248  //AddForeign adds the column to foreign in m struct
   249  func (m *Migration) AddForeign(foreign *Foreign) *Migration {
   250  	m.Foreigns = append(m.Foreigns, foreign)
   251  	return m
   252  }
   253  
   254  //AddIndex adds the column to index in m struct
   255  func (m *Migration) AddIndex(index *Index) *Migration {
   256  	m.Indexes = append(m.Indexes, index)
   257  	return m
   258  }
   259  
   260  //RenameColumn allows renaming of columns
   261  func (m *Migration) RenameColumn(from, to string) *RenameColumn {
   262  	rename := &RenameColumn{OldName: from, NewName: to}
   263  	m.Renames = append(m.Renames, rename)
   264  	return rename
   265  }
   266  
   267  //GetSQL returns the generated sql depending on ModifyType
   268  func (m *Migration) GetSQL() (sql string) {
   269  	sql = ""
   270  	switch m.ModifyType {
   271  	case "create":
   272  		{
   273  			sql += fmt.Sprintf("CREATE TABLE `%s` (", m.TableName)
   274  			for index, column := range m.Columns {
   275  				sql += fmt.Sprintf("\n `%s` %s %s %s %s %s", column.Name, column.DataType, column.Unsign, column.Null, column.Inc, column.Default)
   276  				if len(m.Columns) > index+1 {
   277  					sql += ","
   278  				}
   279  			}
   280  
   281  			if len(m.Primary) > 0 {
   282  				sql += fmt.Sprintf(",\n PRIMARY KEY( ")
   283  			}
   284  			for index, column := range m.Primary {
   285  				sql += fmt.Sprintf(" `%s`", column.Name)
   286  				if len(m.Primary) > index+1 {
   287  					sql += ","
   288  				}
   289  
   290  			}
   291  			if len(m.Primary) > 0 {
   292  				sql += fmt.Sprintf(")")
   293  			}
   294  
   295  			for _, unique := range m.Uniques {
   296  				sql += fmt.Sprintf(",\n UNIQUE KEY `%s`( ", unique.Definition)
   297  				for index, column := range unique.Columns {
   298  					sql += fmt.Sprintf(" `%s`", column.Name)
   299  					if len(unique.Columns) > index+1 {
   300  						sql += ","
   301  					}
   302  				}
   303  				sql += fmt.Sprintf(")")
   304  			}
   305  			for _, foreign := range m.Foreigns {
   306  				sql += fmt.Sprintf(",\n `%s` %s %s %s %s %s", foreign.Name, foreign.DataType, foreign.Unsign, foreign.Null, foreign.Inc, foreign.Default)
   307  				sql += fmt.Sprintf(",\n KEY  `%s_%s_foreign`(`%s`),", m.TableName, foreign.Column.Name, foreign.Column.Name)
   308  				sql += fmt.Sprintf("\n CONSTRAINT `%s_%s_foreign` FOREIGN KEY (`%s`) REFERENCES `%s` (`%s`)  %s %s", m.TableName, foreign.Column.Name, foreign.Column.Name, foreign.ForeignTable, foreign.ForeignColumn, foreign.OnDelete, foreign.OnUpdate)
   309  
   310  			}
   311  			sql += fmt.Sprintf(")ENGINE=%s DEFAULT CHARSET=%s;", m.Engine, m.Charset)
   312  			break
   313  		}
   314  	case "alter":
   315  		{
   316  			sql += fmt.Sprintf("ALTER TABLE `%s` ", m.TableName)
   317  			for index, column := range m.Columns {
   318  				if !column.remove {
   319  					logs.Info("col")
   320  					sql += fmt.Sprintf("\n ADD `%s` %s %s %s %s %s", column.Name, column.DataType, column.Unsign, column.Null, column.Inc, column.Default)
   321  				} else {
   322  					sql += fmt.Sprintf("\n DROP COLUMN `%s`", column.Name)
   323  				}
   324  
   325  				if len(m.Columns) > index+1 {
   326  					sql += ","
   327  				}
   328  			}
   329  			for index, column := range m.Renames {
   330  				sql += fmt.Sprintf("CHANGE COLUMN `%s` `%s` %s %s %s %s %s", column.OldName, column.NewName, column.DataType, column.Unsign, column.Null, column.Inc, column.Default)
   331  				if len(m.Renames) > index+1 {
   332  					sql += ","
   333  				}
   334  			}
   335  
   336  			for index, foreign := range m.Foreigns {
   337  				sql += fmt.Sprintf("ADD `%s` %s %s %s %s %s", foreign.Name, foreign.DataType, foreign.Unsign, foreign.Null, foreign.Inc, foreign.Default)
   338  				sql += fmt.Sprintf(",\n ADD KEY  `%s_%s_foreign`(`%s`)", m.TableName, foreign.Column.Name, foreign.Column.Name)
   339  				sql += fmt.Sprintf(",\n ADD CONSTRAINT  `%s_%s_foreign` FOREIGN KEY (`%s`) REFERENCES `%s` (`%s`)  %s %s", m.TableName, foreign.Column.Name, foreign.Column.Name, foreign.ForeignTable, foreign.ForeignColumn, foreign.OnDelete, foreign.OnUpdate)
   340  				if len(m.Foreigns) > index+1 {
   341  					sql += ","
   342  				}
   343  			}
   344  			sql += ";"
   345  
   346  			break
   347  		}
   348  	case "reverse":
   349  		{
   350  
   351  			sql += fmt.Sprintf("ALTER TABLE `%s`", m.TableName)
   352  			for index, column := range m.Columns {
   353  				if column.remove {
   354  					sql += fmt.Sprintf("\n ADD `%s` %s %s %s %s %s", column.Name, column.DataType, column.Unsign, column.Null, column.Inc, column.Default)
   355  				} else {
   356  					sql += fmt.Sprintf("\n DROP COLUMN `%s`", column.Name)
   357  				}
   358  				if len(m.Columns) > index+1 {
   359  					sql += ","
   360  				}
   361  			}
   362  
   363  			if len(m.Primary) > 0 {
   364  				sql += fmt.Sprintf("\n DROP PRIMARY KEY,")
   365  			}
   366  
   367  			for index, unique := range m.Uniques {
   368  				sql += fmt.Sprintf("\n DROP KEY `%s`", unique.Definition)
   369  				if len(m.Uniques) > index+1 {
   370  					sql += ","
   371  				}
   372  
   373  			}
   374  			for index, column := range m.Renames {
   375  				sql += fmt.Sprintf("\n CHANGE COLUMN `%s` `%s` %s %s %s %s", column.NewName, column.OldName, column.OldDataType, column.OldUnsign, column.OldNull, column.OldDefault)
   376  				if len(m.Renames) > index+1 {
   377  					sql += ","
   378  				}
   379  			}
   380  
   381  			for _, foreign := range m.Foreigns {
   382  				sql += fmt.Sprintf("\n DROP KEY  `%s_%s_foreign`", m.TableName, foreign.Column.Name)
   383  				sql += fmt.Sprintf(",\n DROP FOREIGN KEY  `%s_%s_foreign`", m.TableName, foreign.Column.Name)
   384  				sql += fmt.Sprintf(",\n DROP COLUMN `%s`", foreign.Name)
   385  			}
   386  			sql += ";"
   387  		}
   388  	case "delete":
   389  		{
   390  			sql += fmt.Sprintf("DROP TABLE IF EXISTS `%s`;", m.TableName)
   391  		}
   392  	}
   393  
   394  	return
   395  }