diff --git a/Makefile b/Makefile index b5dea47..4702996 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,17 @@ all: # 构建 make tar windows: - CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o gormt.exe main.go + CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o gormt.exe main.go mac: - CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o gormt main.go + CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -o gormt main.go linux: - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o gormt main.go + CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o gormt main.go tar: # 打包 - CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o gormt.exe main.go + CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o gormt.exe main.go tar czvf gormt_windows.zip gormt.exe config.yml - CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o gormt main.go + CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -o gormt main.go tar czvf gormt_mac.zip gormt config.yml - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o gormt main.go + CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o gormt main.go tar czvf gormt_linux.zip gormt config.yml clear: test ! -d model/ || rm -rf model/* diff --git a/config.yml b/config.yml index 4297f9c..431fcc6 100644 --- a/config.yml +++ b/config.yml @@ -14,10 +14,11 @@ is_foreign_key : true # 是否导出外键关联 is_gui : false # 是否ui模式显示 is_table_name : false # 是否直接生成表名函数 is_null_to_point : false # 数据库默认 'DEFAULT NULL' 时设置结构为指针类型 -mysql_info: - host : 127.0.0.1 +db_info: + host : 127.0.0.1 # type=1的时候,host为yml文件全路径 port : 3306 username : root password : 123456 database : oauth_db + type: 0 # 数据库类型:0:mysql , 1:sqlite , 2:mssql diff --git a/data/cmd/cmd.go b/data/cmd/cmd.go index f744eb8..a43411d 100644 --- a/data/cmd/cmd.go +++ b/data/cmd/cmd.go @@ -13,7 +13,7 @@ import ( "gopkg.in/go-playground/validator.v9" ) -var mysqlInfo config.MysqlDbInfo +var mysqlInfo config.DBInfo var outDir string var singularTable bool var foreignKey bool @@ -78,20 +78,20 @@ func init() { func initConfig() { MergeMysqlDbInfo() validate := validator.New() - err := validate.Struct(config.GetMysqlDbInfo()) + err := validate.Struct(config.GetDbInfo()) if err != nil { mylog.Info("Can't read cmd: using (-h, --help) to get more info") mylog.Error(err) os.Exit(1) } else { mylog.Info("using database info:") - mylog.JSON(config.GetMysqlDbInfo()) + mylog.JSON(config.GetDbInfo()) } } // MergeMysqlDbInfo merge parm func MergeMysqlDbInfo() { - var tmp = config.GetMysqlDbInfo() + var tmp = config.GetDbInfo() if len(mysqlInfo.Database) > 0 { tmp.Database = mysqlInfo.Database } diff --git a/data/config/MyIni.go b/data/config/MyIni.go index 2da009f..bf5936a 100644 --- a/data/config/MyIni.go +++ b/data/config/MyIni.go @@ -9,50 +9,51 @@ import ( // Config custom config struct type Config struct { CfgBase `yaml:"base"` - MySQLInfo MysqlDbInfo `yaml:"mysql_info"` - OutDir string `yaml:"out_dir"` - URLTag string `yaml:"url_tag"` // url tag - Language string `yaml:"language"` // language - DbTag string `yaml:"db_tag"` // 数据库标签(gormt,db) - Simple bool `yaml:"simple"` - IsWEBTag bool `yaml:"is_web_tag"` - IsWebTagPkHidden bool `yaml:"is_web_tag_pk_hidden"` // web标记是否隐藏主键 - SingularTable bool `yaml:"singular_table"` - IsForeignKey bool `yaml:"is_foreign_key"` - IsOutSQL bool `yaml:"is_out_sql"` - IsOutFunc bool `yaml:"is_out_func"` - IsGUI bool `yaml:"is_gui"` // - IsTableName bool `yaml:"is_table_name"` - IsNullToPoint bool `yaml:"is_null_to_point"` // null to porint + DBInfo DBInfo `yaml:"db_info"` + OutDir string `yaml:"out_dir"` + URLTag string `yaml:"url_tag"` // url tag + Language string `yaml:"language"` // language + DbTag string `yaml:"db_tag"` // 数据库标签(gormt,db) + Simple bool `yaml:"simple"` + IsWEBTag bool `yaml:"is_web_tag"` + IsWebTagPkHidden bool `yaml:"is_web_tag_pk_hidden"` // web标记是否隐藏主键 + SingularTable bool `yaml:"singular_table"` + IsForeignKey bool `yaml:"is_foreign_key"` + IsOutSQL bool `yaml:"is_out_sql"` + IsOutFunc bool `yaml:"is_out_func"` + IsGUI bool `yaml:"is_gui"` // + IsTableName bool `yaml:"is_table_name"` + IsNullToPoint bool `yaml:"is_null_to_point"` // null to porint } -// MysqlDbInfo mysql database information. mysql 数据库信息 -type MysqlDbInfo struct { +// DBInfo mysql database information. mysql 数据库信息 +type DBInfo struct { Host string `validate:"required"` // Host. 地址 - Port int `validate:"required"` // Port 端口号 - Username string `validate:"required"` // Username 用户名 + Port int // Port 端口号 + Username string // Username 用户名 Password string // Password 密码 - Database string `validate:"required"` // Database 数据库名 + Database string // Database 数据库名 + Type int // 数据库类型:0:mysql 1:配置 } // SetMysqlDbInfo Update MySQL configuration information -func SetMysqlDbInfo(info *MysqlDbInfo) { - _map.MySQLInfo = *info +func SetMysqlDbInfo(info *DBInfo) { + _map.DBInfo = *info } -// GetMysqlDbInfo Get MySQL configuration information .获取mysql配置信息 -func GetMysqlDbInfo() MysqlDbInfo { - return _map.MySQLInfo +// GetDbInfo Get configuration information .获取数据配置信息 +func GetDbInfo() DBInfo { + return _map.DBInfo } // GetMysqlConStr Get MySQL connection string.获取mysql 连接字符串 func GetMysqlConStr() string { return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local&interpolateParams=True", - _map.MySQLInfo.Username, - _map.MySQLInfo.Password, - _map.MySQLInfo.Host, - _map.MySQLInfo.Port, - _map.MySQLInfo.Database, + _map.DBInfo.Username, + _map.DBInfo.Password, + _map.DBInfo.Host, + _map.DBInfo.Port, + _map.DBInfo.Database, ) } diff --git a/data/config/common.go b/data/config/common.go index 7d2e496..fef9c79 100644 --- a/data/config/common.go +++ b/data/config/common.go @@ -24,7 +24,7 @@ var _map = Config{ CfgBase: CfgBase{ IsDev: false, }, - MySQLInfo: MysqlDbInfo{ + DBInfo: DBInfo{ Host: "127.0.0.1", Port: 3306, Username: "root", @@ -65,11 +65,12 @@ func InitFile(filename string) error { if _, e := os.Stat(filename); e != nil { fmt.Println("init default config file: ", filename) if err := SaveToFile(); err == nil { - fmt.Println("done,please restart.") + InitFile(filename) + return nil } else { fmt.Println("shit,fail", err) } - os.Exit(0) + // os.Exit(0) } bs, err := ioutil.ReadFile(filename) if err != nil { diff --git a/data/dlg/common.go b/data/dlg/common.go index c8ed5be..590fbee 100644 --- a/data/dlg/common.go +++ b/data/dlg/common.go @@ -1,14 +1,17 @@ package dlg import ( + "fmt" "os/exec" "github.com/jroimartin/gocui" "github.com/xxjwxc/gormt/data/view/model" "github.com/xxjwxc/gormt/data/view/model/genmysql" + "github.com/xxjwxc/gormt/data/view/model/gensqlite" "github.com/xxjwxc/gormt/data/config" + "github.com/xxjwxc/public/mylog" "github.com/xxjwxc/public/tools" ) @@ -72,7 +75,18 @@ func getBool(bstr string) bool { } func generate(g *gocui.Gui, v *gocui.View) { - modeldb := genmysql.GetMysqlModel() + var modeldb model.IModel + switch config.GetDbInfo().Type { + case 0: + modeldb = genmysql.GetModel() + case 1: + modeldb = gensqlite.GetModel() + } + if modeldb == nil { + mylog.Error(fmt.Errorf("modeldb not fund : please check db_info.type (0:mysql , 1:sqlite , 2:mssql) ")) + return + } + pkg := modeldb.GenModel() // just for test // out, _ := json.Marshal(pkg) diff --git a/data/dlg/cui.go b/data/dlg/cui.go index e458103..c3cb67c 100644 --- a/data/dlg/cui.go +++ b/data/dlg/cui.go @@ -203,16 +203,18 @@ func enterSet(g *gocui.Gui, v *gocui.View) error { // add input field form.AddInputField("out_dir", SLocalize("out_dir"), formPart[0], formPart[1]).SetText(config.GetOutDir()). AddValidate("required input", requireValidator) - form.AddInputField("db_host", SLocalize("db_host"), formPart[0], formPart[1]).SetText(config.GetMysqlDbInfo().Host). + form.AddInputField("db_host", SLocalize("db_host"), formPart[0], formPart[1]).SetText(config.GetDbInfo().Host). AddValidate("required input", requireValidator) - form.AddInputField("db_port", SLocalize("db_port"), formPart[0], formPart[1]).SetText(tools.AsString(config.GetMysqlDbInfo().Port)). + form.AddInputField("db_port", SLocalize("db_port"), formPart[0], formPart[1]).SetText(tools.AsString(config.GetDbInfo().Port)). AddValidate("required input", requireValidator) - form.AddInputField("db_usename", SLocalize("db_usename"), formPart[0], formPart[1]).SetText(config.GetMysqlDbInfo().Username). + form.AddInputField("db_usename", SLocalize("db_usename"), formPart[0], formPart[1]).SetText(config.GetDbInfo().Username). AddValidate("required input", requireValidator) - form.AddInputField("db_pwd", SLocalize("db_pwd"), formPart[0], formPart[1]).SetText(config.GetMysqlDbInfo().Password). + form.AddInputField("db_pwd", SLocalize("db_pwd"), formPart[0], formPart[1]).SetText(config.GetDbInfo().Password). SetMask().SetMaskKeybinding(gocui.KeyCtrlA). AddValidate("required input", requireValidator) - form.AddInputField("db_name", SLocalize("db_name"), formPart[0], formPart[1]).SetText(config.GetMysqlDbInfo().Database). + form.AddInputField("db_name", SLocalize("db_name"), formPart[0], formPart[1]).SetText(config.GetDbInfo().Database). + AddValidate("required input", requireValidator) + form.AddInputField("db_type", SLocalize("db_type"), formPart[0], formPart[1]).SetText(tools.AsString(config.GetDbInfo().Type)). AddValidate("required input", requireValidator) // add select @@ -264,7 +266,7 @@ func buttonSave(g *gocui.Gui, v *gocui.View) error { mp := form.GetFieldTexts() config.SetOutDir(mp["out_dir"]) - var dbInfo config.MysqlDbInfo + var dbInfo config.DBInfo dbInfo.Host = mp["db_host"] port, err := strconv.Atoi(mp["db_port"]) if err != nil { diff --git a/data/view/cnf/def.go b/data/view/cnf/def.go index 91949aa..8125b49 100644 --- a/data/view/cnf/def.go +++ b/data/view/cnf/def.go @@ -40,6 +40,7 @@ var TypeMysqlDicMp = map[string]string{ "blob": "[]byte", "mediumblob": "[]byte", "longblob": "[]byte", + "integer": "int64", } // TypeMysqlMatchMp Fuzzy Matching Types.模糊匹配类型 @@ -58,6 +59,7 @@ var TypeMysqlMatchMp = map[string]string{ `^(enum)[(](.)+[)]`: "string", `^(varchar)[(]\d+[)]`: "string", `^(varbinary)[(]\d+[)]`: "[]byte", + `^(blob)[(]\d+[)]`: "[]byte", `^(binary)[(]\d+[)]`: "[]byte", `^(decimal)[(]\d+,\d+[)]`: "float64", `^(mediumint)[(]\d+[)]`: "string", @@ -66,4 +68,6 @@ var TypeMysqlMatchMp = map[string]string{ `^(float)[(]\d+,\d+[)] unsigned`: "float64", `^(datetime)[(]\d+[)]`: "time.Time", `^(bit)[(]\d+[)]`: "[]uint8", + `^(text)[(]\d+[)]`: "string", + `^(integer)[(]\d+[)]`: "int", } diff --git a/data/view/gtools/gtools.go b/data/view/gtools/gtools.go index 99e39c7..1416c10 100644 --- a/data/view/gtools/gtools.go +++ b/data/view/gtools/gtools.go @@ -1,6 +1,7 @@ package gtools import ( + "fmt" "os/exec" "github.com/xxjwxc/public/mylog" @@ -11,6 +12,7 @@ import ( "github.com/xxjwxc/gormt/data/config" "github.com/xxjwxc/gormt/data/view/model/genmysql" + "github.com/xxjwxc/gormt/data/view/model/gensqlite" "github.com/xxjwxc/public/tools" ) @@ -28,8 +30,20 @@ func showCmd() { // tt.Nickname = "ticket_001" // orm.Where("nickname = ?", "ticket_001").Find(&tt) // fmt.Println(tt) - modeldb := genmysql.GetMysqlModel() + var modeldb model.IModel + switch config.GetDbInfo().Type { + case 0: + modeldb = genmysql.GetModel() + case 1: + modeldb = gensqlite.GetModel() + } + if modeldb == nil { + mylog.Error(fmt.Errorf("modeldb not fund : please check db_info.type (0:mysql , 1:sqlite , 2:mssql) ")) + return + } + pkg := modeldb.GenModel() + // gencnf.GenOutPut(&pkg) // just for test // out, _ := json.Marshal(pkg) // tools.WriteFile("test.txt", []string{string(out)}, true) diff --git a/data/view/model/gencnf/gencnf.go b/data/view/model/gencnf/gencnf.go new file mode 100644 index 0000000..52b628a --- /dev/null +++ b/data/view/model/gencnf/gencnf.go @@ -0,0 +1,103 @@ +package gencnf + +import ( + "fmt" + "os" + "path" + "strings" + + "gopkg.in/yaml.v3" + + "github.com/xxjwxc/gormt/data/config" + "github.com/xxjwxc/gormt/data/view/model" + "github.com/xxjwxc/public/mylog" + "github.com/xxjwxc/public/tools" +) + +// GetCnfModel get model interface. 获取model接口 +func GetCnfModel() model.IModel { + //now just support mysql + return &CnfModel +} + +// GenOutPut 输出 +func GenOutPut(info *model.DBInfo) { + path := path.Join(config.GetOutDir(), info.DbName+".yml") + out, _ := yaml.Marshal(info) + + flag := os.O_CREATE | os.O_WRONLY | os.O_TRUNC + f, err := os.OpenFile(path, flag, 0666) + if err != nil { + mylog.Error(err) + return + } + defer f.Close() + f.Write(out) +} + +// CnfModel yaml model from IModel +var CnfModel cnfModel + +type cnfModel struct { +} + +// GenModel get model.DBInfo info.获取数据库相关属性 +func (m *cnfModel) GenModel() model.DBInfo { + var dbInfo model.DBInfo + // getPackageInfo(orm, &dbInfo) + // 添加逻辑 + dbInfo.PackageName = m.GetPkgName() + dbInfo.DbName = m.GetDbName() + return dbInfo +} + +// GetDbName get database name.获取数据库名字 +func (m *cnfModel) GetDbName() string { + dir := config.GetDbInfo().Host + dir = strings.Replace(dir, "\\", "/", -1) + if len(dir) > 0 { + if dir[len(dir)-1] == '/' { + dir = dir[:(len(dir) - 1)] + } + } + var dbName string + list := strings.Split(dir, "/") + if len(list) > 0 { + dbName = list[len(list)-1] + } + list = strings.Split(dbName, ".") + if len(list) > 0 { + dbName = list[0] + } + + if len(dbName) == 0 || dbName == "." { + panic(fmt.Sprintf("%v : db host config err.must file dir", dbName)) + } + + return dbName +} + +// GetPkgName package names through config outdir configuration.通过config outdir 配置获取包名 +func (m *cnfModel) 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 +} diff --git a/data/view/model/genmysql/common.go b/data/view/model/genmysql/common.go index b8e8215..dea79c4 100644 --- a/data/view/model/genmysql/common.go +++ b/data/view/model/genmysql/common.go @@ -47,8 +47,8 @@ func fixForeignKey(list []genForeignKey, columuName string, result *[]model.Fore } } -// GetMysqlModel get model interface. 获取model接口 -func GetMysqlModel() model.IModel { +// GetModel get model interface. 获取model接口 +func GetModel() model.IModel { //now just support mysql return &MySQLModel } diff --git a/data/view/model/genmysql/genmysql.go b/data/view/model/genmysql/genmysql.go index bb4ff03..81a4b66 100644 --- a/data/view/model/genmysql/genmysql.go +++ b/data/view/model/genmysql/genmysql.go @@ -23,7 +23,7 @@ func (m *mysqlModel) GenModel() model.DBInfo { defer orm.OnDestoryDB() var dbInfo model.DBInfo - getPackageInfo(orm, &dbInfo) + m.getPackageInfo(orm, &dbInfo) dbInfo.PackageName = m.GetPkgName() dbInfo.DbName = m.GetDbName() return dbInfo @@ -31,7 +31,7 @@ func (m *mysqlModel) GenModel() model.DBInfo { // GetDbName get database name.获取数据库名字 func (m *mysqlModel) GetDbName() string { - return config.GetMysqlDbInfo().Database + return config.GetDbInfo().Database } // GetPkgName package names through config outdir configuration.通过config outdir 配置获取包名 @@ -59,8 +59,8 @@ func (m *mysqlModel) GetPkgName() string { return pkgName } -func getPackageInfo(orm *mysqldb.MySqlDB, info *model.DBInfo) { - tabls := getTables(orm) // get table and notes +func (m *mysqlModel) getPackageInfo(orm *mysqldb.MySqlDB, info *model.DBInfo) { + tabls := m.getTables(orm) // get table and notes // if m := config.GetTableList(); len(m) > 0 { // // 制定了表之后 // newTabls := make(map[string]string) @@ -94,7 +94,7 @@ func getPackageInfo(orm *mysqldb.MySqlDB, info *model.DBInfo) { } // build element.构造元素 - tab.Em = getTableElement(orm, tabName) + tab.Em = m.getTableElement(orm, tabName) // --------end info.TabList = append(info.TabList, tab) @@ -106,7 +106,7 @@ func getPackageInfo(orm *mysqldb.MySqlDB, info *model.DBInfo) { } // getTableElement Get table columns and comments.获取表列及注释 -func getTableElement(orm *mysqldb.MySqlDB, tab string) (el []model.ColumnsInfo) { +func (m *mysqlModel) getTableElement(orm *mysqldb.MySqlDB, tab string) (el []model.ColumnsInfo) { keyNameCount := make(map[string]int) KeyColumnMp := make(map[string][]keys) // get keys @@ -133,7 +133,7 @@ func getTableElement(orm *mysqldb.MySqlDB, tab string) (el []model.ColumnsInfo) var foreignKeyList []genForeignKey if config.GetIsForeignKey() { sql := fmt.Sprintf(`select table_schema as table_schema,table_name as table_name,column_name as column_name,referenced_table_schema as referenced_table_schema,referenced_table_name as referenced_table_name,referenced_column_name as referenced_column_name - from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where table_schema = '%v' AND REFERENCED_TABLE_NAME IS NOT NULL AND TABLE_NAME = '%v'`, config.GetMysqlDbInfo().Database, tab) + from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where table_schema = '%v' AND REFERENCED_TABLE_NAME IS NOT NULL AND TABLE_NAME = '%v'`, m.GetDbName(), tab) orm.Raw(sql).Scan(&foreignKeyList) } // ------------------end @@ -189,7 +189,7 @@ func getTableElement(orm *mysqldb.MySqlDB, tab string) (el []model.ColumnsInfo) } // getTables Get columns and comments.获取表列及注释 -func getTables(orm *mysqldb.MySqlDB) map[string]string { +func (m *mysqlModel) getTables(orm *mysqldb.MySqlDB) map[string]string { tbDesc := make(map[string]string) // Get column names.获取列名 @@ -212,7 +212,7 @@ func getTables(orm *mysqldb.MySqlDB) map[string]string { rows.Close() // Get table annotations.获取表注释 - rows1, err := orm.Raw("SELECT TABLE_NAME,TABLE_COMMENT FROM information_schema.TABLES WHERE table_schema= '" + config.GetMysqlDbInfo().Database + "'").Rows() + rows1, err := orm.Raw("SELECT TABLE_NAME,TABLE_COMMENT FROM information_schema.TABLES WHERE table_schema= '" + m.GetDbName() + "'").Rows() if err != nil { if !config.GetIsGUI() { fmt.Println(err) diff --git a/data/view/model/gensqlite/common.go b/data/view/model/gensqlite/common.go new file mode 100644 index 0000000..cc0b96b --- /dev/null +++ b/data/view/model/gensqlite/common.go @@ -0,0 +1,74 @@ +package gensqlite + +import ( + "strings" + + "github.com/xxjwxc/gormt/data/config" + + "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.Name, "id") || + strings.EqualFold(v.Name, "created_at") || + strings.EqualFold(v.Name, "updated_at") || + strings.EqualFold(v.Name, "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 &SQLiteModel +} + +// FixElementNote 分析元素表注释 +func FixElementNote(em *model.ColumnsInfo, note string) { + matches := noteRegex.FindStringSubmatch(note) + if len(matches) < 2 { + em.Notes = note + return + } + em.Notes = note[len(matches[0]):] + + list := strings.Split(matches[1], ";") + for _, v := range list { + tmp := strings.Split(v, ":") + if len(tmp) == 2 { + if strings.EqualFold(tmp[0], "default") { // 默认值 + em.Default = tmp[1] + } + } + } +} diff --git a/data/view/model/gensqlite/def.go b/data/view/model/gensqlite/def.go new file mode 100644 index 0000000..1cca557 --- /dev/null +++ b/data/view/model/gensqlite/def.go @@ -0,0 +1,31 @@ +package gensqlite + +import "regexp" + +type keys struct { + NonUnique int `gorm:"column:Non_unique"` + KeyName string `gorm:"column:Key_name"` + ColumnName string `gorm:"column:Column_name"` +} + +// genColumns show full columns +type genColumns struct { + Name string `gorm:"column:name"` + Type string `gorm:"column:type"` + Pk int `gorm:"column:pk"` + NotNull int `gorm:"column:notnull"` +} + +//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.该索引受影响的表的哪一列 +} + +var noteRegex = regexp.MustCompile(`^\[@gormt\s(\S+)+\]`) diff --git a/data/view/model/gensqlite/gensqlite.go b/data/view/model/gensqlite/gensqlite.go new file mode 100644 index 0000000..8792cd2 --- /dev/null +++ b/data/view/model/gensqlite/gensqlite.go @@ -0,0 +1,197 @@ +package gensqlite + +import ( + "fmt" + "sort" + "strings" + + "github.com/xxjwxc/public/mylog" + + "github.com/jinzhu/gorm" + _ "github.com/mattn/go-sqlite3" + "github.com/xxjwxc/gormt/data/config" + "github.com/xxjwxc/gormt/data/view/model" + "github.com/xxjwxc/public/tools" +) + +// SQLiteModel mysql model from IModel +var SQLiteModel sqliteModel + +type sqliteModel struct { +} + +// GenModel get model.DBInfo info.获取数据库相关属性 +func (m *sqliteModel) GenModel() model.DBInfo { + db, err := gorm.Open("sqlite3", config.GetDbInfo().Host) + if err != nil { + mylog.Error(err) + return model.DBInfo{} + } + defer db.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 *sqliteModel) GetDbName() string { + dir := config.GetDbInfo().Host + dir = strings.Replace(dir, "\\", "/", -1) + if len(dir) > 0 { + if dir[len(dir)-1] == '/' { + dir = dir[:(len(dir) - 1)] + } + } + var dbName string + list := strings.Split(dir, "/") + if len(list) > 0 { + dbName = list[len(list)-1] + } + list = strings.Split(dbName, ".") + if len(list) > 0 { + dbName = list[0] + } + + if len(dbName) == 0 || dbName == "." { + panic(fmt.Sprintf("%v : db host config err.must file dir", dbName)) + } + + return dbName +} + +// GetPkgName package names through config outdir configuration.通过config outdir 配置获取包名 +func (m *sqliteModel) 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 *sqliteModel) getPackageInfo(orm *gorm.DB, info *model.DBInfo) { + tabls := m.getTables(orm) // get table and notes + for tabName, notes := range tabls { + var tab model.TabInfo + tab.Name = tabName + tab.Notes = notes + + if config.GetIsOutSQL() { + // Get create SQL statements.获取创建sql语句 + rows, err := orm.Raw("SELECT tbl_name,sql FROM sqlite_master WHERE type='table' AND name = " + 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 *sqliteModel) getTableElement(orm *gorm.DB, tab string) (el []model.ColumnsInfo) { + var list []genColumns + // Get table annotations.获取表注释 + orm.Raw(fmt.Sprintf("PRAGMA table_info(%v)", assemblyTable(tab))).Scan(&list) + // filter gorm.Model.过滤 gorm.Model + if filterModel(&list) { + el = append(el, model.ColumnsInfo{ + Type: "gorm.Model", + }) + } + // -----------------end + + // ForeignKey + var foreignKeyList []genForeignKey + if config.GetIsForeignKey() { + } + // ------------------end + + for _, v := range list { + var tmp model.ColumnsInfo + tmp.Name = v.Name + tmp.Type = v.Type + FixElementNote(&tmp, "") + if v.Pk == 1 { // 主键 + tmp.Index = append(tmp.Index, model.KList{ + Key: model.ColumnsKeyPrimary, + Multi: false, + }) + } + + tmp.IsNull = (v.NotNull != 1) + + // ForeignKey + fixForeignKey(foreignKeyList, tmp.Name, &tmp.ForeignKeyList) + // -----------------end + el = append(el, tmp) + } + return +} + +// getTables Get columns and comments.获取表列及注释 +func (m *sqliteModel) getTables(orm *gorm.DB) map[string]string { + tbDesc := make(map[string]string) + + // Get column names.获取列名 + var tables []string + + rows, err := orm.Raw("SELECT name FROM sqlite_master WHERE type='table'").Rows() + if err != nil { + if !config.GetIsGUI() { + fmt.Println(err) + } + return tbDesc + } + + for rows.Next() { + var table string + rows.Scan(&table) + if !strings.EqualFold(table, "sqlite_sequence") { // 剔除系统默认 + tables = append(tables, table) + tbDesc[table] = "" + } + } + rows.Close() + + // TODO.获取表注释 + + return tbDesc +} + +func assemblyTable(name string) string { + return "'" + name + "'" +} diff --git a/go.mod b/go.mod index aa03475..a15d0aa 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/jinzhu/gorm v1.9.12 github.com/jroimartin/gocui v0.4.0 github.com/leodido/go-urn v1.2.0 // indirect + github.com/mattn/go-sqlite3 v2.0.1+incompatible github.com/nicksnyder/go-i18n/v2 v2.0.3 github.com/spf13/cobra v1.0.0 github.com/xxjwxc/public v0.0.0-20200605161710-72fc28675475 @@ -17,4 +18,4 @@ require ( gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 ) -// replace github.com/xxjwxc/public => ../public \ No newline at end of file +// replace github.com/xxjwxc/public => ../public diff --git a/go.sum b/go.sum index a49d4d6..f7156b6 100644 --- a/go.sum +++ b/go.sum @@ -207,6 +207,7 @@ github.com/xxjwxc/public v0.0.0-20200604090416-5afd146414d5 h1:8AYUDpnj279r9Gf2J github.com/xxjwxc/public v0.0.0-20200604090416-5afd146414d5/go.mod h1:0BFWVHqt7nKW8MtIx7R7bOkoGQFFnKsaJeeVbkzY88E= github.com/xxjwxc/public v0.0.0-20200605161710-72fc28675475 h1:VDny2T9+fQwq9WZkwrnD7hfANzX5lUOx53l31NPA9T8= github.com/xxjwxc/public v0.0.0-20200605161710-72fc28675475/go.mod h1:0BFWVHqt7nKW8MtIx7R7bOkoGQFFnKsaJeeVbkzY88E= +github.com/xxjwxc/public v0.0.0-20200921104903-7ca9b2863090 h1:cmzvPQvZ94OAA6SY2JWvFr8BKJxFd6pa/TEC7ZZkATs= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= diff --git a/sql.yml b/sql.yml new file mode 100644 index 0000000..fdcc09e --- /dev/null +++ b/sql.yml @@ -0,0 +1,42 @@ +dbname: caoguo_db # 数据库名 +comment: 潮果 # 数据库描述 +dbs: [mysql] # 数据库类型 +tables: # 数据库表 + name: product_tbl # 表名 + comment: 递增Id # 表注释 + columns: # 表列信息 + [ + name: id , # 列名 + comment: 递增Id, # 列注释 + isnull: false , # 是否为空 + type: bigint(20) , # 类型 + default: 10, # 默认值 + klist: + [ + key: ColumnsKeyPrimary, + multi: true, # 是否多个(复合组建) + keyname: test, + ], + foreignkey: # 外键 + [ + tablename: product_tbl, # 该索引受影响的表 + columnname: id # 该索引受影响的表的哪一列 + ] + ],[ + name: id , # 列名 + comment: 递增Id, # 列注释 + isnull: false , # 是否为空 + type: bigint(20) , # 类型 + default: 10, # 默认值 + klist: + [ + key: ColumnsKeyPrimary, + multi: true, # 是否多个(复合组建) + keyname: test, + ] + foreignkey: # 外键 + [ + tablename: product_tbl, # 该索引受影响的表 + columnname: id # 该索引受影响的表的哪一列 + ] + ] \ No newline at end of file