beego/client/orm/cmd_utils.go

177 lines
4.1 KiB
Go

// Copyright 2014 beego Author. All Rights Reserved.
//
// 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
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// 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.
package orm
import (
"fmt"
"strings"
"github.com/beego/beego/v2/client/orm/internal/models"
)
type dbIndex struct {
Table string
Name string
SQL string
}
// get database column type string.
func getColumnTyp(al *alias, fi *models.FieldInfo) (col string) {
T := al.DbBaser.DbTypes()
fieldType := fi.FieldType
fieldSize := fi.Size
defer func() {
// handling the placeholder, including %COL%
col = strings.ReplaceAll(col, "%COL%", fi.Column)
}()
checkColumn:
switch fieldType {
case TypeBooleanField:
col = T["bool"]
case TypeVarCharField:
if al.Driver == DRPostgres && fi.ToText {
col = T["string-text"]
} else {
col = fmt.Sprintf(T["string"], fieldSize)
}
case TypeCharField:
col = fmt.Sprintf(T["string-char"], fieldSize)
case TypeTextField:
col = T["string-text"]
case TypeTimeField:
col = T["time.Time-clock"]
case TypeDateField:
col = T["time.Time-date"]
case TypeDateTimeField:
// the precision of sqlite is not implemented
if al.Driver == 2 || fi.TimePrecision == nil {
col = T["time.Time"]
} else {
s := T["time.Time-precision"]
col = fmt.Sprintf(s, *fi.TimePrecision)
}
case TypeBitField:
col = T["int8"]
case TypeSmallIntegerField:
col = T["int16"]
case TypeIntegerField:
col = T["int32"]
case TypeBigIntegerField:
if al.Driver == DRSqlite {
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"]
if !strings.Contains(s, "%d") {
col = s
} else {
col = fmt.Sprintf(s, fi.Digits, fi.Decimals)
}
case TypeJSONField:
if al.Driver != DRPostgres {
fieldType = TypeVarCharField
goto checkColumn
}
col = T["json"]
case TypeJsonbField:
if al.Driver != DRPostgres {
fieldType = TypeVarCharField
goto checkColumn
}
col = T["jsonb"]
case RelForeignKey, RelOneToOne:
fieldType = fi.RelModelInfo.Fields.Pk.FieldType
fieldSize = fi.RelModelInfo.Fields.Pk.Size
goto checkColumn
}
return
}
// create alter sql string.
func getColumnAddQuery(al *alias, fi *models.FieldInfo) string {
Q := al.DbBaser.TableQuote()
typ := getColumnTyp(al, fi)
if !fi.Null {
typ += " " + "NOT NULL"
}
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),
)
}
// Get string value for the attribute "DEFAULT" for the CREATE, ALTER commands
func getColumnDefault(fi *models.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:
return v
case TypeBitField, TypeSmallIntegerField, TypeIntegerField,
TypeBigIntegerField, TypePositiveBitField, TypePositiveSmallIntegerField,
TypePositiveIntegerField, TypePositiveBigIntegerField, TypeFloatField,
TypeDecimalField:
t = " DEFAULT %s "
d = "0"
case TypeBooleanField:
t = " DEFAULT %s "
d = "FALSE"
case TypeJSONField, TypeJsonbField:
d = "{}"
}
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
}