2021-09-11 14:04:09 +08:00
|
|
|
|
package api
|
2021-01-08 15:37:32 +08:00
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"fmt"
|
2022-06-30 16:42:25 +08:00
|
|
|
|
"io"
|
2022-06-02 17:41:11 +08:00
|
|
|
|
"mayfly-go/internal/devops/api/form"
|
|
|
|
|
|
"mayfly-go/internal/devops/api/vo"
|
|
|
|
|
|
"mayfly-go/internal/devops/application"
|
|
|
|
|
|
"mayfly-go/internal/devops/domain/entity"
|
|
|
|
|
|
sysApplication "mayfly-go/internal/sys/application"
|
|
|
|
|
|
"mayfly-go/pkg/biz"
|
|
|
|
|
|
"mayfly-go/pkg/ctx"
|
|
|
|
|
|
"mayfly-go/pkg/ginx"
|
|
|
|
|
|
"mayfly-go/pkg/model"
|
|
|
|
|
|
"mayfly-go/pkg/utils"
|
|
|
|
|
|
"mayfly-go/pkg/ws"
|
2021-01-08 15:37:32 +08:00
|
|
|
|
"strconv"
|
2021-04-21 10:22:09 +08:00
|
|
|
|
"strings"
|
2022-06-30 16:42:25 +08:00
|
|
|
|
"time"
|
2021-01-08 15:37:32 +08:00
|
|
|
|
|
2021-04-16 15:10:07 +08:00
|
|
|
|
"github.com/gin-gonic/gin"
|
2022-06-30 16:42:25 +08:00
|
|
|
|
"github.com/xwb1989/sqlparser"
|
2021-04-16 15:10:07 +08:00
|
|
|
|
)
|
2021-01-08 15:37:32 +08:00
|
|
|
|
|
2021-05-08 18:00:33 +08:00
|
|
|
|
type Db struct {
|
2022-06-16 15:55:18 +08:00
|
|
|
|
DbApp application.Db
|
|
|
|
|
|
DbSqlExecApp application.DbSqlExec
|
|
|
|
|
|
MsgApp sysApplication.Msg
|
|
|
|
|
|
ProjectApp application.Project
|
2021-05-08 18:00:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-06-30 16:42:25 +08:00
|
|
|
|
const DEFAULT_COLUMN_SIZE = 500
|
|
|
|
|
|
|
2021-01-08 15:37:32 +08:00
|
|
|
|
// @router /api/dbs [get]
|
2021-05-08 18:00:33 +08:00
|
|
|
|
func (d *Db) Dbs(rc *ctx.ReqCtx) {
|
2021-07-28 18:03:19 +08:00
|
|
|
|
g := rc.GinCtx
|
|
|
|
|
|
m := &entity.Db{EnvId: uint64(ginx.QueryInt(g, "envId", 0)),
|
|
|
|
|
|
ProjectId: uint64(ginx.QueryInt(g, "projectId", 0)),
|
|
|
|
|
|
}
|
2021-12-11 11:19:47 +08:00
|
|
|
|
m.CreatorId = rc.LoginAccount.Id
|
2021-05-08 18:00:33 +08:00
|
|
|
|
rc.ResData = d.DbApp.GetPageList(m, ginx.GetPageParam(rc.GinCtx), new([]vo.SelectDataDbVO))
|
2021-01-08 15:37:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
func (d *Db) Save(rc *ctx.ReqCtx) {
|
|
|
|
|
|
form := &form.DbForm{}
|
|
|
|
|
|
ginx.BindJsonAndValid(rc.GinCtx, form)
|
|
|
|
|
|
|
|
|
|
|
|
db := new(entity.Db)
|
|
|
|
|
|
utils.Copy(db, form)
|
2022-07-18 20:36:31 +08:00
|
|
|
|
|
|
|
|
|
|
// 密码解密,并使用解密后的赋值
|
|
|
|
|
|
originPwd, err := utils.DefaultRsaDecrypt(form.Password, true)
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
|
|
|
|
|
|
db.Password = originPwd
|
|
|
|
|
|
|
2022-07-14 11:39:12 +08:00
|
|
|
|
// 密码脱敏记录日志
|
|
|
|
|
|
form.Password = "****"
|
|
|
|
|
|
rc.ReqParam = form
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
db.SetBaseInfo(rc.LoginAccount)
|
|
|
|
|
|
d.DbApp.Save(db)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-07-23 16:41:04 +08:00
|
|
|
|
// 获取数据库实例的所有数据库名
|
|
|
|
|
|
func (d *Db) GetDatabaseNames(rc *ctx.ReqCtx) {
|
|
|
|
|
|
form := &form.DbForm{}
|
|
|
|
|
|
ginx.BindJsonAndValid(rc.GinCtx, form)
|
|
|
|
|
|
|
|
|
|
|
|
db := new(entity.Db)
|
|
|
|
|
|
utils.Copy(db, form)
|
|
|
|
|
|
|
|
|
|
|
|
// 密码解密,并使用解密后的赋值
|
|
|
|
|
|
originPwd, err := utils.DefaultRsaDecrypt(form.Password, true)
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
|
|
|
|
|
|
db.Password = originPwd
|
|
|
|
|
|
|
|
|
|
|
|
// 如果id不为空,并且密码为空则从数据库查询
|
|
|
|
|
|
if form.Id != 0 && db.Password == "" {
|
|
|
|
|
|
db = d.DbApp.GetById(form.Id)
|
|
|
|
|
|
}
|
|
|
|
|
|
rc.ResData = d.DbApp.GetDatabases(db)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
func (d *Db) DeleteDb(rc *ctx.ReqCtx) {
|
2022-06-16 15:55:18 +08:00
|
|
|
|
dbId := GetDbId(rc.GinCtx)
|
|
|
|
|
|
d.DbApp.Delete(dbId)
|
|
|
|
|
|
// 删除该库的sql执行记录
|
|
|
|
|
|
d.DbSqlExecApp.DeleteBy(&entity.DbSqlExec{DbId: dbId})
|
2021-07-28 18:03:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-18 17:57:33 +08:00
|
|
|
|
func (d *Db) TableInfos(rc *ctx.ReqCtx) {
|
2022-05-08 14:10:57 +08:00
|
|
|
|
rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetTableInfos()
|
2021-08-18 17:57:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (d *Db) TableIndex(rc *ctx.ReqCtx) {
|
|
|
|
|
|
tn := rc.GinCtx.Query("tableName")
|
|
|
|
|
|
biz.NotEmpty(tn, "tableName不能为空")
|
2022-05-08 14:10:57 +08:00
|
|
|
|
rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetTableIndex(tn)
|
2021-08-18 17:57:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (d *Db) GetCreateTableDdl(rc *ctx.ReqCtx) {
|
|
|
|
|
|
tn := rc.GinCtx.Query("tableName")
|
|
|
|
|
|
biz.NotEmpty(tn, "tableName不能为空")
|
2022-05-08 14:10:57 +08:00
|
|
|
|
rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetCreateTableDdl(tn)
|
2021-08-18 17:57:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
func (d *Db) ExecSql(rc *ctx.ReqCtx) {
|
2021-04-16 15:10:07 +08:00
|
|
|
|
g := rc.GinCtx
|
2022-06-16 15:55:18 +08:00
|
|
|
|
form := &form.DbSqlExecForm{}
|
|
|
|
|
|
ginx.BindJsonAndValid(g, form)
|
2022-04-22 17:49:21 +08:00
|
|
|
|
|
2022-06-16 15:55:18 +08:00
|
|
|
|
id := GetDbId(g)
|
|
|
|
|
|
db := form.Db
|
2022-05-08 14:10:57 +08:00
|
|
|
|
dbInstance := d.DbApp.GetDbInstance(id, db)
|
|
|
|
|
|
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbInstance.ProjectId), "%s")
|
2022-04-22 17:49:21 +08:00
|
|
|
|
|
2021-04-21 10:22:09 +08:00
|
|
|
|
// 去除前后空格及换行符
|
2022-06-16 15:55:18 +08:00
|
|
|
|
sql := strings.TrimFunc(form.Sql, func(r rune) bool {
|
2021-04-21 10:22:09 +08:00
|
|
|
|
s := string(r)
|
|
|
|
|
|
return s == " " || s == "\n"
|
|
|
|
|
|
})
|
2022-06-16 15:55:18 +08:00
|
|
|
|
|
2022-05-08 14:10:57 +08:00
|
|
|
|
rc.ReqParam = fmt.Sprintf("db: %d:%s | sql: %s", id, db, sql)
|
2021-04-21 10:22:09 +08:00
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
biz.NotEmpty(sql, "sql不能为空")
|
2022-06-30 16:42:25 +08:00
|
|
|
|
if strings.HasPrefix(sql, "SELECT") || strings.HasPrefix(sql, "select") || strings.HasPrefix(sql, "show") || strings.HasPrefix(sql, "explain") {
|
2022-04-22 17:49:21 +08:00
|
|
|
|
colNames, res, err := dbInstance.SelectData(sql)
|
2021-11-25 14:34:15 +08:00
|
|
|
|
biz.ErrIsNilAppendErr(err, "查询失败: %s")
|
2021-07-28 18:03:19 +08:00
|
|
|
|
colAndRes := make(map[string]interface{})
|
|
|
|
|
|
colAndRes["colNames"] = colNames
|
|
|
|
|
|
colAndRes["res"] = res
|
|
|
|
|
|
rc.ResData = colAndRes
|
|
|
|
|
|
} else {
|
2022-06-16 15:55:18 +08:00
|
|
|
|
// 根据执行sql,生成执行记录
|
|
|
|
|
|
execRecord := d.DbSqlExecApp.GenExecLog(rc.LoginAccount, id, db, sql, dbInstance)
|
|
|
|
|
|
|
2022-04-22 17:49:21 +08:00
|
|
|
|
rowsAffected, err := dbInstance.Exec(sql)
|
2021-11-25 14:34:15 +08:00
|
|
|
|
biz.ErrIsNilAppendErr(err, "执行失败: %s")
|
2021-07-28 18:03:19 +08:00
|
|
|
|
res := make([]map[string]string, 0)
|
|
|
|
|
|
resData := make(map[string]string)
|
|
|
|
|
|
resData["影响条数"] = fmt.Sprintf("%d", rowsAffected)
|
|
|
|
|
|
res = append(res, resData)
|
|
|
|
|
|
|
|
|
|
|
|
colAndRes := make(map[string]interface{})
|
|
|
|
|
|
colAndRes["colNames"] = []string{"影响条数"}
|
|
|
|
|
|
colAndRes["res"] = res
|
|
|
|
|
|
|
|
|
|
|
|
rc.ResData = colAndRes
|
2022-06-16 15:55:18 +08:00
|
|
|
|
// 保存sql执行记录
|
|
|
|
|
|
if res[0]["影响条数"] > "0" {
|
|
|
|
|
|
execRecord.Remark = form.Remark
|
|
|
|
|
|
d.DbSqlExecApp.Save(execRecord)
|
|
|
|
|
|
}
|
2021-07-28 18:03:19 +08:00
|
|
|
|
}
|
2021-01-08 15:37:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-11-25 14:34:15 +08:00
|
|
|
|
// 执行sql文件
|
|
|
|
|
|
func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
|
|
|
|
|
|
g := rc.GinCtx
|
|
|
|
|
|
fileheader, err := g.FormFile("file")
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "读取sql文件失败: %s")
|
|
|
|
|
|
|
|
|
|
|
|
file, _ := fileheader.Open()
|
|
|
|
|
|
filename := fileheader.Filename
|
2022-05-08 14:10:57 +08:00
|
|
|
|
dbId, db := GetIdAndDb(g)
|
2021-11-25 14:34:15 +08:00
|
|
|
|
|
2022-07-14 11:39:12 +08:00
|
|
|
|
rc.ReqParam = fmt.Sprintf("dbId: %d, db: %s, filename: %s", dbId, db, filename)
|
|
|
|
|
|
|
2021-11-25 14:34:15 +08:00
|
|
|
|
go func() {
|
2022-05-08 14:10:57 +08:00
|
|
|
|
db := d.DbApp.GetDbInstance(dbId, db)
|
2022-01-12 16:00:31 +08:00
|
|
|
|
|
|
|
|
|
|
dbEntity := d.DbApp.GetById(dbId)
|
|
|
|
|
|
dbInfo := fmt.Sprintf("于%s的%s环境", dbEntity.Name, dbEntity.Env)
|
|
|
|
|
|
|
2021-12-02 10:35:48 +08:00
|
|
|
|
defer func() {
|
|
|
|
|
|
if err := recover(); err != nil {
|
|
|
|
|
|
switch t := err.(type) {
|
|
|
|
|
|
case *biz.BizError:
|
2022-01-12 16:00:31 +08:00
|
|
|
|
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]%s执行失败: [%s]", filename, dbInfo, t.Error())))
|
2021-12-02 10:35:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
2022-05-08 14:10:57 +08:00
|
|
|
|
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, db.ProjectId), "%s")
|
2022-04-22 17:49:21 +08:00
|
|
|
|
|
2022-06-30 16:42:25 +08:00
|
|
|
|
tokens := sqlparser.NewTokenizer(file)
|
|
|
|
|
|
for {
|
|
|
|
|
|
stmt, err := sqlparser.ParseNext(tokens)
|
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
|
break
|
2021-11-25 14:34:15 +08:00
|
|
|
|
}
|
2022-06-30 16:42:25 +08:00
|
|
|
|
sql := sqlparser.String(stmt)
|
|
|
|
|
|
_, err = db.Exec(sql)
|
2021-11-25 14:34:15 +08:00
|
|
|
|
if err != nil {
|
2022-01-12 16:00:31 +08:00
|
|
|
|
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.ErrMsg("sql脚本执行失败", fmt.Sprintf("[%s]%s执行失败: [%s]", filename, dbInfo, err.Error())))
|
2021-11-25 14:34:15 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-01-12 16:00:31 +08:00
|
|
|
|
d.MsgApp.CreateAndSend(rc.LoginAccount, ws.SuccessMsg("sql脚本执行成功", fmt.Sprintf("[%s]%s执行完成", filename, dbInfo)))
|
2021-11-25 14:34:15 +08:00
|
|
|
|
}()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-06-30 16:42:25 +08:00
|
|
|
|
// 数据库dump
|
|
|
|
|
|
func (d *Db) DumpSql(rc *ctx.ReqCtx) {
|
|
|
|
|
|
g := rc.GinCtx
|
|
|
|
|
|
dbId, db := GetIdAndDb(g)
|
|
|
|
|
|
dumpType := g.Query("type")
|
|
|
|
|
|
tablesStr := g.Query("tables")
|
|
|
|
|
|
biz.NotEmpty(tablesStr, "请选择要导出的表")
|
|
|
|
|
|
tables := strings.Split(tablesStr, ",")
|
|
|
|
|
|
|
|
|
|
|
|
// 是否需要导出表结构
|
|
|
|
|
|
needStruct := dumpType == "1" || dumpType == "3"
|
|
|
|
|
|
// 是否需要导出数据
|
|
|
|
|
|
needData := dumpType == "2" || dumpType == "3"
|
|
|
|
|
|
|
2022-07-10 12:14:06 +08:00
|
|
|
|
dbInstance := d.DbApp.GetDbInstance(dbId, db)
|
|
|
|
|
|
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbInstance.ProjectId), "%s")
|
|
|
|
|
|
|
2022-06-30 16:42:25 +08:00
|
|
|
|
now := time.Now()
|
|
|
|
|
|
filename := fmt.Sprintf("%s.%s.sql", db, now.Format("200601021504"))
|
|
|
|
|
|
g.Header("Content-Type", "application/octet-stream")
|
|
|
|
|
|
g.Header("Content-Disposition", "attachment; filename="+filename)
|
|
|
|
|
|
|
|
|
|
|
|
writer := g.Writer
|
|
|
|
|
|
writer.WriteString("-- ----------------------------")
|
|
|
|
|
|
writer.WriteString("\n-- 导出平台: mayfly-go")
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf("\n-- 导出时间: %s ", now.Format("2006-01-02 15:04:05")))
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf("\n-- 导出数据库: %s ", db))
|
|
|
|
|
|
writer.WriteString("\n-- ----------------------------\n")
|
|
|
|
|
|
|
|
|
|
|
|
for _, table := range tables {
|
|
|
|
|
|
if needStruct {
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf("\n-- ----------------------------\n-- 表结构: %s \n-- ----------------------------\n", table))
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf("DROP TABLE IF EXISTS `%s`;\n", table))
|
|
|
|
|
|
writer.WriteString(dbInstance.GetCreateTableDdl(table)[0]["Create Table"].(string) + ";\n")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if !needData {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf("\n-- ----------------------------\n-- 表记录: %s \n-- ----------------------------\n", table))
|
|
|
|
|
|
writer.WriteString("BEGIN;\n")
|
|
|
|
|
|
|
|
|
|
|
|
countSql := fmt.Sprintf("SELECT COUNT(*) count FROM %s", table)
|
|
|
|
|
|
_, countRes, _ := dbInstance.SelectData(countSql)
|
|
|
|
|
|
// 查询出所有列信息总数,手动分页获取所有数据
|
|
|
|
|
|
maCount := int(countRes[0]["count"].(int64))
|
|
|
|
|
|
// 计算需要查询的页数
|
|
|
|
|
|
pageNum := maCount / DEFAULT_COLUMN_SIZE
|
|
|
|
|
|
if maCount%DEFAULT_COLUMN_SIZE > 0 {
|
|
|
|
|
|
pageNum++
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-07-10 12:14:06 +08:00
|
|
|
|
var sqlTmp string
|
|
|
|
|
|
switch dbInstance.Type {
|
|
|
|
|
|
case "mysql":
|
|
|
|
|
|
sqlTmp = "SELECT * FROM %s LIMIT %d, %d"
|
|
|
|
|
|
case "postgres":
|
|
|
|
|
|
sqlTmp = "SELECT * FROM %s OFFSET %d LIMIT %d"
|
|
|
|
|
|
}
|
2022-06-30 16:42:25 +08:00
|
|
|
|
for index := 0; index < pageNum; index++ {
|
|
|
|
|
|
sql := fmt.Sprintf(sqlTmp, table, index*DEFAULT_COLUMN_SIZE, DEFAULT_COLUMN_SIZE)
|
|
|
|
|
|
columns, result, _ := dbInstance.SelectData(sql)
|
|
|
|
|
|
|
|
|
|
|
|
insertSql := "INSERT INTO `%s` VALUES (%s);\n"
|
|
|
|
|
|
for _, res := range result {
|
|
|
|
|
|
var values []string
|
|
|
|
|
|
for _, column := range columns {
|
|
|
|
|
|
value := res[column]
|
|
|
|
|
|
if value == nil {
|
|
|
|
|
|
values = append(values, "NULL")
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
strValue, ok := value.(string)
|
|
|
|
|
|
if ok {
|
|
|
|
|
|
values = append(values, fmt.Sprintf("%#v", strValue))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
values = append(values, utils.ToString(value))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf(insertSql, table, strings.Join(values, ", ")))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
writer.WriteString("COMMIT;\n")
|
|
|
|
|
|
}
|
|
|
|
|
|
rc.NoRes = true
|
2022-07-14 11:39:12 +08:00
|
|
|
|
|
|
|
|
|
|
rc.ReqParam = fmt.Sprintf("dbId: %d, db: %s, tables: %s, dumpType: %s", dbId, db, tablesStr, dumpType)
|
2022-06-30 16:42:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-08 15:37:32 +08:00
|
|
|
|
// @router /api/db/:dbId/t-metadata [get]
|
2021-05-08 18:00:33 +08:00
|
|
|
|
func (d *Db) TableMA(rc *ctx.ReqCtx) {
|
2022-05-08 14:10:57 +08:00
|
|
|
|
dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
|
|
|
|
|
|
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
|
2022-04-22 17:49:21 +08:00
|
|
|
|
rc.ResData = dbi.GetTableMetedatas()
|
2021-01-08 15:37:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// @router /api/db/:dbId/c-metadata [get]
|
2021-05-08 18:00:33 +08:00
|
|
|
|
func (d *Db) ColumnMA(rc *ctx.ReqCtx) {
|
2021-04-16 15:10:07 +08:00
|
|
|
|
g := rc.GinCtx
|
|
|
|
|
|
tn := g.Query("tableName")
|
|
|
|
|
|
biz.NotEmpty(tn, "tableName不能为空")
|
2022-04-22 17:49:21 +08:00
|
|
|
|
|
2022-05-08 14:10:57 +08:00
|
|
|
|
dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
|
|
|
|
|
|
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
|
2022-04-22 17:49:21 +08:00
|
|
|
|
rc.ResData = dbi.GetColumnMetadatas(tn)
|
2021-01-08 15:37:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// @router /api/db/:dbId/hint-tables [get]
|
2021-05-08 18:00:33 +08:00
|
|
|
|
func (d *Db) HintTables(rc *ctx.ReqCtx) {
|
2022-05-08 14:10:57 +08:00
|
|
|
|
dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
|
|
|
|
|
|
biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
|
2021-07-28 18:03:19 +08:00
|
|
|
|
// 获取所有表
|
2021-04-16 15:10:07 +08:00
|
|
|
|
tables := dbi.GetTableMetedatas()
|
2021-07-28 18:03:19 +08:00
|
|
|
|
|
|
|
|
|
|
tableNames := make([]string, 0)
|
2021-04-16 15:10:07 +08:00
|
|
|
|
for _, v := range tables {
|
2022-06-16 15:55:18 +08:00
|
|
|
|
tableNames = append(tableNames, v["tableName"].(string))
|
2021-07-28 18:03:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
// key = 表名,value = 列名数组
|
|
|
|
|
|
res := make(map[string][]string)
|
|
|
|
|
|
|
2022-03-24 17:50:44 +08:00
|
|
|
|
// 表为空,则直接返回
|
|
|
|
|
|
if len(tableNames) == 0 {
|
|
|
|
|
|
rc.ResData = res
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有表下的所有列信息
|
|
|
|
|
|
columnMds := dbi.GetColumnMetadatas(tableNames...)
|
2021-07-28 18:03:19 +08:00
|
|
|
|
for _, v := range columnMds {
|
2022-06-16 15:55:18 +08:00
|
|
|
|
tName := v["tableName"].(string)
|
2021-07-28 18:03:19 +08:00
|
|
|
|
if res[tName] == nil {
|
|
|
|
|
|
res[tName] = make([]string, 0)
|
2021-01-08 15:37:32 +08:00
|
|
|
|
}
|
2021-07-28 18:03:19 +08:00
|
|
|
|
|
|
|
|
|
|
columnName := fmt.Sprintf("%s [%s]", v["columnName"], v["columnType"])
|
|
|
|
|
|
comment := v["columnComment"]
|
|
|
|
|
|
// 如果字段备注不为空,则加上备注信息
|
2022-07-10 12:14:06 +08:00
|
|
|
|
if comment != nil && comment != "" {
|
2021-07-28 18:03:19 +08:00
|
|
|
|
columnName = fmt.Sprintf("%s[%s]", columnName, comment)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
res[tName] = append(res[tName], columnName)
|
2021-04-16 15:10:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
rc.ResData = res
|
2021-01-08 15:37:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// @router /api/db/:dbId/sql [post]
|
2021-05-08 18:00:33 +08:00
|
|
|
|
func (d *Db) SaveSql(rc *ctx.ReqCtx) {
|
2021-04-16 15:10:07 +08:00
|
|
|
|
g := rc.GinCtx
|
|
|
|
|
|
account := rc.LoginAccount
|
|
|
|
|
|
dbSqlForm := &form.DbSqlSaveForm{}
|
|
|
|
|
|
ginx.BindJsonAndValid(g, dbSqlForm)
|
|
|
|
|
|
rc.ReqParam = dbSqlForm
|
2021-01-08 15:37:32 +08:00
|
|
|
|
|
2021-04-16 15:10:07 +08:00
|
|
|
|
dbId := GetDbId(g)
|
|
|
|
|
|
// 判断dbId是否存在
|
2021-05-08 20:50:34 +08:00
|
|
|
|
err := model.GetById(new(entity.Db), dbId)
|
2021-05-08 18:00:33 +08:00
|
|
|
|
biz.ErrIsNil(err, "该数据库信息不存在")
|
2021-01-08 15:37:32 +08:00
|
|
|
|
|
2021-04-16 15:10:07 +08:00
|
|
|
|
// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
|
2022-05-08 14:10:57 +08:00
|
|
|
|
dbSql := &entity.DbSql{Type: dbSqlForm.Type, DbId: dbId, Name: dbSqlForm.Name, Db: dbSqlForm.Db}
|
2021-04-16 15:10:07 +08:00
|
|
|
|
dbSql.CreatorId = account.Id
|
|
|
|
|
|
e := model.GetBy(dbSql)
|
2021-01-08 15:37:32 +08:00
|
|
|
|
|
2021-04-16 15:10:07 +08:00
|
|
|
|
dbSql.SetBaseInfo(account)
|
|
|
|
|
|
// 更新sql信息
|
|
|
|
|
|
dbSql.Sql = dbSqlForm.Sql
|
|
|
|
|
|
if e == nil {
|
|
|
|
|
|
model.UpdateById(dbSql)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
model.Insert(dbSql)
|
|
|
|
|
|
}
|
2021-01-08 15:37:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-12-20 20:42:52 +08:00
|
|
|
|
// 获取所有保存的sql names
|
|
|
|
|
|
func (d *Db) GetSqlNames(rc *ctx.ReqCtx) {
|
2022-05-08 14:10:57 +08:00
|
|
|
|
id, db := GetIdAndDb(rc.GinCtx)
|
2021-12-20 20:42:52 +08:00
|
|
|
|
// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
|
2022-05-08 14:10:57 +08:00
|
|
|
|
dbSql := &entity.DbSql{Type: 1, DbId: id, Db: db}
|
2021-12-20 20:42:52 +08:00
|
|
|
|
dbSql.CreatorId = rc.LoginAccount.Id
|
|
|
|
|
|
var sqls []entity.DbSql
|
|
|
|
|
|
model.ListBy(dbSql, &sqls, "id", "name")
|
|
|
|
|
|
|
|
|
|
|
|
rc.ResData = sqls
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除保存的sql
|
|
|
|
|
|
func (d *Db) DeleteSql(rc *ctx.ReqCtx) {
|
|
|
|
|
|
dbSql := &entity.DbSql{Type: 1, DbId: GetDbId(rc.GinCtx)}
|
|
|
|
|
|
dbSql.CreatorId = rc.LoginAccount.Id
|
|
|
|
|
|
dbSql.Name = rc.GinCtx.Query("name")
|
|
|
|
|
|
|
|
|
|
|
|
model.DeleteByCondition(dbSql)
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-08 15:37:32 +08:00
|
|
|
|
// @router /api/db/:dbId/sql [get]
|
2021-05-08 18:00:33 +08:00
|
|
|
|
func (d *Db) GetSql(rc *ctx.ReqCtx) {
|
2022-05-08 14:10:57 +08:00
|
|
|
|
id, db := GetIdAndDb(rc.GinCtx)
|
2021-12-20 20:42:52 +08:00
|
|
|
|
// 根据创建者id, 数据库id,以及sql模板名称查询保存的sql信息
|
2022-05-08 14:10:57 +08:00
|
|
|
|
dbSql := &entity.DbSql{Type: 1, DbId: id, Db: db}
|
2021-04-16 15:10:07 +08:00
|
|
|
|
dbSql.CreatorId = rc.LoginAccount.Id
|
2021-12-20 20:42:52 +08:00
|
|
|
|
dbSql.Name = rc.GinCtx.Query("name")
|
|
|
|
|
|
|
2021-04-16 15:10:07 +08:00
|
|
|
|
e := model.GetBy(dbSql)
|
|
|
|
|
|
if e != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
rc.ResData = dbSql
|
2021-01-08 15:37:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-16 15:10:07 +08:00
|
|
|
|
func GetDbId(g *gin.Context) uint64 {
|
|
|
|
|
|
dbId, _ := strconv.Atoi(g.Param("dbId"))
|
2021-03-24 17:18:39 +08:00
|
|
|
|
biz.IsTrue(dbId > 0, "dbId错误")
|
2021-01-08 15:37:32 +08:00
|
|
|
|
return uint64(dbId)
|
|
|
|
|
|
}
|
2022-05-08 14:10:57 +08:00
|
|
|
|
|
|
|
|
|
|
func GetIdAndDb(g *gin.Context) (uint64, string) {
|
|
|
|
|
|
db := g.Query("db")
|
|
|
|
|
|
biz.NotEmpty(db, "db不能为空")
|
|
|
|
|
|
return GetDbId(g), db
|
|
|
|
|
|
}
|