Files
gormt/data/view/model/model.go
2022-07-06 18:41:33 +08:00

455 lines
12 KiB
Go
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package model
import (
"bytes"
"fmt"
"strings"
"text/template"
"github.com/xxjwxc/gormt/data/view/cnf"
"github.com/xxjwxc/public/mybigcamel"
"github.com/xxjwxc/gormt/data/config"
"github.com/xxjwxc/gormt/data/view/genfunc"
"github.com/xxjwxc/gormt/data/view/genstruct"
)
type _Model struct {
info DBInfo
pkg *genstruct.GenPackage
}
// Generate build code string.生成代码
func Generate(info DBInfo) (out []GenOutInfo, m _Model) {
m = _Model{
info: info,
}
// struct
if config.GetIsOutFileByTableName() {
outByTable := m.GenerateByTableName()
out = append(out, outByTable...)
} else {
var stt GenOutInfo
stt.FileCtx = m.generate()
stt.FileName = info.DbName + ".go"
if name := config.GetOutFileName(); len(name) > 0 {
stt.FileName = name + ".go"
}
out = append(out, stt)
}
// ------end
// gen function
if config.GetIsOutFunc() {
out = append(out, m.generateFunc()...)
}
// -------------- end
return
}
// getTableNameWithPrefix get table name with prefix
func getTableNameWithPrefix(tableName string) string {
tablePrefix := config.GetTablePrefix()
if tablePrefix == "" {
return tableName
}
if strings.HasPrefix(tablePrefix, "-") {
trimPrefix := strings.TrimPrefix(tablePrefix, "-")
tableName = strings.TrimPrefix(tableName, trimPrefix)
} else {
tableName = tablePrefix + tableName
}
return tableName
}
// GetPackage gen struct on table
func (m *_Model) GetPackage() genstruct.GenPackage {
if m.pkg == nil {
var pkg genstruct.GenPackage
pkg.SetPackage(m.info.PackageName) //package name
for _, tab := range m.info.TabList {
var sct genstruct.GenStruct
sct.SetTableName(tab.Name)
tab.Name = getTableNameWithPrefix(tab.Name)
fmt.Println(tab.Name)
sct.SetStructName(getCamelName(tab.Name)) // Big hump.大驼峰
sct.SetNotes(tab.Notes)
sct.AddElement(m.genTableElement(tab.Em)...) // build element.构造元素
sct.SetCreatTableStr(tab.SQLBuildStr)
pkg.AddStruct(sct)
}
m.pkg = &pkg
}
return *m.pkg
}
// GetPackageByTableName Generate multiple model files based on the table name. 根据表名生成多个model文件
func (m *_Model) GenerateByTableName() (out []GenOutInfo) {
if m.pkg == nil {
for _, tab := range m.info.TabList {
var pkg genstruct.GenPackage
pkg.SetPackage(m.info.PackageName) //package name
var sct genstruct.GenStruct
sct.SetTableName(tab.Name)
tab.Name = getTableNameWithPrefix(tab.Name)
sct.SetStructName(getCamelName(tab.Name)) // Big hump.大驼峰
sct.SetNotes(tab.Notes)
sct.AddElement(m.genTableElement(tab.Em)...) // build element.构造元素
sct.SetCreatTableStr(tab.SQLBuildStr)
pkg.AddStruct(sct)
var stt GenOutInfo
stt.FileCtx = pkg.Generate()
stt.FileName = tab.Name + ".go"
out = append(out, stt)
}
}
return
}
func (m *_Model) generate() string {
m.pkg = nil
m.GetPackage()
return m.pkg.Generate()
}
// genTableElement Get table columns and comments.获取表列及注释
func (m *_Model) genTableElement(cols []ColumnsInfo) (el []genstruct.GenElement) {
_tagGorm := config.GetDBTag()
_tagJSON := config.GetURLTag()
for _, v := range cols {
var tmp genstruct.GenElement
var isPK bool
if strings.EqualFold(v.Type, "gorm.Model") { // gorm model
tmp.SetType(v.Type) //
} else {
tmp.SetName(getCamelName(v.Name))
tmp.SetNotes(v.Notes)
tmp.SetType(getTypeName(v.Type, v.IsNull))
// 是否输出gorm标签
if len(_tagGorm) > 0 {
// not simple output. 默认只输出gorm主键和字段标签
if !config.GetSimple() {
if strings.EqualFold(v.Extra, "auto_increment") {
tmp.AddTag(_tagGorm, "autoIncrement:true")
}
for _, v1 := range v.Index {
switch v1.Key {
// case ColumnsKeyDefault:
case ColumnsKeyPrimary: // primary key.主键
tmp.AddTag(_tagGorm, "primaryKey")
isPK = true
case ColumnsKeyUnique: // unique key.唯一索引
tmp.AddTag(_tagGorm, "unique")
case ColumnsKeyIndex: // index key.复合索引
uninStr := getUninStr("index", ":", v1.KeyName)
// 兼容 gorm 本身 sort 标签
if v1.KeyName == "sort" {
uninStr = "index"
}
if v1.KeyType == "FULLTEXT" {
uninStr += ",class:FULLTEXT"
}
tmp.AddTag(_tagGorm, uninStr)
case ColumnsKeyUniqueIndex: // unique index key.唯一复合索引
tmp.AddTag(_tagGorm, getUninStr("uniqueIndex", ":", v1.KeyName))
}
}
} else {
for _, v1 := range v.Index {
switch v1.Key {
// case ColumnsKeyDefault:
case ColumnsKeyPrimary: // primary key.主键
tmp.AddTag(_tagGorm, "primaryKey")
isPK = true
}
}
}
}
}
if len(v.Name) > 0 {
// 是否输出gorm标签
if len(_tagGorm) > 0 {
// not simple output
if !config.GetSimple() {
tmp.AddTag(_tagGorm, "column:"+v.Name)
tmp.AddTag(_tagGorm, "type:"+v.Type)
if !v.IsNull {
tmp.AddTag(_tagGorm, "not null")
} else if v.IsNull && !config.GetIsNullToPoint() {
// 当该字段默认值为null并且结构不用指针类型时添加default:null的tag
tmp.AddTag(_tagGorm, "default:null")
}
// default tag
if len(v.Gormt) > 0 {
tmp.AddTag(_tagGorm, v.Gormt)
}
if len(v.Notes) > 0 {
tmp.AddTag(_tagGorm, fmt.Sprintf("comment:'%v'", v.Notes))
}
} else {
tmp.AddTag(_tagGorm, "column:"+v.Name)
}
}
// json tag
if config.GetIsWEBTag() {
if isPK && config.GetIsWebTagPkHidden() {
tmp.AddTag(_tagJSON, "-")
} else {
if config.GetWebTagType() == 0 {
tmp.AddTag(_tagJSON, mybigcamel.UnSmallMarshal(mybigcamel.Marshal(v.Name)))
} else {
tmp.AddTag(_tagJSON, mybigcamel.UnMarshal(v.Name))
}
}
}
}
tmp.ColumnName = v.Name // 列名
el = append(el, tmp)
// ForeignKey
if config.GetIsForeignKey() && len(v.ForeignKeyList) > 0 {
fklist := m.genForeignKey(v)
el = append(el, fklist...)
}
// -----------end
}
return
}
// genForeignKey Get information about foreign key of table column.获取表列外键相关信息
func (m *_Model) genForeignKey(col ColumnsInfo) (fklist []genstruct.GenElement) {
_tagGorm := config.GetDBTag()
_tagJSON := config.GetURLTag()
for _, v := range col.ForeignKeyList {
isMulti, isFind, notes := m.getColumnsKeyMulti(v.TableName, v.ColumnName)
if isFind {
var tmp genstruct.GenElement
tmp.SetNotes(notes)
if isMulti {
tmp.SetName(getCamelName(v.TableName) + "List")
tmp.SetType("[]" + getCamelName(v.TableName))
} else {
tmp.SetName(getCamelName(v.TableName))
tmp.SetType(getCamelName(v.TableName))
}
tmp.AddTag(_tagGorm, "joinForeignKey:"+col.Name) // association_foreignkey
tmp.AddTag(_tagGorm, "foreignKey:"+v.ColumnName)
tmp.AddTag(_tagGorm, "references:"+getCamelName(col.Name))
// json tag
if config.GetIsWEBTag() {
if config.GetWebTagType() == 0 {
tmp.AddTag(_tagJSON, mybigcamel.UnSmallMarshal(mybigcamel.Marshal(v.TableName))+"List")
} else {
tmp.AddTag(_tagJSON, mybigcamel.UnMarshal(v.TableName)+"_list")
}
}
fklist = append(fklist, tmp)
}
}
return
}
func (m *_Model) getColumnsKeyMulti(tableName, col string) (isMulti bool, isFind bool, notes string) {
var haveGomod bool
for _, v := range m.info.TabList {
if strings.EqualFold(v.Name, tableName) {
for _, v1 := range v.Em {
if strings.EqualFold(v1.Name, col) {
for _, v2 := range v1.Index {
switch v2.Key {
case ColumnsKeyPrimary, ColumnsKeyUnique, ColumnsKeyUniqueIndex: // primary key unique key . 主键,唯一索引
{
if !v2.Multi { // 唯一索引
return false, true, v.Notes
}
}
// case ColumnsKeyIndex: // index key. 复合索引
// {
// isMulti = true
// }
}
}
return true, true, v.Notes
} else if strings.EqualFold(v1.Type, "gorm.Model") {
haveGomod = true
notes = v.Notes
}
}
break
}
}
// default gorm.Model
if haveGomod {
if strings.EqualFold(col, "id") {
return false, true, notes
}
if strings.EqualFold(col, "created_at") ||
strings.EqualFold(col, "updated_at") ||
strings.EqualFold(col, "deleted_at") {
return true, true, notes
}
}
return false, false, ""
// -----------------end
}
// ///////////////////////// func
func (m *_Model) generateFunc() (genOut []GenOutInfo) {
// getn base
tmpl, err := template.New("gen_base").Funcs(template.FuncMap{"GetVV": func() string { return "`%v`" }}).Parse(genfunc.GetGenBaseTemp())
if err != nil {
panic(err)
}
var buf bytes.Buffer
tmpl.Execute(&buf, m.info)
genOut = append(genOut, GenOutInfo{
FileName: "gen.base.go",
FileCtx: buf.String(),
})
//tools.WriteFile(outDir+"gen_router.go", []string{buf.String()}, true)
// -------end------
// gen page 分页查询的基础
if config.GetIsOutPage() {
genPage, err := template.New("gen_page").Parse(genfunc.GetGenPageTemp())
if err != nil {
panic(err)
}
var bufPage bytes.Buffer
genPage.Execute(&bufPage, m.info)
genOut = append(genOut, GenOutInfo{
FileName: "gen.page.go",
FileCtx: bufPage.String(),
})
}
// -------end------
for _, tab := range m.info.TabList {
var pkg genstruct.GenPackage
pkg.SetPackage(m.info.PackageName) //package name
pkg.AddImport(`"fmt"`)
pkg.AddImport(`"context"`) // 添加import信息
pkg.AddImport(cnf.EImportsHead["gorm.Model"])
// wxw 2021.2.26 17:17
var data funDef
data.TableName = tab.Name
data.IsOutPage = config.GetIsOutPage() // 添加分页开关
tab.Name = getTableNameWithPrefix(tab.Name)
data.StructName = getCamelName(tab.Name)
var primary, unique, uniqueIndex, index []FList
for _, el := range tab.Em {
if strings.EqualFold(el.Type, "gorm.Model") {
data.Em = append(data.Em, getGormModelElement()...)
pkg.AddImport(`"time"`)
buildFList(&primary, ColumnsKeyPrimary, "", "int64", "id")
} else {
typeName := getTypeName(el.Type, el.IsNull)
isMulti := (len(el.Index) == 0)
isUniquePrimary := false
for _, v1 := range el.Index {
if v1.Multi {
isMulti = v1.Multi
}
switch v1.Key {
// case ColumnsKeyDefault:
case ColumnsKeyPrimary: // primary key.主键
isUniquePrimary = !v1.Multi
buildFList(&primary, ColumnsKeyPrimary, v1.KeyName, typeName, el.Name)
case ColumnsKeyUnique: // unique key.唯一索引
buildFList(&unique, ColumnsKeyUnique, v1.KeyName, typeName, el.Name)
case ColumnsKeyIndex: // index key.复合索引
buildFList(&index, ColumnsKeyIndex, v1.KeyName, typeName, el.Name)
case ColumnsKeyUniqueIndex: // unique index key.唯一复合索引
buildFList(&uniqueIndex, ColumnsKeyUniqueIndex, v1.KeyName, typeName, el.Name)
}
}
if isMulti && isUniquePrimary { // 主键唯一
isMulti = false
}
data.Em = append(data.Em, EmInfo{
IsMulti: isMulti,
Notes: fixNotes(el.Notes),
Type: typeName, // Type.类型标记
ColName: el.Name,
ColNameEx: fmt.Sprintf("`%v`", el.Name),
ColStructName: getCamelName(el.Name),
})
if v2, ok := cnf.EImportsHead[typeName]; ok {
if len(v2) > 0 {
pkg.AddImport(v2)
}
}
}
// 外键列表
for _, v := range el.ForeignKeyList {
isMulti, isFind, notes := m.getColumnsKeyMulti(v.TableName, v.ColumnName)
if isFind {
var info PreloadInfo
info.IsMulti = isMulti
info.Notes = fixNotes(notes)
info.ForeignkeyTableName = v.TableName
info.ForeignkeyCol = v.ColumnName
info.ForeignkeyStructName = getCamelName(v.TableName)
info.ColName = el.Name
info.ColStructName = getCamelName(el.Name)
data.PreloadList = append(data.PreloadList, info)
}
}
// ---------end--
}
data.Primary = append(data.Primary, primary...)
data.Primary = append(data.Primary, unique...)
data.Primary = append(data.Primary, uniqueIndex...)
data.Index = append(data.Index, index...)
tmpl, err := template.New("gen_logic").
Funcs(template.FuncMap{"GenPreloadList": GenPreloadList, "GenFListIndex": GenFListIndex, "CapLowercase": CapLowercase, "GetTablePrefixName": GetTablePrefixName}).
Parse(genfunc.GetGenLogicTemp())
if err != nil {
panic(err)
}
var buf bytes.Buffer
tmpl.Execute(&buf, data)
pkg.AddFuncStr(buf.String())
genOut = append(genOut, GenOutInfo{
FileName: fmt.Sprintf(m.info.DbName+".gen.%v.go", tab.Name),
FileCtx: pkg.Generate(),
})
}
return
}