1
0
mirror of https://github.com/astaxie/beego.git synced 2024-11-14 07:00:56 +00:00
Beego/orm/cmd_utils.go

315 lines
7.4 KiB
Go
Raw Normal View History

2014-08-18 08:41:43 +00:00
// Copyright 2014 beego Author. All Rights Reserved.
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// http://www.apache.org/licenses/LICENSE-2.0
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2013-08-19 14:37:39 +00:00
package orm
import (
"fmt"
"os"
"strings"
)
2013-08-27 04:33:27 +00:00
type dbIndex struct {
Table string
Name string
2015-09-12 13:46:43 +00:00
SQL string
2013-08-27 04:33:27 +00:00
}
2014-01-17 09:04:15 +00:00
// create database drop sql.
2015-09-12 13:46:43 +00:00
func getDbDropSQL(al *alias) (sqls []string) {
2013-08-19 14:37:39 +00:00
if len(modelCache.cache) == 0 {
fmt.Println("no Model found, need register your model")
os.Exit(2)
}
Q := al.DbBaser.TableQuote()
for _, mi := range modelCache.allOrdered() {
sqls = append(sqls, fmt.Sprintf(`DROP TABLE IF EXISTS %s%s%s`, Q, mi.table, Q))
}
return sqls
}
2014-01-17 09:04:15 +00:00
// get database column type string.
2013-08-27 04:33:27 +00:00
func getColumnTyp(al *alias, fi *fieldInfo) (col string) {
T := al.DbBaser.DbTypes()
fieldType := fi.fieldType
fieldSize := fi.size
2013-08-27 04:33:27 +00:00
checkColumn:
switch fieldType {
case TypeBooleanField:
col = T["bool"]
case TypeCharField:
if al.Driver == DRPostgres && fi.toText {
col = T["string-text"]
} else {
col = fmt.Sprintf(T["string"], fieldSize)
}
2013-08-27 04:33:27 +00:00
case TypeTextField:
col = T["string-text"]
case TypeTimeField:
col = T["time.Time-clock"]
2013-08-27 04:33:27 +00:00
case TypeDateField:
col = T["time.Time-date"]
case TypeDateTimeField:
col = T["time.Time"]
case TypeBitField:
col = T["int8"]
case TypeSmallIntegerField:
col = T["int16"]
case TypeIntegerField:
col = T["int32"]
case TypeBigIntegerField:
2015-09-12 13:46:43 +00:00
if al.Driver == DRSqlite {
2013-08-27 04:33:27 +00:00
fieldType = TypeIntegerField
goto checkColumn
}
col = T["int64"]
case TypePositiveBitField:
col = T["uint8"]
case TypePositiveSmallIntegerField:
col = T["uint16"]
case TypePositiveIntegerField:
col = T["uint32"]
case TypePositiveBigIntegerField:
col = T["uint64"]
case TypeFloatField:
col = T["float64"]
case TypeDecimalField:
s := T["float64-decimal"]
2017-03-17 17:24:45 +00:00
if !strings.Contains(s, "%d") {
2013-08-27 04:33:27 +00:00
col = s
} else {
col = fmt.Sprintf(s, fi.digits, fi.decimals)
}
2016-04-09 02:22:40 +00:00
case TypeJSONField:
2016-04-08 13:53:27 +00:00
if al.Driver != DRPostgres {
fieldType = TypeCharField
goto checkColumn
}
col = T["json"]
case TypeJsonbField:
if al.Driver != DRPostgres {
fieldType = TypeCharField
goto checkColumn
}
col = T["jsonb"]
2013-08-27 04:33:27 +00:00
case RelForeignKey, RelOneToOne:
fieldType = fi.relModelInfo.fields.pk.fieldType
fieldSize = fi.relModelInfo.fields.pk.size
2013-08-27 04:33:27 +00:00
goto checkColumn
}
return
}
2014-01-17 09:04:15 +00:00
// create alter sql string.
2013-08-27 04:33:27 +00:00
func getColumnAddQuery(al *alias, fi *fieldInfo) string {
Q := al.DbBaser.TableQuote()
typ := getColumnTyp(al, fi)
2017-03-17 17:24:45 +00:00
if !fi.null {
2013-08-27 04:33:27 +00:00
typ += " " + "NOT NULL"
}
2015-09-12 13:46:43 +00:00
return fmt.Sprintf("ALTER TABLE %s%s%s ADD COLUMN %s%s%s %s %s",
Q, fi.mi.table, Q,
Q, fi.column, Q,
typ, getColumnDefault(fi),
)
2013-08-27 04:33:27 +00:00
}
2014-01-17 09:04:15 +00:00
// create database creation string.
2015-09-12 13:46:43 +00:00
func getDbCreateSQL(al *alias) (sqls []string, tableIndexes map[string][]dbIndex) {
2013-08-19 14:37:39 +00:00
if len(modelCache.cache) == 0 {
fmt.Println("no Model found, need register your model")
os.Exit(2)
}
Q := al.DbBaser.TableQuote()
T := al.DbBaser.DbTypes()
sep := fmt.Sprintf("%s, %s", Q, Q)
2013-08-19 14:37:39 +00:00
2013-08-27 04:33:27 +00:00
tableIndexes = make(map[string][]dbIndex)
2013-08-25 03:31:07 +00:00
2013-08-19 14:37:39 +00:00
for _, mi := range modelCache.allOrdered() {
sql := fmt.Sprintf("-- %s\n", strings.Repeat("-", 50))
sql += fmt.Sprintf("-- Table Structure for `%s`\n", mi.fullName)
sql += fmt.Sprintf("-- %s\n", strings.Repeat("-", 50))
sql += fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s%s%s (\n", Q, mi.table, Q)
columns := make([]string, 0, len(mi.fields.fieldsDB))
sqlIndexes := [][]string{}
2013-08-19 14:37:39 +00:00
for _, fi := range mi.fields.fieldsDB {
column := fmt.Sprintf(" %s%s%s ", Q, fi.column, Q)
2013-08-27 04:33:27 +00:00
col := getColumnTyp(al, fi)
2013-08-19 14:37:39 +00:00
if fi.auto {
switch al.Driver {
2015-09-12 13:46:43 +00:00
case DRSqlite, DRPostgres:
2013-08-19 14:37:39 +00:00
column += T["auto"]
default:
2013-08-19 14:37:39 +00:00
column += col + " " + T["auto"]
}
} else if fi.pk {
column += col + " " + T["pk"]
} else {
column += col
2017-03-17 17:24:45 +00:00
if !fi.null {
2013-08-19 14:37:39 +00:00
column += " " + "NOT NULL"
}
2014-07-01 01:30:08 +00:00
//if fi.initial.String() != "" {
// column += " DEFAULT " + fi.initial.String()
//}
2015-09-12 13:46:43 +00:00
// Append attribute DEFAULT
column += getColumnDefault(fi)
2013-08-19 14:37:39 +00:00
if fi.unique {
column += " " + "UNIQUE"
}
if fi.index {
2013-08-25 03:31:07 +00:00
sqlIndexes = append(sqlIndexes, []string{fi.column})
}
2013-08-19 14:37:39 +00:00
}
2017-03-17 17:24:45 +00:00
if strings.Contains(column, "%COL%") {
2013-08-19 14:37:39 +00:00
column = strings.Replace(column, "%COL%", fi.column, -1)
}
columns = append(columns, column)
}
if mi.model != nil {
allnames := getTableUnique(mi.addrField)
if !mi.manual && len(mi.uniques) > 0 {
allnames = append(allnames, mi.uniques)
}
for _, names := range allnames {
cols := make([]string, 0, len(names))
for _, name := range names {
if fi, ok := mi.fields.GetByAny(name); ok && fi.dbcol {
cols = append(cols, fi.column)
} else {
panic(fmt.Errorf("cannot found column `%s` when parse UNIQUE in `%s.TableUnique`", name, mi.fullName))
}
}
column := fmt.Sprintf(" UNIQUE (%s%s%s)", Q, strings.Join(cols, sep), Q)
columns = append(columns, column)
}
}
2013-08-19 14:37:39 +00:00
sql += strings.Join(columns, ",\n")
sql += "\n)"
2015-09-12 13:46:43 +00:00
if al.Driver == DRMySQL {
var engine string
if mi.model != nil {
engine = getTableEngine(mi.addrField)
}
if engine == "" {
engine = al.Engine
}
sql += " ENGINE=" + engine
2013-08-19 14:37:39 +00:00
}
sql += ";"
2013-08-19 14:37:39 +00:00
sqls = append(sqls, sql)
if mi.model != nil {
for _, names := range getTableIndex(mi.addrField) {
cols := make([]string, 0, len(names))
for _, name := range names {
if fi, ok := mi.fields.GetByAny(name); ok && fi.dbcol {
cols = append(cols, fi.column)
} else {
panic(fmt.Errorf("cannot found column `%s` when parse INDEX in `%s.TableIndex`", name, mi.fullName))
}
}
sqlIndexes = append(sqlIndexes, cols)
}
}
for _, names := range sqlIndexes {
2013-08-25 05:50:50 +00:00
name := mi.table + "_" + strings.Join(names, "_")
cols := strings.Join(names, sep)
sql := fmt.Sprintf("CREATE INDEX %s%s%s ON %s%s%s (%s%s%s);", Q, name, Q, Q, mi.table, Q, Q, cols, Q)
2013-08-27 04:33:27 +00:00
index := dbIndex{}
index.Table = mi.table
index.Name = name
2015-09-12 13:46:43 +00:00
index.SQL = sql
2013-08-27 04:33:27 +00:00
tableIndexes[mi.table] = append(tableIndexes[mi.table], index)
}
2013-08-19 14:37:39 +00:00
}
2013-08-25 03:31:07 +00:00
return
2013-08-19 14:37:39 +00:00
}
// Get string value for the attribute "DEFAULT" for the CREATE, ALTER commands
func getColumnDefault(fi *fieldInfo) string {
var (
v, t, d string
)
// Skip default attribute if field is in relations
if fi.rel || fi.reverse {
return v
}
t = " DEFAULT '%s' "
// These defaults will be useful if there no config value orm:"default" and NOT NULL is on
switch fi.fieldType {
case TypeTimeField, TypeDateField, TypeDateTimeField, TypeTextField:
2015-09-12 13:46:43 +00:00
return v
2016-01-15 00:43:02 +00:00
case TypeBitField, TypeSmallIntegerField, TypeIntegerField,
2015-09-12 13:46:43 +00:00
TypeBigIntegerField, TypePositiveBitField, TypePositiveSmallIntegerField,
TypePositiveIntegerField, TypePositiveBigIntegerField, TypeFloatField,
TypeDecimalField:
2016-01-04 14:10:18 +00:00
t = " DEFAULT %s "
2015-09-12 13:46:43 +00:00
d = "0"
2016-01-15 00:43:02 +00:00
case TypeBooleanField:
t = " DEFAULT %s "
d = "FALSE"
2016-04-09 02:22:40 +00:00
case TypeJSONField, TypeJsonbField:
2016-04-08 13:53:27 +00:00
d = "{}"
}
2015-09-12 13:46:43 +00:00
if fi.colDefault {
if !fi.initial.Exist() {
v = fmt.Sprintf(t, "")
} else {
v = fmt.Sprintf(t, fi.initial.String())
}
} else {
if !fi.null {
v = fmt.Sprintf(t, d)
}
}
return v
}