From 3b9d9a7d74133d5261e0d8a9d966d08e206b665f Mon Sep 17 00:00:00 2001 From: viwii <15517103103@163.com> Date: Sun, 11 Apr 2021 20:43:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=BF=E6=9C=8B=E5=8F=8B=E5=90=88=E5=B9=B6ms?= =?UTF-8?q?sql?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/view/gtools/gtools.go | 7 +- data/view/model/genmssql/common.go | 100 +++++++++++ data/view/model/genmssql/def.go | 46 +++++ data/view/model/genmssql/genmssql.go | 257 +++++++++++++++++++++++++++ 4 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 data/view/model/genmssql/common.go create mode 100644 data/view/model/genmssql/def.go create mode 100644 data/view/model/genmssql/genmssql.go diff --git a/data/view/gtools/gtools.go b/data/view/gtools/gtools.go index 1416c10..91c935e 100644 --- a/data/view/gtools/gtools.go +++ b/data/view/gtools/gtools.go @@ -11,6 +11,7 @@ import ( "github.com/xxjwxc/gormt/data/config" + "github.com/xxjwxc/gormt/data/view/model/genmssql" "github.com/xxjwxc/gormt/data/view/model/genmysql" "github.com/xxjwxc/gormt/data/view/model/gensqlite" "github.com/xxjwxc/public/tools" @@ -32,10 +33,12 @@ func showCmd() { // fmt.Println(tt) var modeldb model.IModel switch config.GetDbInfo().Type { - case 0: + case 0: // mysql modeldb = genmysql.GetModel() - case 1: + case 1: // sqllite modeldb = gensqlite.GetModel() + case 2: // + modeldb = genmssql.GetModel() } if modeldb == nil { mylog.Error(fmt.Errorf("modeldb not fund : please check db_info.type (0:mysql , 1:sqlite , 2:mssql) ")) diff --git a/data/view/model/genmssql/common.go b/data/view/model/genmssql/common.go new file mode 100644 index 0000000..cc2148c --- /dev/null +++ b/data/view/model/genmssql/common.go @@ -0,0 +1,100 @@ +package genmssql + +import ( + "strings" + + "github.com/xxjwxc/gormt/data/config" + "github.com/xxjwxc/public/mylog" + + "github.com/xxjwxc/gormt/data/view/model" +) + +// filterModel filter.过滤 gorm.Model +func filterModel(list *[]genColumns) bool { + if config.GetDBTag() != "gorm" { + return false + } + + var _temp []genColumns + num := 0 + for _, v := range *list { + if strings.EqualFold(v.Field, "id") || + strings.EqualFold(v.Field, "created_at") || + strings.EqualFold(v.Field, "updated_at") || + strings.EqualFold(v.Field, "deleted_at") { + num++ + } else { + _temp = append(_temp, v) + } + } + + if num >= 4 { + *list = _temp + return true + } + + return false +} + +// fixForeignKey fix foreign key.过滤外键 +func fixForeignKey(list []genForeignKey, columuName string, result *[]model.ForeignKey) { + for _, v := range list { + if strings.EqualFold(v.ColumnName, columuName) { // find it .找到了 + *result = append(*result, model.ForeignKey{ + TableName: v.ReferencedTableName, + ColumnName: v.ReferencedColumnName, + }) + } + } +} + +// GetModel get model interface. 获取model接口 +func GetModel() model.IModel { + //now just support mysql + return &MssqlModel +} + +// FixNotes 分析元素表注释 +func FixNotes(em *model.ColumnsInfo, note string) { + b0 := FixElementTag(em, note) // gorm + b1 := FixForeignKeyTag(em, em.Notes) // 外键 + if !b0 && b1 { // 补偿 + FixElementTag(em, em.Notes) // gorm + } +} + +// FixElementTag 分析元素表注释 +func FixElementTag(em *model.ColumnsInfo, note string) bool { + matches := noteRegex.FindStringSubmatch(note) + if len(matches) < 2 { + em.Notes = note + return false + } + + mylog.Infof("get one gorm tag:(%v) ==> (%v)", em.BaseInfo.Name, matches[1]) + em.Notes = note[len(matches[0]):] + em.Gormt = matches[1] + return true +} + +// FixForeignKeyTag 分析元素表注释(外键) +func FixForeignKeyTag(em *model.ColumnsInfo, note string) bool { + matches := foreignKeyRegex.FindStringSubmatch(note) // foreign key 外键 + if len(matches) < 2 { + em.Notes = note + return false + } + em.Notes = note[len(matches[0]):] + + // foreign key 外键 + tmp := strings.Split(matches[1], ".") + if len(tmp) > 0 { + mylog.Infof("get one foreign key:(%v) ==> (%v)", em.BaseInfo.Name, matches[1]) + em.ForeignKeyList = append(em.ForeignKeyList, model.ForeignKey{ + TableName: tmp[0], + ColumnName: tmp[1], + }) + } + + return true +} diff --git a/data/view/model/genmssql/def.go b/data/view/model/genmssql/def.go new file mode 100644 index 0000000..f57c07e --- /dev/null +++ b/data/view/model/genmssql/def.go @@ -0,0 +1,46 @@ +package genmssql + +import "regexp" + +// genColumns show full columns +type genColumns struct { + Field string `gorm:"column:Field"` + Type string `gorm:"column:Type"` + Key string `gorm:"column:Key"` + Desc string `gorm:"column:Comment"` + Null string `gorm:"column:Null"` + Default *string `gorm:"column:Default"` +} + +//select table_schema,table_name,column_name,referenced_table_schema,referenced_table_name,referenced_column_name from INFORMATION_SCHEMA.KEY_COLUMN_USAGE +// where table_schema ='matrix' AND REFERENCED_TABLE_NAME IS NOT NULL AND TABLE_NAME = 'credit_card' ; +// genForeignKey Foreign key of db info . 表的外键信息 +type genForeignKey struct { + TableSchema string `gorm:"column:table_schema"` // Database of columns.列所在的数据库 + TableName string `gorm:"column:table_name"` // Data table of column.列所在的数据表 + ColumnName string `gorm:"column:column_name"` // Column names.列名 + ReferencedTableSchema string `gorm:"column:referenced_table_schema"` // The database where the index is located.该索引所在的数据库 + ReferencedTableName string `gorm:"column:referenced_table_name"` // Affected tables . 该索引受影响的表 + ReferencedColumnName string `gorm:"column:referenced_column_name"` // Which column of the affected table.该索引受影响的表的哪一列 +} + +///////////////////////////////////////////////////////////////////////// + +// TableDescription 表及表注释 +type TableDescription struct { + Name string `gorm:"column:name"` // 表名 + Value string `gorm:"column:value"` // 表注释 +} + +type ColumnKeys struct { + ID int `gorm:"column:id"` + Name string `gorm:"column:name"` // 列名 + Pk int `gorm:"column:pk"` // 是否主键 + Type string `gorm:"column:tp"` // 类型 + Length int `gorm:"column:len"` // 长度 + Isnull int `gorm:"column:isnull"` // 是否为空 + Desc string `gorm:"column:des"` // 列注释 +} + +var noteRegex = regexp.MustCompile(`^\[@gorm\s(\S+)+\]`) +var foreignKeyRegex = regexp.MustCompile(`^\[@fk\s(\S+)+\]`) diff --git a/data/view/model/genmssql/genmssql.go b/data/view/model/genmssql/genmssql.go new file mode 100644 index 0000000..584a81b --- /dev/null +++ b/data/view/model/genmssql/genmssql.go @@ -0,0 +1,257 @@ +package genmssql + +import ( + "fmt" + "sort" + "strings" + + "github.com/xxjwxc/gormt/data/config" + "github.com/xxjwxc/gormt/data/view/model" + "github.com/xxjwxc/public/mylog" + "github.com/xxjwxc/public/tools" + "gorm.io/driver/sqlserver" + "gorm.io/gorm" +) + +// MssqlModel mysql model from IModel +var MssqlModel mssqlModel + +type mssqlModel struct { +} + +// GenModel get model.DBInfo info.获取数据库相关属性 +func (m *mssqlModel) GenModel() model.DBInfo { + dsn := fmt.Sprintf("server=%v;database=%v;user id=%v;password=%v;port=%v;encrypt=disable", + config.GetDbInfo().Host, config.GetDbInfo().Database, config.GetDbInfo().Username, config.GetDbInfo().Password, config.GetDbInfo().Port) + db, err := gorm.Open(sqlserver.Open(dsn), &gorm.Config{}) + if err != nil { + mylog.Error(err) + return model.DBInfo{} + } + defer func() { + sqldb, _ := db.DB() + sqldb.Close() + }() + + var dbInfo model.DBInfo + m.getPackageInfo(db, &dbInfo) + dbInfo.PackageName = m.GetPkgName() + dbInfo.DbName = m.GetDbName() + return dbInfo +} + +// GetDbName get database name.获取数据库名字 +func (m *mssqlModel) GetDbName() string { + return config.GetDbInfo().Database +} + +// GetTableNames get table name.获取格式化后指定的表名 +func (m *mssqlModel) GetTableNames() string { + return config.GetTableNames() +} + +// GetOriginTableNames get table name.获取原始指定的表名 +func (m *mssqlModel) GetOriginTableNames() string { + return config.GetOriginTableNames() +} + +// GetPkgName package names through config outdir configuration.通过config outdir 配置获取包名 +func (m *mssqlModel) GetPkgName() string { + dir := config.GetOutDir() + dir = strings.Replace(dir, "\\", "/", -1) + if len(dir) > 0 { + if dir[len(dir)-1] == '/' { + dir = dir[:(len(dir) - 1)] + } + } + var pkgName string + list := strings.Split(dir, "/") + if len(list) > 0 { + pkgName = list[len(list)-1] + } + + if len(pkgName) == 0 || pkgName == "." { + list = strings.Split(tools.GetModelPath(), "/") + if len(list) > 0 { + pkgName = list[len(list)-1] + } + } + + return pkgName +} + +func (m *mssqlModel) getPackageInfo(orm *gorm.DB, info *model.DBInfo) { + tabls := m.getTables(orm) // get table and notes + // if m := config.GetTableList(); len(m) > 0 { + // // 制定了表之后 + // newTabls := make(map[string]string) + // for t := range m { + // if notes, ok := tabls[t]; ok { + // newTabls[t] = notes + // } else { + // fmt.Printf("table: %s not found in db\n", t) + // } + // } + // tabls = newTabls + // } + for tabName, notes := range tabls { + var tab model.TabInfo + tab.Name = tabName + tab.Notes = notes + + if config.GetIsOutSQL() { + // TODO:获取创建sql语句 + // Get create SQL statements.获取创建sql语句 + // rows, err := orm.Raw("show create table " + assemblyTable(tabName)).Rows() + // //defer rows.Close() + // if err == nil { + // if rows.Next() { + // var table, CreateTable string + // rows.Scan(&table, &CreateTable) + // tab.SQLBuildStr = CreateTable + // } + // } + // rows.Close() + // ----------end + } + + // build element.构造元素 + tab.Em = m.getTableElement(orm, tabName) + // --------end + + info.TabList = append(info.TabList, tab) + } + // sort tables + sort.Slice(info.TabList, func(i, j int) bool { + return info.TabList[i].Name < info.TabList[j].Name + }) +} + +// getTableElement Get table columns and comments.获取表列及注释 +func (m *mssqlModel) getTableElement(orm *gorm.DB, tab string) (el []model.ColumnsInfo) { + sql := fmt.Sprintf(`SELECT + id = a.colorder, + name = a.name, + pk = case when exists(SELECT 1 FROM sysobjects where xtype='PK' and parent_obj=a.id and name in ( + SELECT name FROM sysindexes WHERE indid in( SELECT indid FROM sysindexkeys WHERE id = a.id AND colid=a.colid))) then 1 else 0 end, + tp = b.name, + len = COLUMNPROPERTY(a.id,a.name,'PRECISION'), + isnull = a.isnullable, + des = isnull(g.[value],'') +FROM + syscolumns a +left join + systypes b +on + a.xusertype=b.xusertype +inner join + sysobjects d +on + a.id=d.id and d.xtype='U' and d.name<>'dtproperties' +left join +sys.extended_properties g +on + a.id=G.major_id and a.colid=g.minor_id +left join +sys.extended_properties f +on + d.id=f.major_id and f.minor_id=0 +where + d.name='%v' +order by + a.id,a.colorder`, tab) + + lenPk := 0 + // get keys + var Keys []ColumnKeys + orm.Raw(sql).Scan(&Keys) + for i := 0; i < len(Keys); i++ { + v := &Keys[i] + if v.Pk == 1 { + lenPk++ + } + if strings.EqualFold(v.Type, "varchar") { // 字符串 + v.Type = fmt.Sprintf("varchar(%v)", v.Length) + } else if strings.EqualFold(v.Type, "int") { // int + v.Type = fmt.Sprintf("int(%v)", v.Length) + } + } + // ----------end + + // TODO:ForeignKey + + for _, v := range Keys { + var tmp model.ColumnsInfo + tmp.Name = v.Name + tmp.Type = v.Type + FixNotes(&tmp, v.Desc) // 分析表注释 + + if v.Pk > 0 { // 主键,或者联合组件 + if lenPk <= 1 { // 主键 + tmp.Index = append(tmp.Index, model.KList{ + Key: model.ColumnsKeyPrimary, + Multi: false, + KeyType: "primaryKey", + }) + } else { + tmp.Index = append(tmp.Index, model.KList{ + Key: model.ColumnsKeyPrimary, + Multi: true, + KeyType: "FULLTEXT", + }) + } + } + + tmp.IsNull = (v.Isnull == 1) + + el = append(el, tmp) + } + return +} + +// getTables Get columns and comments.获取表列及注释 +func (m *mssqlModel) getTables(orm *gorm.DB) map[string]string { + tbDesc := make(map[string]string) + + // Get column names.获取列名 + if m.GetOriginTableNames() != "" { + sarr := strings.Split(m.GetOriginTableNames(), ",") + if len(sarr) != 0 { + for _, val := range sarr { + tbDesc[val] = "" + } + } + } else { + var list []TableDescription + err := orm.Raw(`SELECT DISTINCT + d.name, + f.value + FROM + syscolumns a + LEFT JOIN systypes b ON a.xusertype= b.xusertype + INNER JOIN sysobjects d ON a.id= d.id + AND d.xtype= 'U' + AND d.name<> 'dtproperties' + LEFT JOIN syscomments e ON a.cdefault= e.id + LEFT JOIN sys.extended_properties g ON a.id= G.major_id + AND a.colid= g.minor_id + LEFT JOIN sys.extended_properties f ON d.id= f.major_id + AND f.minor_id= 0 ;`).Scan(&list).Error + if err != nil { + if !config.GetIsGUI() { + fmt.Println(err) + } + return tbDesc + } + + for _, v := range list { + tbDesc[v.Name] = v.Value + } + } + + return tbDesc +} + +func assemblyTable(name string) string { + return "`" + name + "`" +}