Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
B
beego
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
beego
Commits
715ba918
Commit
715ba918
authored
Jul 17, 2017
by
astaxie
Committed by
GitHub
Jul 17, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2744 from gnanakeethan/feature/database-migration
[Proposal] Database Migrations;
parents
e8c83663
8bb0a708
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
446 additions
and
30 deletions
+446
-30
ddl.go
migration/ddl.go
+365
-24
doc.go
migration/doc.go
+41
-0
migration.go
migration/migration.go
+40
-6
No files found.
migration/ddl.go
View file @
715ba918
...
...
@@ -14,40 +14,381 @@
package
migration
// Table store the tablename and Column
type
Table
struct
{
TableName
string
Columns
[]
*
Column
}
import
(
"fmt"
"github.com/astaxie/beego"
)
//
Create return the create sql
func
(
t
*
Table
)
Create
()
string
{
return
""
//
Index struct defines the structure of Index Columns
type
Index
struct
{
Name
string
}
// Drop return the drop sql
func
(
t
*
Table
)
Drop
()
string
{
return
""
// Unique struct defines a single unique key combination
type
Unique
struct
{
Definition
string
Columns
[]
*
Column
}
//
Column define the columns name type and Default
//
Column struct defines a single column of a table
type
Column
struct
{
Name
string
Type
string
Default
interface
{}
Name
string
Inc
string
Null
string
Default
string
Unsign
string
DataType
string
remove
bool
Modify
bool
}
// Foreign struct defines a single foreign relationship
type
Foreign
struct
{
ForeignTable
string
ForeignColumn
string
OnDelete
string
OnUpdate
string
Column
}
// RenameColumn struct allows renaming of columns
type
RenameColumn
struct
{
OldName
string
OldNull
string
OldDefault
string
OldUnsign
string
OldDataType
string
NewName
string
Column
}
// CreateTable creates the table on system
func
(
m
*
Migration
)
CreateTable
(
tablename
,
engine
,
charset
string
,
p
...
func
())
{
m
.
TableName
=
tablename
m
.
Engine
=
engine
m
.
Charset
=
charset
m
.
ModifyType
=
"create"
}
func
(
m
*
Migration
)
AlterTable
(
tablename
string
)
{
m
.
TableName
=
tablename
m
.
ModifyType
=
"alter"
}
// Create return create sql with the provided tbname and columns
func
Create
(
tbname
string
,
columns
...
Column
)
string
{
return
""
// NewCol creates a new standard column and attaches it to m struct
func
(
m
*
Migration
)
NewCol
(
name
string
)
*
Column
{
col
:=
&
Column
{
Name
:
name
}
m
.
AddColumns
(
col
)
return
col
}
//PriCol creates a new primary column and attaches it to m struct
func
(
m
*
Migration
)
PriCol
(
name
string
)
*
Column
{
col
:=
&
Column
{
Name
:
name
}
m
.
AddColumns
(
col
)
m
.
AddPrimary
(
col
)
return
col
}
//UniCol creates / appends columns to specified unique key and attaches it to m struct
func
(
m
*
Migration
)
UniCol
(
uni
,
name
string
)
*
Column
{
col
:=
&
Column
{
Name
:
name
}
m
.
AddColumns
(
col
)
uniqueOriginal
:=
&
Unique
{}
for
_
,
unique
:=
range
m
.
Uniques
{
if
unique
.
Definition
==
uni
{
unique
.
AddColumnsToUnique
(
col
)
uniqueOriginal
=
unique
}
}
if
uniqueOriginal
.
Definition
==
""
{
unique
:=
&
Unique
{
Definition
:
uni
}
unique
.
AddColumnsToUnique
(
col
)
m
.
AddUnique
(
unique
)
}
return
col
}
//ForeignCol creates a new foreign column and returns the instance of column
func
(
m
*
Migration
)
ForeignCol
(
colname
,
foreigncol
,
foreigntable
string
)
(
foreign
*
Foreign
)
{
foreign
=
&
Foreign
{
ForeignColumn
:
foreigncol
,
ForeignTable
:
foreigntable
}
foreign
.
Name
=
colname
m
.
AddForeign
(
foreign
)
return
foreign
}
// Drop return the drop sql with the provided tbname and columns
func
Drop
(
tbname
string
,
columns
...
Column
)
string
{
return
""
//SetOnDelete sets the on delete of foreign
func
(
foreign
*
Foreign
)
SetOnDelete
(
del
string
)
*
Foreign
{
foreign
.
OnDelete
=
"ON DELETE"
+
del
return
foreign
}
// TableDDL is still in think
func
TableDDL
(
tbname
string
,
columns
...
Column
)
string
{
return
""
//SetOnUpdate sets the on update of foreign
func
(
foreign
*
Foreign
)
SetOnUpdate
(
update
string
)
*
Foreign
{
foreign
.
OnUpdate
=
"ON UPDATE"
+
update
return
foreign
}
//Remove marks the columns to be removed.
//it allows reverse m to create the column.
func
(
c
*
Column
)
Remove
()
{
c
.
remove
=
true
}
//SetAuto enables auto_increment of column (can be used once)
func
(
c
*
Column
)
SetAuto
(
inc
bool
)
*
Column
{
if
inc
{
c
.
Inc
=
"auto_increment"
}
return
c
}
//SetNullable sets the column to be null
func
(
c
*
Column
)
SetNullable
(
null
bool
)
*
Column
{
if
null
{
c
.
Null
=
""
}
else
{
c
.
Null
=
"NOT NULL"
}
return
c
}
//SetDefault sets the default value, prepend with "DEFAULT "
func
(
c
*
Column
)
SetDefault
(
def
string
)
*
Column
{
c
.
Default
=
"DEFAULT "
+
def
return
c
}
//SetUnsigned sets the column to be unsigned int
func
(
c
*
Column
)
SetUnsigned
(
unsign
bool
)
*
Column
{
if
unsign
{
c
.
Unsign
=
"UNSIGNED"
}
return
c
}
//SetDataType sets the dataType of the column
func
(
c
*
Column
)
SetDataType
(
dataType
string
)
*
Column
{
c
.
DataType
=
dataType
return
c
}
//SetOldNullable allows reverting to previous nullable on reverse ms
func
(
c
*
RenameColumn
)
SetOldNullable
(
null
bool
)
*
RenameColumn
{
if
null
{
c
.
OldNull
=
""
}
else
{
c
.
OldNull
=
"NOT NULL"
}
return
c
}
//SetOldDefault allows reverting to previous default on reverse ms
func
(
c
*
RenameColumn
)
SetOldDefault
(
def
string
)
*
RenameColumn
{
c
.
OldDefault
=
def
return
c
}
//SetOldUnsigned allows reverting to previous unsgined on reverse ms
func
(
c
*
RenameColumn
)
SetOldUnsigned
(
unsign
bool
)
*
RenameColumn
{
if
unsign
{
c
.
OldUnsign
=
"UNSIGNED"
}
return
c
}
//SetOldDataType allows reverting to previous datatype on reverse ms
func
(
c
*
RenameColumn
)
SetOldDataType
(
dataType
string
)
*
RenameColumn
{
c
.
OldDataType
=
dataType
return
c
}
//SetPrimary adds the columns to the primary key (can only be used any number of times in only one m)
func
(
c
*
Column
)
SetPrimary
(
m
*
Migration
)
*
Column
{
m
.
Primary
=
append
(
m
.
Primary
,
c
)
return
c
}
//AddColumnsToUnique adds the columns to Unique Struct
func
(
unique
*
Unique
)
AddColumnsToUnique
(
columns
...*
Column
)
*
Unique
{
unique
.
Columns
=
append
(
unique
.
Columns
,
columns
...
)
return
unique
}
//AddColumns adds columns to m struct
func
(
m
*
Migration
)
AddColumns
(
columns
...*
Column
)
*
Migration
{
m
.
Columns
=
append
(
m
.
Columns
,
columns
...
)
return
m
}
//AddPrimary adds the column to primary in m struct
func
(
m
*
Migration
)
AddPrimary
(
primary
*
Column
)
*
Migration
{
m
.
Primary
=
append
(
m
.
Primary
,
primary
)
return
m
}
//AddUnique adds the column to unique in m struct
func
(
m
*
Migration
)
AddUnique
(
unique
*
Unique
)
*
Migration
{
m
.
Uniques
=
append
(
m
.
Uniques
,
unique
)
return
m
}
//AddForeign adds the column to foreign in m struct
func
(
m
*
Migration
)
AddForeign
(
foreign
*
Foreign
)
*
Migration
{
m
.
Foreigns
=
append
(
m
.
Foreigns
,
foreign
)
return
m
}
//AddIndex adds the column to index in m struct
func
(
m
*
Migration
)
AddIndex
(
index
*
Index
)
*
Migration
{
m
.
Indexes
=
append
(
m
.
Indexes
,
index
)
return
m
}
//RenameColumn allows renaming of columns
func
(
m
*
Migration
)
RenameColumn
(
from
,
to
string
)
*
RenameColumn
{
rename
:=
&
RenameColumn
{
OldName
:
from
,
NewName
:
to
}
m
.
Renames
=
append
(
m
.
Renames
,
rename
)
return
rename
}
//GetSQL returns the generated sql depending on ModifyType
func
(
m
*
Migration
)
GetSQL
()
(
sql
string
)
{
sql
=
""
switch
m
.
ModifyType
{
case
"create"
:
{
sql
+=
fmt
.
Sprintf
(
"CREATE TABLE `%s` ("
,
m
.
TableName
)
for
index
,
column
:=
range
m
.
Columns
{
sql
+=
fmt
.
Sprintf
(
"
\n
`%s` %s %s %s %s %s"
,
column
.
Name
,
column
.
DataType
,
column
.
Unsign
,
column
.
Null
,
column
.
Inc
,
column
.
Default
)
if
len
(
m
.
Columns
)
>
index
+
1
{
sql
+=
","
}
}
if
len
(
m
.
Primary
)
>
0
{
sql
+=
fmt
.
Sprintf
(
",
\n
PRIMARY KEY( "
)
}
for
index
,
column
:=
range
m
.
Primary
{
sql
+=
fmt
.
Sprintf
(
" `%s`"
,
column
.
Name
)
if
len
(
m
.
Primary
)
>
index
+
1
{
sql
+=
","
}
}
if
len
(
m
.
Primary
)
>
0
{
sql
+=
fmt
.
Sprintf
(
")"
)
}
for
_
,
unique
:=
range
m
.
Uniques
{
sql
+=
fmt
.
Sprintf
(
",
\n
UNIQUE KEY `%s`( "
,
unique
.
Definition
)
for
index
,
column
:=
range
unique
.
Columns
{
sql
+=
fmt
.
Sprintf
(
" `%s`"
,
column
.
Name
)
if
len
(
unique
.
Columns
)
>
index
+
1
{
sql
+=
","
}
}
sql
+=
fmt
.
Sprintf
(
")"
)
}
for
_
,
foreign
:=
range
m
.
Foreigns
{
sql
+=
fmt
.
Sprintf
(
",
\n
`%s` %s %s %s %s %s"
,
foreign
.
Name
,
foreign
.
DataType
,
foreign
.
Unsign
,
foreign
.
Null
,
foreign
.
Inc
,
foreign
.
Default
)
sql
+=
fmt
.
Sprintf
(
",
\n
KEY `%s_%s_foreign`(`%s`),"
,
m
.
TableName
,
foreign
.
Column
.
Name
,
foreign
.
Column
.
Name
)
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
)
}
sql
+=
fmt
.
Sprintf
(
")ENGINE=%s DEFAULT CHARSET=%s;"
,
m
.
Engine
,
m
.
Charset
)
break
}
case
"alter"
:
{
sql
+=
fmt
.
Sprintf
(
"ALTER TABLE `%s` "
,
m
.
TableName
)
for
index
,
column
:=
range
m
.
Columns
{
if
!
column
.
remove
{
beego
.
BeeLogger
.
Info
(
"col"
)
sql
+=
fmt
.
Sprintf
(
"
\n
ADD `%s` %s %s %s %s %s"
,
column
.
Name
,
column
.
DataType
,
column
.
Unsign
,
column
.
Null
,
column
.
Inc
,
column
.
Default
)
}
else
{
sql
+=
fmt
.
Sprintf
(
"
\n
DROP COLUMN `%s`"
,
column
.
Name
)
}
if
len
(
m
.
Columns
)
>
index
{
sql
+=
","
}
}
for
index
,
column
:=
range
m
.
Renames
{
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
)
if
len
(
m
.
Renames
)
>
index
+
1
{
sql
+=
","
}
}
for
index
,
foreign
:=
range
m
.
Foreigns
{
sql
+=
fmt
.
Sprintf
(
"ADD `%s` %s %s %s %s %s"
,
foreign
.
Name
,
foreign
.
DataType
,
foreign
.
Unsign
,
foreign
.
Null
,
foreign
.
Inc
,
foreign
.
Default
)
sql
+=
fmt
.
Sprintf
(
",
\n
ADD KEY `%s_%s_foreign`(`%s`)"
,
m
.
TableName
,
foreign
.
Column
.
Name
,
foreign
.
Column
.
Name
)
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
)
if
len
(
m
.
Foreigns
)
>
index
+
1
{
sql
+=
","
}
}
sql
+=
";"
break
}
case
"reverse"
:
{
sql
+=
fmt
.
Sprintf
(
"ALTER TABLE `%s`"
,
m
.
TableName
)
for
index
,
column
:=
range
m
.
Columns
{
if
column
.
remove
{
sql
+=
fmt
.
Sprintf
(
"
\n
ADD `%s` %s %s %s %s %s"
,
column
.
Name
,
column
.
DataType
,
column
.
Unsign
,
column
.
Null
,
column
.
Inc
,
column
.
Default
)
}
else
{
sql
+=
fmt
.
Sprintf
(
"
\n
DROP COLUMN `%s`"
,
column
.
Name
)
}
if
len
(
m
.
Columns
)
>
index
{
sql
+=
","
}
}
if
len
(
m
.
Primary
)
>
0
{
sql
+=
fmt
.
Sprintf
(
"
\n
DROP PRIMARY KEY,"
)
}
for
index
,
unique
:=
range
m
.
Uniques
{
sql
+=
fmt
.
Sprintf
(
"
\n
DROP KEY `%s`"
,
unique
.
Definition
)
if
len
(
m
.
Uniques
)
>
index
{
sql
+=
","
}
}
for
index
,
column
:=
range
m
.
Renames
{
sql
+=
fmt
.
Sprintf
(
"
\n
CHANGE COLUMN `%s` `%s` %s %s %s %s"
,
column
.
NewName
,
column
.
OldName
,
column
.
OldDataType
,
column
.
OldUnsign
,
column
.
OldNull
,
column
.
OldDefault
)
if
len
(
m
.
Renames
)
>
index
{
sql
+=
","
}
}
for
_
,
foreign
:=
range
m
.
Foreigns
{
sql
+=
fmt
.
Sprintf
(
"
\n
DROP KEY `%s_%s_foreign`"
,
m
.
TableName
,
foreign
.
Column
.
Name
)
sql
+=
fmt
.
Sprintf
(
",
\n
DROP FOREIGN KEY `%s_%s_foreign`"
,
m
.
TableName
,
foreign
.
Column
.
Name
)
sql
+=
fmt
.
Sprintf
(
",
\n
DROP COLUMN `%s`"
,
foreign
.
Name
)
}
sql
+=
";"
}
case
"delete"
:
{
sql
+=
fmt
.
Sprintf
(
"DROP TABLE IF EXISTS `%s`;"
,
m
.
TableName
)
}
}
return
}
migration/doc.go
0 → 100644
View file @
715ba918
/* Package migration enables you to generate migrations back and forth. It generates both migrations.
//Creates a table
m.CreateTable("tablename","InnoDB","utf8");
//Alter a table
m.AlterTable("tablename")
//Standard Column Methods
* SetDataType
* SetNullable
* SetDefault
* SetUnsigned (use only on integer types unless produces error)
//Sets a primary column, multiple calls allowed, standard column methods available
m.PriCol("id").SetAuto(true).SetNullable(false).SetDataType("INT(10)").SetUnsigned(true)
//UniCol Can be used multiple times, allows standard Column methods. Use same "index" string to add to same index
m.UniCol("index","column")
//Standard Column Initialisation, can call .Remove() after NewCol("") on alter to remove
m.NewCol("name").SetDataType("VARCHAR(255) COLLATE utf8_unicode_ci").SetNullable(false)
m.NewCol("value").SetDataType("DOUBLE(8,2)").SetNullable(false)
//Rename Columns , only use with Alter table, doesn't works with Create, prefix standard column methods with "Old" to
//create a true reversible migration eg: SetOldDataType("DOUBLE(12,3)")
m.RenameColumn("from","to")...
//Foreign Columns, single columns are only supported, SetOnDelete & SetOnUpdate are available, call appropriately.
//Supports standard column methods, automatic reverse.
m.ForeignCol("local_col","foreign_col","foreign_table")
*/
package
migration
migration/migration.go
View file @
715ba918
...
...
@@ -52,6 +52,26 @@ type Migrationer interface {
GetCreated
()
int64
}
//Migration defines the migrations by either SQL or DDL
type
Migration
struct
{
sqls
[]
string
Created
string
TableName
string
Engine
string
Charset
string
ModifyType
string
Columns
[]
*
Column
Indexes
[]
*
Index
Primary
[]
*
Column
Uniques
[]
*
Unique
Foreigns
[]
*
Foreign
Renames
[]
*
RenameColumn
RemoveColumns
[]
*
Column
RemoveIndexes
[]
*
Index
RemoveUniques
[]
*
Unique
RemoveForeigns
[]
*
Foreign
}
var
(
migrationMap
map
[
string
]
Migrationer
)
...
...
@@ -60,20 +80,34 @@ func init() {
migrationMap
=
make
(
map
[
string
]
Migrationer
)
}
// Migration the basic type which will implement the basic type
type
Migration
struct
{
sqls
[]
string
Created
string
}
// Up implement in the Inheritance struct for upgrade
func
(
m
*
Migration
)
Up
()
{
switch
m
.
ModifyType
{
case
"reverse"
:
m
.
ModifyType
=
"alter"
case
"delete"
:
m
.
ModifyType
=
"create"
}
m
.
sqls
=
append
(
m
.
sqls
,
m
.
GetSQL
())
}
// Down implement in the Inheritance struct for down
func
(
m
*
Migration
)
Down
()
{
switch
m
.
ModifyType
{
case
"alter"
:
m
.
ModifyType
=
"reverse"
case
"create"
:
m
.
ModifyType
=
"delete"
}
m
.
sqls
=
append
(
m
.
sqls
,
m
.
GetSQL
())
}
//Migrate adds the SQL to the execution list
func
(
m
*
Migration
)
Migrate
(
migrationType
string
)
{
m
.
ModifyType
=
migrationType
m
.
sqls
=
append
(
m
.
sqls
,
m
.
GetSQL
())
}
// SQL add sql want to execute
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment