2017-04-07 01:47:25 +00:00
|
|
|
// Copyright 2017 The Xorm Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package xorm
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2019-06-23 15:22:43 +00:00
|
|
|
"xorm.io/core"
|
2017-04-07 01:47:25 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type tagContext struct {
|
|
|
|
tagName string
|
|
|
|
params []string
|
|
|
|
preTag, nextTag string
|
|
|
|
table *core.Table
|
|
|
|
col *core.Column
|
|
|
|
fieldValue reflect.Value
|
|
|
|
isIndex bool
|
|
|
|
isUnique bool
|
|
|
|
indexNames map[string]int
|
|
|
|
engine *Engine
|
|
|
|
hasCacheTag bool
|
|
|
|
hasNoCacheTag bool
|
|
|
|
ignoreNext bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// tagHandler describes tag handler for XORM
|
|
|
|
type tagHandler func(ctx *tagContext) error
|
|
|
|
|
|
|
|
var (
|
|
|
|
// defaultTagHandlers enumerates all the default tag handler
|
|
|
|
defaultTagHandlers = map[string]tagHandler{
|
|
|
|
"<-": OnlyFromDBTagHandler,
|
|
|
|
"->": OnlyToDBTagHandler,
|
|
|
|
"PK": PKTagHandler,
|
|
|
|
"NULL": NULLTagHandler,
|
|
|
|
"NOT": IgnoreTagHandler,
|
|
|
|
"AUTOINCR": AutoIncrTagHandler,
|
|
|
|
"DEFAULT": DefaultTagHandler,
|
|
|
|
"CREATED": CreatedTagHandler,
|
|
|
|
"UPDATED": UpdatedTagHandler,
|
|
|
|
"DELETED": DeletedTagHandler,
|
|
|
|
"VERSION": VersionTagHandler,
|
|
|
|
"UTC": UTCTagHandler,
|
|
|
|
"LOCAL": LocalTagHandler,
|
|
|
|
"NOTNULL": NotNullTagHandler,
|
|
|
|
"INDEX": IndexTagHandler,
|
|
|
|
"UNIQUE": UniqueTagHandler,
|
|
|
|
"CACHE": CacheTagHandler,
|
|
|
|
"NOCACHE": NoCacheTagHandler,
|
2017-08-22 11:39:52 +00:00
|
|
|
"COMMENT": CommentTagHandler,
|
2017-04-07 01:47:25 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
for k := range core.SqlTypes {
|
|
|
|
defaultTagHandlers[k] = SQLTypeTagHandler
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// IgnoreTagHandler describes ignored tag handler
|
|
|
|
func IgnoreTagHandler(ctx *tagContext) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// OnlyFromDBTagHandler describes mapping direction tag handler
|
|
|
|
func OnlyFromDBTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.MapType = core.ONLYFROMDB
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// OnlyToDBTagHandler describes mapping direction tag handler
|
|
|
|
func OnlyToDBTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.MapType = core.ONLYTODB
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PKTagHandler decribes primary key tag handler
|
|
|
|
func PKTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.IsPrimaryKey = true
|
|
|
|
ctx.col.Nullable = false
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NULLTagHandler describes null tag handler
|
|
|
|
func NULLTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.Nullable = (strings.ToUpper(ctx.preTag) != "NOT")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NotNullTagHandler describes notnull tag handler
|
|
|
|
func NotNullTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.Nullable = false
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AutoIncrTagHandler describes autoincr tag handler
|
|
|
|
func AutoIncrTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.IsAutoIncrement = true
|
|
|
|
/*
|
|
|
|
if len(ctx.params) > 0 {
|
|
|
|
autoStartInt, err := strconv.Atoi(ctx.params[0])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
ctx.col.AutoIncrStart = autoStartInt
|
|
|
|
} else {
|
|
|
|
ctx.col.AutoIncrStart = 1
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DefaultTagHandler describes default tag handler
|
|
|
|
func DefaultTagHandler(ctx *tagContext) error {
|
|
|
|
if len(ctx.params) > 0 {
|
|
|
|
ctx.col.Default = ctx.params[0]
|
|
|
|
} else {
|
|
|
|
ctx.col.Default = ctx.nextTag
|
|
|
|
ctx.ignoreNext = true
|
|
|
|
}
|
2019-10-02 20:47:20 +00:00
|
|
|
ctx.col.DefaultIsEmpty = false
|
2017-04-07 01:47:25 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreatedTagHandler describes created tag handler
|
|
|
|
func CreatedTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.IsCreated = true
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// VersionTagHandler describes version tag handler
|
|
|
|
func VersionTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.IsVersion = true
|
|
|
|
ctx.col.Default = "1"
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UTCTagHandler describes utc tag handler
|
|
|
|
func UTCTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.TimeZone = time.UTC
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// LocalTagHandler describes local tag handler
|
|
|
|
func LocalTagHandler(ctx *tagContext) error {
|
|
|
|
if len(ctx.params) == 0 {
|
|
|
|
ctx.col.TimeZone = time.Local
|
|
|
|
} else {
|
|
|
|
var err error
|
|
|
|
ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UpdatedTagHandler describes updated tag handler
|
|
|
|
func UpdatedTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.IsUpdated = true
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeletedTagHandler describes deleted tag handler
|
|
|
|
func DeletedTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.IsDeleted = true
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IndexTagHandler describes index tag handler
|
|
|
|
func IndexTagHandler(ctx *tagContext) error {
|
|
|
|
if len(ctx.params) > 0 {
|
|
|
|
ctx.indexNames[ctx.params[0]] = core.IndexType
|
|
|
|
} else {
|
|
|
|
ctx.isIndex = true
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UniqueTagHandler describes unique tag handler
|
|
|
|
func UniqueTagHandler(ctx *tagContext) error {
|
|
|
|
if len(ctx.params) > 0 {
|
|
|
|
ctx.indexNames[ctx.params[0]] = core.UniqueType
|
|
|
|
} else {
|
|
|
|
ctx.isUnique = true
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-08-22 11:39:52 +00:00
|
|
|
// CommentTagHandler add comment to column
|
|
|
|
func CommentTagHandler(ctx *tagContext) error {
|
|
|
|
if len(ctx.params) > 0 {
|
|
|
|
ctx.col.Comment = strings.Trim(ctx.params[0], "' ")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-04-07 01:47:25 +00:00
|
|
|
// SQLTypeTagHandler describes SQL Type tag handler
|
|
|
|
func SQLTypeTagHandler(ctx *tagContext) error {
|
|
|
|
ctx.col.SQLType = core.SQLType{Name: ctx.tagName}
|
|
|
|
if len(ctx.params) > 0 {
|
|
|
|
if ctx.tagName == core.Enum {
|
|
|
|
ctx.col.EnumOptions = make(map[string]int)
|
|
|
|
for k, v := range ctx.params {
|
|
|
|
v = strings.TrimSpace(v)
|
|
|
|
v = strings.Trim(v, "'")
|
|
|
|
ctx.col.EnumOptions[v] = k
|
|
|
|
}
|
|
|
|
} else if ctx.tagName == core.Set {
|
|
|
|
ctx.col.SetOptions = make(map[string]int)
|
|
|
|
for k, v := range ctx.params {
|
|
|
|
v = strings.TrimSpace(v)
|
|
|
|
v = strings.Trim(v, "'")
|
|
|
|
ctx.col.SetOptions[v] = k
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
var err error
|
|
|
|
if len(ctx.params) == 2 {
|
|
|
|
ctx.col.Length, err = strconv.Atoi(ctx.params[0])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
ctx.col.Length2, err = strconv.Atoi(ctx.params[1])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else if len(ctx.params) == 1 {
|
|
|
|
ctx.col.Length, err = strconv.Atoi(ctx.params[0])
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExtendsTagHandler describes extends tag handler
|
|
|
|
func ExtendsTagHandler(ctx *tagContext) error {
|
|
|
|
var fieldValue = ctx.fieldValue
|
2019-07-24 21:39:14 +00:00
|
|
|
var isPtr = false
|
2017-04-07 01:47:25 +00:00
|
|
|
switch fieldValue.Kind() {
|
|
|
|
case reflect.Ptr:
|
|
|
|
f := fieldValue.Type().Elem()
|
|
|
|
if f.Kind() == reflect.Struct {
|
|
|
|
fieldPtr := fieldValue
|
|
|
|
fieldValue = fieldValue.Elem()
|
|
|
|
if !fieldValue.IsValid() || fieldPtr.IsNil() {
|
|
|
|
fieldValue = reflect.New(f).Elem()
|
|
|
|
}
|
|
|
|
}
|
2019-07-24 21:39:14 +00:00
|
|
|
isPtr = true
|
2017-04-07 01:47:25 +00:00
|
|
|
fallthrough
|
|
|
|
case reflect.Struct:
|
|
|
|
parentTable, err := ctx.engine.mapType(fieldValue)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, col := range parentTable.Columns() {
|
|
|
|
col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName)
|
2019-07-24 21:39:14 +00:00
|
|
|
|
|
|
|
var tagPrefix = ctx.col.FieldName
|
|
|
|
if len(ctx.params) > 0 {
|
|
|
|
col.Nullable = isPtr
|
|
|
|
tagPrefix = ctx.params[0]
|
|
|
|
if col.IsPrimaryKey {
|
|
|
|
col.Name = ctx.col.FieldName
|
|
|
|
col.IsPrimaryKey = false
|
|
|
|
} else {
|
|
|
|
col.Name = fmt.Sprintf("%v%v", tagPrefix, col.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if col.Nullable {
|
|
|
|
col.IsAutoIncrement = false
|
|
|
|
col.IsPrimaryKey = false
|
|
|
|
}
|
|
|
|
|
2017-04-07 01:47:25 +00:00
|
|
|
ctx.table.AddColumn(col)
|
|
|
|
for indexName, indexType := range col.Indexes {
|
|
|
|
addIndex(indexName, ctx.table, col, indexType)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
//TODO: warning
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CacheTagHandler describes cache tag handler
|
|
|
|
func CacheTagHandler(ctx *tagContext) error {
|
|
|
|
if !ctx.hasCacheTag {
|
|
|
|
ctx.hasCacheTag = true
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NoCacheTagHandler describes nocache tag handler
|
|
|
|
func NoCacheTagHandler(ctx *tagContext) error {
|
|
|
|
if !ctx.hasNoCacheTag {
|
|
|
|
ctx.hasNoCacheTag = true
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|