mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-04 00:10:25 +08:00
refactor: 组件升级、代码优化
This commit is contained in:
@@ -4,22 +4,22 @@ go 1.20
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.9.0
|
||||
github.com/go-sql-driver/mysql v1.7.0
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/mojocn/base64Captcha v1.3.5 // 验证码
|
||||
github.com/pkg/sftp v1.13.5
|
||||
github.com/redis/go-redis/v9 v9.0.2
|
||||
github.com/redis/go-redis/v9 v9.0.4
|
||||
github.com/robfig/cron/v3 v3.0.1 // 定时任务
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/sirupsen/logrus v1.9.2
|
||||
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
|
||||
go.mongodb.org/mongo-driver v1.11.4 // mongo
|
||||
golang.org/x/crypto v0.8.0 // ssh
|
||||
golang.org/x/crypto v0.9.0 // ssh
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
// gorm
|
||||
gorm.io/driver/mysql v1.5.0
|
||||
gorm.io/gorm v1.25.0
|
||||
gorm.io/gorm v1.25.1
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -55,9 +55,9 @@ require (
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
||||
golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect
|
||||
golang.org/x/net v0.9.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
)
|
||||
|
||||
@@ -36,7 +36,7 @@ func (i *Index) Count(rc *req.Ctx) {
|
||||
dbNum = i.DbApp.Count(&dbentity.DbQuery{TagIds: tagIds})
|
||||
redisNum = i.RedisApp.Count(&redisentity.RedisQuery{TagIds: tagIds})
|
||||
}
|
||||
rc.ResData = map[string]interface{}{
|
||||
rc.ResData = map[string]any{
|
||||
"mongoNum": mongoNum,
|
||||
"machineNum": machienNum,
|
||||
"dbNum": dbNum,
|
||||
|
||||
@@ -266,7 +266,7 @@ func (d *Db) DumpSql(rc *req.Ctx) {
|
||||
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(dbmeta.GetCreateTableDdl(table)[0]["Create Table"].(string) + ";\n")
|
||||
writer.WriteString(dbmeta.GetCreateTableDdl(table) + ";\n")
|
||||
}
|
||||
|
||||
if !needData {
|
||||
@@ -339,7 +339,7 @@ func (d *Db) HintTables(rc *req.Ctx) {
|
||||
tables := dm.GetTables()
|
||||
tableNames := make([]string, 0)
|
||||
for _, v := range tables {
|
||||
tableNames = append(tableNames, v["tableName"].(string))
|
||||
tableNames = append(tableNames, v.TableName)
|
||||
}
|
||||
// key = 表名,value = 列名数组
|
||||
res := make(map[string][]string)
|
||||
@@ -353,15 +353,15 @@ func (d *Db) HintTables(rc *req.Ctx) {
|
||||
// 获取所有表下的所有列信息
|
||||
columnMds := dm.GetColumns(tableNames...)
|
||||
for _, v := range columnMds {
|
||||
tName := v["tableName"].(string)
|
||||
tName := v.TableName
|
||||
if res[tName] == nil {
|
||||
res[tName] = make([]string, 0)
|
||||
}
|
||||
|
||||
columnName := fmt.Sprintf("%s [%s]", v["columnName"], v["columnType"])
|
||||
comment := v["columnComment"]
|
||||
columnName := fmt.Sprintf("%s [%s]", v.ColumnName, v.ColumnType)
|
||||
comment := v.ColumnComment
|
||||
// 如果字段备注不为空,则加上备注信息
|
||||
if comment != nil && comment != "" {
|
||||
if comment != "" {
|
||||
columnName = fmt.Sprintf("%s[%s]", columnName, comment)
|
||||
}
|
||||
|
||||
|
||||
@@ -249,22 +249,15 @@ type DbInstance struct {
|
||||
|
||||
// 执行查询语句
|
||||
// 依次返回 列名数组,结果map,错误
|
||||
func (d *DbInstance) SelectData(execSql string) ([]string, []map[string]interface{}, error) {
|
||||
func (d *DbInstance) SelectData(execSql string) ([]string, []map[string]any, error) {
|
||||
return SelectDataByDb(d.db, execSql)
|
||||
}
|
||||
|
||||
// 将查询结果映射至struct,可具体参考sqlx库
|
||||
func (d *DbInstance) SelectData2Struct(execSql string, dest interface{}) error {
|
||||
func (d *DbInstance) SelectData2Struct(execSql string, dest any) error {
|
||||
return Select2StructByDb(d.db, execSql, dest)
|
||||
}
|
||||
|
||||
// 执行内部查询语句,不返回列名以及不限制行数
|
||||
// 依次返回 结果map,错误
|
||||
func (d *DbInstance) innerSelect(execSql string) ([]map[string]interface{}, error) {
|
||||
_, res, err := SelectDataByDb(d.db, execSql)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// 执行 update, insert, delete,建表等sql
|
||||
// 返回影响条数和错误
|
||||
func (d *DbInstance) Exec(sql string) (int64, error) {
|
||||
|
||||
@@ -1,32 +1,102 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"mayfly-go/pkg/biz"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 表信息
|
||||
type Table struct {
|
||||
TableName string `json:"tableName"` // 表名
|
||||
TableComment string `json:"tableComment"` // 表备注
|
||||
CreateTime string `json:"createTime"` // 创建时间
|
||||
TableRows int `json:"tableRows"`
|
||||
DataLength int64 `json:"dataLength"`
|
||||
IndexLength int64 `json:"indexLength"`
|
||||
}
|
||||
|
||||
// 表的列信息
|
||||
type Column struct {
|
||||
TableName string `json:"tableName"` // 表名
|
||||
ColumnName string `json:"columnName"` // 列名
|
||||
ColumnType string `json:"columnType"` // 列类型
|
||||
ColumnComment string `json:"columnComment"` // 列备注
|
||||
ColumnKey string `json:"columnKey"`
|
||||
ColumnDefault string `json:"columnDefault"`
|
||||
Nullable string `json:"nullable"` // 是否可为null
|
||||
Extra string `json:"extra"` // 其他信息
|
||||
}
|
||||
|
||||
// 表索引信息
|
||||
type Index struct {
|
||||
IndexName string `json:"indexName"` // 索引名
|
||||
ColumnName string `json:"columnName"` // 列名
|
||||
IndexType string `json:"indexType"` // 索引类型
|
||||
IndexComment string `json:"indexComment"` // 备注
|
||||
SeqInIndex int `json:"seqInIndex"`
|
||||
NonUnique int `json:"nonUnique"`
|
||||
}
|
||||
|
||||
// -----------------------------------元数据接口定义------------------------------------------
|
||||
// 数据库元信息接口(表、列、获取表数据等元信息)
|
||||
// 所有数据查出来直接用map接收,注意不同数据库实现该接口返回的map中的key需要统一.
|
||||
// 即: 使用别名统一即可。如table_name AS tableName
|
||||
type DbMetadata interface {
|
||||
|
||||
// 获取表基础元信息
|
||||
// 表名: tableName, 备注: tableComment
|
||||
GetTables() []map[string]interface{}
|
||||
GetTables() []Table
|
||||
|
||||
// 获取指定表名的所有列元信息
|
||||
// 表名: tableName, 列名: columnName, 列类型: columnType, 备注: columnComment, 是否可为null: nullable, 其他信息: extra
|
||||
GetColumns(tableNames ...string) []map[string]interface{}
|
||||
GetColumns(tableNames ...string) []Column
|
||||
|
||||
// 获取表主键字段名,没有主键标识则默认第一个字段
|
||||
GetPrimaryKey(tablename string) string
|
||||
|
||||
// 获取表信息,比GetTables获取更详细的表信息
|
||||
GetTableInfos() []map[string]interface{}
|
||||
GetTableInfos() []Table
|
||||
|
||||
// 获取表索引信息
|
||||
GetTableIndex(tableName string) []map[string]interface{}
|
||||
GetTableIndex(tableName string) []Index
|
||||
|
||||
// 获取建表ddl
|
||||
GetCreateTableDdl(tableName string) []map[string]interface{}
|
||||
GetCreateTableDdl(tableName string) string
|
||||
|
||||
// 获取指定表的数据-分页查询
|
||||
// @return columns: 列字段名;result: 结果集;error: 错误
|
||||
GetTableRecord(tableName string, pageNum, pageSize int) ([]string, []map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// ------------------------- 元数据sql操作 -------------------------
|
||||
//
|
||||
//go:embed metasql/*
|
||||
var metasql embed.FS
|
||||
|
||||
// sql缓存 key: sql备注的key 如:MYSQL_TABLE_MA value: sql内容
|
||||
var sqlCache = make(map[string]string, 20)
|
||||
|
||||
// 获取本地文件的sql内容,并进行解析,获取对应key的sql内容
|
||||
func GetLocalSql(file, key string) string {
|
||||
sql := sqlCache[key]
|
||||
if sql != "" {
|
||||
return sql
|
||||
}
|
||||
|
||||
bytes, err := metasql.ReadFile(file)
|
||||
biz.ErrIsNilAppendErr(err, "获取sql meta文件内容失败: %s")
|
||||
allSql := string(bytes)
|
||||
|
||||
sqls := strings.Split(allSql, "\n\n")
|
||||
var resSql string
|
||||
for _, sql := range sqls {
|
||||
// 获取sql第一行的sql备注信息如:--MYSQL_TABLE_MA 表信息元数据
|
||||
info := strings.SplitN(sql, "\n", 2)
|
||||
// 原始sql,即去除第一行的key与备注信息
|
||||
rowSql := info[1]
|
||||
// 获取sql key;如:MYSQL_TABLE_MA
|
||||
sqlKey := strings.Split(strings.Split(info[0], " ")[0], "--")[1]
|
||||
if key == sqlKey {
|
||||
resSql = rowSql
|
||||
}
|
||||
sqlCache[sqlKey] = rowSql
|
||||
}
|
||||
return resSql
|
||||
}
|
||||
|
||||
69
server/internal/db/application/metasql/mysql_meta.sql
Normal file
69
server/internal/db/application/metasql/mysql_meta.sql
Normal file
@@ -0,0 +1,69 @@
|
||||
--MYSQL_TABLE_MA 表信息元数据
|
||||
SELECT
|
||||
table_name tableName,
|
||||
table_comment tableComment
|
||||
from
|
||||
information_schema.tables
|
||||
WHERE
|
||||
table_schema = (
|
||||
SELECT
|
||||
database ()
|
||||
)
|
||||
|
||||
--MYSQL_TABLE_INFO 表详细信息
|
||||
SELECT
|
||||
table_name tableName,
|
||||
table_comment tableComment,
|
||||
table_rows tableRows,
|
||||
data_length dataLength,
|
||||
index_length indexLength,
|
||||
create_time createTime
|
||||
FROM
|
||||
information_schema.tables
|
||||
WHERE
|
||||
table_schema = (
|
||||
SELECT
|
||||
database ()
|
||||
)
|
||||
|
||||
--MYSQL_INDEX_INFO 索引信息
|
||||
SELECT
|
||||
index_name indexName,
|
||||
column_name columnName,
|
||||
index_type indexType,
|
||||
non_unique nonUnique,
|
||||
SEQ_IN_INDEX seqInIndex,
|
||||
INDEX_COMMENT indexComment
|
||||
FROM
|
||||
information_schema.STATISTICS
|
||||
WHERE
|
||||
table_schema = (
|
||||
SELECT
|
||||
database ()
|
||||
)
|
||||
AND table_name = '%s'
|
||||
ORDER BY
|
||||
index_name asc,
|
||||
SEQ_IN_INDEX asc
|
||||
|
||||
--MYSQL_COLUMN_MA 列信息元数据
|
||||
SELECT
|
||||
table_name tableName,
|
||||
column_name columnName,
|
||||
column_type columnType,
|
||||
column_default columnDefault,
|
||||
column_comment columnComment,
|
||||
column_key columnKey,
|
||||
extra extra,
|
||||
is_nullable nullable
|
||||
from
|
||||
information_schema.columns
|
||||
WHERE
|
||||
table_schema = (
|
||||
SELECT
|
||||
database ()
|
||||
)
|
||||
AND table_name in (%s)
|
||||
ORDER BY
|
||||
tableName,
|
||||
ordinal_position
|
||||
169
server/internal/db/application/metasql/pgsql_meta.sql
Normal file
169
server/internal/db/application/metasql/pgsql_meta.sql
Normal file
@@ -0,0 +1,169 @@
|
||||
--PGSQL_TABLE_MA 表信息元数据
|
||||
SELECT
|
||||
obj_description (c.oid) AS "tableComment",
|
||||
c.relname AS "tableName"
|
||||
FROM
|
||||
pg_class c
|
||||
JOIN pg_namespace n ON c.relnamespace = n.oid
|
||||
WHERE
|
||||
n.nspname = (
|
||||
select
|
||||
current_schema ()
|
||||
)
|
||||
AND c.reltype > 0
|
||||
|
||||
--PGSQL_TABLE_INFO 表详细信息
|
||||
SELECT
|
||||
obj_description (c.oid) AS "tableComment",
|
||||
c.relname AS "tableName",
|
||||
pg_table_size ('"' || n.nspname || '"."' || c.relname || '"') as "dataLength",
|
||||
pg_indexes_size ('"' || n.nspname || '"."' || c.relname || '"') as "indexLength",
|
||||
c.reltuples as "tableRows"
|
||||
FROM
|
||||
pg_class c
|
||||
JOIN pg_namespace n ON c.relnamespace = n.oid
|
||||
WHERE
|
||||
n.nspname = (
|
||||
select
|
||||
current_schema ()
|
||||
)
|
||||
AND c.reltype > 0
|
||||
|
||||
--PGSQL_INDEX_INFO 表索引信息
|
||||
SELECT
|
||||
indexname AS "indexName",
|
||||
indexdef AS "indexComment"
|
||||
FROM
|
||||
pg_indexes
|
||||
WHERE
|
||||
schemaname = (
|
||||
select
|
||||
current_schema ()
|
||||
)
|
||||
AND tablename = '%s'
|
||||
|
||||
--PGSQL_COLUMN_MA 表列信息
|
||||
SELECT
|
||||
C.relname AS "tableName",
|
||||
A.attname AS "columnName",
|
||||
tc.is_nullable AS "nullable",
|
||||
concat_ws ( '', t.typname, SUBSTRING ( format_type ( a.atttypid, a.atttypmod ) FROM '\(.*\)' ) ) AS "columnType",
|
||||
(CASE WHEN ( SELECT COUNT(*) FROM pg_constraint WHERE conrelid = a.attrelid AND conkey[1]= attnum AND contype = 'p' ) > 0 THEN 'PRI' ELSE '' END ) AS "columnKey",
|
||||
d.description AS "columnComment"
|
||||
FROM
|
||||
pg_attribute a LEFT JOIN pg_description d ON d.objoid = a.attrelid
|
||||
AND d.objsubid = A.attnum
|
||||
LEFT JOIN pg_class c ON A.attrelid = c.oid
|
||||
LEFT JOIN pg_namespace pn ON c.relnamespace = pn.oid
|
||||
LEFT JOIN pg_type t ON a.atttypid = t.oid
|
||||
JOIN information_schema.columns tc ON tc.column_name = a.attname AND tc.table_name = C.relname AND tc.table_schema = pn.nspname
|
||||
WHERE
|
||||
A.attnum >= 0
|
||||
AND pn.nspname = (select current_schema())
|
||||
AND C.relname in (%s)
|
||||
ORDER BY
|
||||
C.relname DESC,
|
||||
A.attnum ASC
|
||||
|
||||
--PGSQL_TABLE_DDL_FUNC 表ddl函数
|
||||
CREATE OR REPLACE FUNCTION showcreatetable(namespace character varying, tablename character varying)
|
||||
RETURNS character varying AS
|
||||
$BODY$
|
||||
declare
|
||||
tableScript character varying default '';
|
||||
begin
|
||||
-- columns
|
||||
tableScript:=tableScript || ' CREATE TABLE '|| tablename|| ' ( '|| chr(13)||chr(10) || array_to_string(
|
||||
array(
|
||||
select ' ' || concat_ws(' ',fieldName, fieldType, fieldLen, indexType, isNullStr, fieldComment ) as column_line
|
||||
from (
|
||||
select a.attname as fieldName,format_type(a.atttypid,a.atttypmod) as fieldType,(case when atttypmod-4>0 then
|
||||
atttypmod-4 else 0 end) as fieldLen,
|
||||
(case when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum and
|
||||
contype='p')>0 then 'PRI'
|
||||
when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum and contype='u')>0
|
||||
then 'UNI'
|
||||
when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum and contype='f')>0
|
||||
then 'FRI'
|
||||
else '' end) as indexType,
|
||||
(case when a.attnotnull=true then 'not null' else 'null' end) as isNullStr,
|
||||
' comment ' || col_description(a.attrelid,a.attnum) as fieldComment
|
||||
from pg_attribute a where attstattarget=-1 and attrelid = (select c.oid from pg_class c,pg_namespace n where
|
||||
c.relnamespace=n.oid and n.nspname =namespace and relname =tablename)
|
||||
) as string_columns
|
||||
),','||chr(13)||chr(10)) || ',';
|
||||
-- 约束
|
||||
tableScript:= tableScript || chr(13)||chr(10) || array_to_string(
|
||||
array(
|
||||
select concat(' CONSTRAINT ',conname ,c ,u,p,f) from (
|
||||
select conname,
|
||||
case when contype='c' then ' CHECK('|| ( select findattname(namespace,tablename,'c') ) ||')' end as c ,
|
||||
case when contype='u' then ' UNIQUE('|| ( select findattname(namespace,tablename,'u') ) ||')' end as u ,
|
||||
case when contype='p' then ' PRIMARY KEY ('|| ( select findattname(namespace,tablename,'p') ) ||')' end as p ,
|
||||
case when contype='f' then ' FOREIGN KEY('|| ( select findattname(namespace,tablename,'u') ) ||') REFERENCES '||
|
||||
(select p.relname from pg_class p where p.oid=c.confrelid ) || '('|| ( select
|
||||
findattname(namespace,tablename,'u') ) ||')' end as f
|
||||
from pg_constraint c
|
||||
where contype in('u','c','f','p') and conrelid=(
|
||||
select oid from pg_class where relname=tablename and relnamespace =(
|
||||
select oid from pg_namespace where nspname = namespace
|
||||
)
|
||||
)
|
||||
) as t
|
||||
) ,',' || chr(13)||chr(10) ) || chr(13)||chr(10) ||' ); ';
|
||||
-- indexs
|
||||
-- CREATE UNIQUE INDEX pg_language_oid_index ON pg_language USING btree (oid); -- table pg_language
|
||||
--
|
||||
/** **/
|
||||
--- 获取非约束索引 column
|
||||
-- CREATE UNIQUE INDEX pg_language_oid_index ON pg_language USING btree (oid); -- table pg_language
|
||||
tableScript:= tableScript || chr(13)||chr(10) || chr(13)||chr(10) || array_to_string(
|
||||
array(
|
||||
select 'CREATE INDEX ' || indexrelname || ' ON ' || tablename || ' USING btree '|| '(' || attname || ');' from (
|
||||
SELECT
|
||||
i.relname AS indexrelname , x.indkey,
|
||||
( select array_to_string (
|
||||
array(
|
||||
select a.attname from pg_attribute a where attrelid=c.oid and a.attnum in ( select unnest(x.indkey) )
|
||||
)
|
||||
,',' ) )as attname
|
||||
FROM pg_class c
|
||||
JOIN pg_index x ON c.oid = x.indrelid
|
||||
JOIN pg_class i ON i.oid = x.indexrelid
|
||||
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relname=tablename and i.relname not in
|
||||
( select constraint_name from information_schema.key_column_usage where table_name=tablename )
|
||||
)as t
|
||||
) ,','|| chr(13)||chr(10));
|
||||
-- COMMENT COMMENT ON COLUMN sys_activity.id IS '主键';
|
||||
tableScript:= tableScript || chr(13)||chr(10) || chr(13)||chr(10) || array_to_string(
|
||||
array(
|
||||
SELECT 'COMMENT ON COLUMN' || tablename || '.' || a.attname ||' IS '|| ''''|| d.description ||''''
|
||||
FROM pg_class c
|
||||
JOIN pg_description d ON c.oid=d.objoid
|
||||
JOIN pg_attribute a ON c.oid = a.attrelid
|
||||
WHERE c.relname=tablename
|
||||
AND a.attnum = d.objsubid),','|| chr(13)||chr(10)) ;
|
||||
return tableScript;
|
||||
end
|
||||
$BODY$ LANGUAGE plpgsql;
|
||||
CREATE OR REPLACE FUNCTION findattname(namespace character varying, tablename character varying, ctype character
|
||||
varying)
|
||||
RETURNS character varying as $BODY$
|
||||
declare
|
||||
tt oid ;
|
||||
aname character varying default '';
|
||||
begin
|
||||
tt := oid from pg_class where relname= tablename and relnamespace =(select oid from pg_namespace where
|
||||
nspname=namespace) ;
|
||||
aname:= array_to_string(
|
||||
array(
|
||||
select a.attname from pg_attribute a
|
||||
where a.attrelid=tt and a.attnum in (
|
||||
select unnest(conkey) from pg_constraint c where contype=ctype
|
||||
and conrelid=tt and array_to_string(conkey,',') is not null
|
||||
)
|
||||
),',');
|
||||
return aname;
|
||||
end
|
||||
$BODY$ LANGUAGE plpgsql
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"mayfly-go/internal/db/domain/entity"
|
||||
machineapp "mayfly-go/internal/machine/application"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/utils"
|
||||
"net"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
@@ -30,25 +31,11 @@ func getMysqlDB(d *entity.Db, db string) (*sql.DB, error) {
|
||||
|
||||
// ---------------------------------- mysql元数据 -----------------------------------
|
||||
const (
|
||||
// mysql 表信息元数据
|
||||
MYSQL_TABLE_MA = `SELECT table_name tableName, table_comment tableComment from information_schema.tables WHERE table_schema = (SELECT database())`
|
||||
|
||||
// mysql 表信息
|
||||
MYSQL_TABLE_INFO = `SELECT table_name tableName, table_comment tableComment, table_rows tableRows,
|
||||
data_length dataLength, index_length indexLength, create_time createTime
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = (SELECT database())`
|
||||
|
||||
// mysql 索引信息
|
||||
MYSQL_INDEX_INFO = `SELECT index_name indexName, column_name columnName, index_type indexType, non_unique nonUnique,
|
||||
SEQ_IN_INDEX seqInIndex, INDEX_COMMENT indexComment
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE table_schema = (SELECT database()) AND table_name = '%s' ORDER BY index_name asc , SEQ_IN_INDEX asc`
|
||||
|
||||
// mysql 列信息元数据
|
||||
MYSQL_COLUMN_MA = `SELECT table_name tableName, column_name columnName, column_type columnType, column_default columnDefault,
|
||||
column_comment columnComment, column_key columnKey, extra, is_nullable nullable from information_schema.columns
|
||||
WHERE table_schema = (SELECT database()) AND table_name in (%s) ORDER BY tableName, ordinal_position`
|
||||
MYSQL_META_FILE = "metasql/mysql_meta.sql"
|
||||
MYSQL_TABLE_MA_KEY = "MYSQL_TABLE_MA"
|
||||
MYSQL_TABLE_INFO_KEY = "MYSQL_TABLE_INFO"
|
||||
MYSQL_INDEX_INFO_KEY = "MYSQL_INDEX_INFO"
|
||||
MYSQL_COLUMN_MA_KEY = "MYSQL_COLUMN_MA"
|
||||
)
|
||||
|
||||
type MysqlMetadata struct {
|
||||
@@ -56,14 +43,22 @@ type MysqlMetadata struct {
|
||||
}
|
||||
|
||||
// 获取表基础元信息, 如表名等
|
||||
func (mm *MysqlMetadata) GetTables() []map[string]interface{} {
|
||||
res, err := mm.di.innerSelect(MYSQL_TABLE_MA)
|
||||
func (mm *MysqlMetadata) GetTables() []Table {
|
||||
_, res, err := mm.di.SelectData(GetLocalSql(MYSQL_META_FILE, MYSQL_TABLE_MA_KEY))
|
||||
biz.ErrIsNilAppendErr(err, "获取表基本信息失败: %s")
|
||||
return res
|
||||
|
||||
tables := make([]Table, 0)
|
||||
for _, re := range res {
|
||||
tables = append(tables, Table{
|
||||
TableName: re["tableName"].(string),
|
||||
TableComment: utils.Any2String(re["tableComment"]),
|
||||
})
|
||||
}
|
||||
return tables
|
||||
}
|
||||
|
||||
// 获取列元信息, 如列名等
|
||||
func (mm *MysqlMetadata) GetColumns(tableNames ...string) []map[string]interface{} {
|
||||
func (mm *MysqlMetadata) GetColumns(tableNames ...string) []Column {
|
||||
tableName := ""
|
||||
for i := 0; i < len(tableNames); i++ {
|
||||
if i != 0 {
|
||||
@@ -71,9 +66,22 @@ func (mm *MysqlMetadata) GetColumns(tableNames ...string) []map[string]interface
|
||||
}
|
||||
tableName = tableName + "'" + tableNames[i] + "'"
|
||||
}
|
||||
result, err := mm.di.innerSelect(fmt.Sprintf(MYSQL_COLUMN_MA, tableName))
|
||||
|
||||
_, res, err := mm.di.SelectData(fmt.Sprintf(GetLocalSql(MYSQL_META_FILE, MYSQL_COLUMN_MA_KEY), tableName))
|
||||
biz.ErrIsNilAppendErr(err, "获取数据库列信息失败: %s")
|
||||
return result
|
||||
columns := make([]Column, 0)
|
||||
for _, re := range res {
|
||||
columns = append(columns, Column{
|
||||
TableName: re["tableName"].(string),
|
||||
ColumnName: re["columnName"].(string),
|
||||
ColumnType: utils.Any2String(re["columnType"]),
|
||||
ColumnComment: utils.Any2String(re["columnComment"]),
|
||||
Nullable: utils.Any2String(re["nullable"]),
|
||||
ColumnKey: utils.Any2String(re["columnKey"]),
|
||||
ColumnDefault: utils.Any2String(re["columnDefault"]),
|
||||
})
|
||||
}
|
||||
return columns
|
||||
}
|
||||
|
||||
// 获取表主键字段名,不存在主键标识则默认第一个字段
|
||||
@@ -81,36 +89,59 @@ func (mm *MysqlMetadata) GetPrimaryKey(tablename string) string {
|
||||
columns := mm.GetColumns(tablename)
|
||||
biz.IsTrue(len(columns) > 0, "[%s] 表不存在", tablename)
|
||||
for _, v := range columns {
|
||||
if v["columnKey"].(string) == "PRI" {
|
||||
return v["columnName"].(string)
|
||||
if v.ColumnKey == "PRI" {
|
||||
return v.ColumnName
|
||||
}
|
||||
}
|
||||
|
||||
return columns[0]["columnName"].(string)
|
||||
return columns[0].ColumnName
|
||||
}
|
||||
|
||||
// 获取表信息,比GetTableMetedatas获取更详细的表信息
|
||||
func (mm *MysqlMetadata) GetTableInfos() []map[string]interface{} {
|
||||
res, err := mm.di.innerSelect(MYSQL_TABLE_INFO)
|
||||
func (mm *MysqlMetadata) GetTableInfos() []Table {
|
||||
_, res, err := mm.di.SelectData(GetLocalSql(MYSQL_META_FILE, MYSQL_TABLE_INFO_KEY))
|
||||
biz.ErrIsNilAppendErr(err, "获取表信息失败: %s")
|
||||
return res
|
||||
|
||||
tables := make([]Table, 0)
|
||||
for _, re := range res {
|
||||
tables = append(tables, Table{
|
||||
TableName: re["tableName"].(string),
|
||||
TableComment: utils.Any2String(re["tableComment"]),
|
||||
CreateTime: utils.Any2String(re["createTime"]),
|
||||
TableRows: utils.Any2Int(re["tableRows"]),
|
||||
DataLength: utils.Any2Int64(re["dataLength"]),
|
||||
IndexLength: utils.Any2Int64(re["indexLength"]),
|
||||
})
|
||||
}
|
||||
return tables
|
||||
}
|
||||
|
||||
// 获取表索引信息
|
||||
func (mm *MysqlMetadata) GetTableIndex(tableName string) []map[string]interface{} {
|
||||
res, err := mm.di.innerSelect(fmt.Sprintf(MYSQL_INDEX_INFO, tableName))
|
||||
func (mm *MysqlMetadata) GetTableIndex(tableName string) []Index {
|
||||
_, res, err := mm.di.SelectData(fmt.Sprintf(GetLocalSql(MYSQL_META_FILE, MYSQL_INDEX_INFO_KEY), tableName))
|
||||
biz.ErrIsNilAppendErr(err, "获取表索引信息失败: %s")
|
||||
indexs := make([]Index, 0)
|
||||
for _, re := range res {
|
||||
indexs = append(indexs, Index{
|
||||
IndexName: re["indexName"].(string),
|
||||
ColumnName: utils.Any2String(re["columnName"]),
|
||||
IndexType: utils.Any2String(re["indexType"]),
|
||||
IndexComment: utils.Any2String(re["indexComment"]),
|
||||
NonUnique: utils.Any2Int(re["nonUnique"]),
|
||||
SeqInIndex: utils.Any2Int(re["seqInIndex"]),
|
||||
})
|
||||
}
|
||||
// 把查询结果以索引名分组,索引字段以逗号连接
|
||||
result := make([]map[string]interface{}, 0)
|
||||
result := make([]Index, 0)
|
||||
key := ""
|
||||
for _, v := range res {
|
||||
for _, v := range indexs {
|
||||
// 当前的索引名
|
||||
in := v["indexName"].(string)
|
||||
in := v.IndexName
|
||||
if key == in {
|
||||
// 索引字段已根据名称和顺序排序,故取最后一个即可
|
||||
i := len(result) - 1
|
||||
// 同索引字段以逗号连接
|
||||
result[i]["columnName"] = result[i]["columnName"].(string) + "," + v["columnName"].(string)
|
||||
result[i].ColumnName = result[i].ColumnName + "," + v.ColumnName
|
||||
} else {
|
||||
key = in
|
||||
result = append(result, v)
|
||||
@@ -120,9 +151,9 @@ func (mm *MysqlMetadata) GetTableIndex(tableName string) []map[string]interface{
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (mm *MysqlMetadata) GetCreateTableDdl(tableName string) []map[string]interface{} {
|
||||
res, _ := mm.di.innerSelect(fmt.Sprintf("show create table %s ", tableName))
|
||||
return res
|
||||
func (mm *MysqlMetadata) GetCreateTableDdl(tableName string) string {
|
||||
_, res, _ := mm.di.SelectData(fmt.Sprintf("show create table %s ", tableName))
|
||||
return res[0]["Create Table"].(string)
|
||||
}
|
||||
|
||||
func (mm *MysqlMetadata) GetTableRecord(tableName string, pageNum, pageSize int) ([]string, []map[string]interface{}, error) {
|
||||
|
||||
@@ -57,38 +57,12 @@ func (pd *PqSqlDialer) DialTimeout(network, address string, timeout time.Duratio
|
||||
|
||||
// ---------------------------------- pgsql元数据 -----------------------------------
|
||||
const (
|
||||
// postgres 表信息元数据
|
||||
PGSQL_TABLE_MA = `SELECT obj_description(c.oid) AS "tableComment", c.relname AS "tableName" FROM pg_class c
|
||||
JOIN pg_namespace n ON c.relnamespace = n.oid WHERE n.nspname = (select current_schema()) AND c.reltype > 0`
|
||||
|
||||
PGSQL_TABLE_INFO = `SELECT obj_description(c.oid) AS "tableComment", c.relname AS "tableName" FROM pg_class c
|
||||
JOIN pg_namespace n ON c.relnamespace = n.oid WHERE n.nspname = (select current_schema()) AND c.reltype > 0`
|
||||
|
||||
PGSQL_INDEX_INFO = `SELECT indexname AS "indexName", indexdef AS "indexComment"
|
||||
FROM pg_indexes WHERE schemaname = (select current_schema()) AND tablename = '%s'`
|
||||
|
||||
PGSQL_COLUMN_MA = `SELECT
|
||||
C.relname AS "tableName",
|
||||
A.attname AS "columnName",
|
||||
tc.is_nullable AS "nullable",
|
||||
concat_ws ( '', t.typname, SUBSTRING ( format_type ( a.atttypid, a.atttypmod ) FROM '\(.*\)' ) ) AS "columnType",
|
||||
(CASE WHEN ( SELECT COUNT(*) FROM pg_constraint WHERE conrelid = a.attrelid AND conkey[1]= attnum AND contype = 'p' ) > 0 THEN 'PRI' ELSE '' END ) AS "columnKey",
|
||||
d.description AS "columnComment"
|
||||
FROM
|
||||
pg_attribute a LEFT JOIN pg_description d ON d.objoid = a.attrelid
|
||||
AND d.objsubid = A.attnum
|
||||
LEFT JOIN pg_class c ON A.attrelid = c.oid
|
||||
LEFT JOIN pg_namespace pn ON c.relnamespace = pn.oid
|
||||
LEFT JOIN pg_type t ON a.atttypid = t.oid
|
||||
JOIN information_schema.columns tc ON tc.column_name = a.attname AND tc.table_name = C.relname AND tc.table_schema = pn.nspname
|
||||
WHERE
|
||||
A.attnum >= 0
|
||||
AND pn.nspname = (select current_schema())
|
||||
AND C.relname in (%s)
|
||||
ORDER BY
|
||||
C.relname DESC,
|
||||
A.attnum ASC
|
||||
`
|
||||
PGSQL_META_FILE = "metasql/pgsql_meta.sql"
|
||||
PGSQL_TABLE_MA_KEY = "PGSQL_TABLE_MA"
|
||||
PGSQL_TABLE_INFO_KEY = "PGSQL_TABLE_INFO"
|
||||
PGSQL_INDEX_INFO_KEY = "PGSQL_INDEX_INFO"
|
||||
PGSQL_COLUMN_MA_KEY = "PGSQL_COLUMN_MA"
|
||||
PGSQL_TABLE_DDL_KEY = "PGSQL_TABLE_DDL_FUNC"
|
||||
)
|
||||
|
||||
type PgsqlMetadata struct {
|
||||
@@ -96,14 +70,22 @@ type PgsqlMetadata struct {
|
||||
}
|
||||
|
||||
// 获取表基础元信息, 如表名等
|
||||
func (pm *PgsqlMetadata) GetTables() []map[string]interface{} {
|
||||
res, err := pm.di.innerSelect(PGSQL_TABLE_MA)
|
||||
func (pm *PgsqlMetadata) GetTables() []Table {
|
||||
_, res, err := pm.di.SelectData(GetLocalSql(PGSQL_META_FILE, PGSQL_TABLE_MA_KEY))
|
||||
biz.ErrIsNilAppendErr(err, "获取表基本信息失败: %s")
|
||||
return res
|
||||
|
||||
tables := make([]Table, 0)
|
||||
for _, re := range res {
|
||||
tables = append(tables, Table{
|
||||
TableName: re["tableName"].(string),
|
||||
TableComment: utils.Any2String(re["tableComment"]),
|
||||
})
|
||||
}
|
||||
return tables
|
||||
}
|
||||
|
||||
// 获取列元信息, 如列名等
|
||||
func (pm *PgsqlMetadata) GetColumns(tableNames ...string) []map[string]interface{} {
|
||||
func (pm *PgsqlMetadata) GetColumns(tableNames ...string) []Column {
|
||||
tableName := ""
|
||||
for i := 0; i < len(tableNames); i++ {
|
||||
if i != 0 {
|
||||
@@ -111,41 +93,86 @@ func (pm *PgsqlMetadata) GetColumns(tableNames ...string) []map[string]interface
|
||||
}
|
||||
tableName = tableName + "'" + tableNames[i] + "'"
|
||||
}
|
||||
result, err := pm.di.innerSelect(fmt.Sprintf(PGSQL_COLUMN_MA, tableName))
|
||||
|
||||
_, res, err := pm.di.SelectData(fmt.Sprintf(GetLocalSql(PGSQL_META_FILE, PGSQL_COLUMN_MA_KEY), tableName))
|
||||
biz.ErrIsNilAppendErr(err, "获取数据库列信息失败: %s")
|
||||
return result
|
||||
columns := make([]Column, 0)
|
||||
for _, re := range res {
|
||||
columns = append(columns, Column{
|
||||
TableName: re["tableName"].(string),
|
||||
ColumnName: re["columnName"].(string),
|
||||
ColumnType: utils.Any2String(re["columnType"]),
|
||||
ColumnComment: utils.Any2String(re["columnComment"]),
|
||||
Nullable: utils.Any2String(re["nullable"]),
|
||||
ColumnKey: utils.Any2String(re["columnKey"]),
|
||||
ColumnDefault: utils.Any2String(re["columnDefault"]),
|
||||
})
|
||||
}
|
||||
return columns
|
||||
}
|
||||
|
||||
func (pm *PgsqlMetadata) GetPrimaryKey(tablename string) string {
|
||||
columns := pm.GetColumns(tablename)
|
||||
biz.IsTrue(len(columns) > 0, "[%s] 表不存在", tablename)
|
||||
for _, v := range columns {
|
||||
if v["columnKey"].(string) == "PRI" {
|
||||
return v["columnName"].(string)
|
||||
if v.ColumnKey == "PRI" {
|
||||
return v.ColumnName
|
||||
}
|
||||
}
|
||||
|
||||
return columns[0]["columnName"].(string)
|
||||
return columns[0].ColumnName
|
||||
}
|
||||
|
||||
// 获取表信息,比GetTables获取更详细的表信息
|
||||
func (pm *PgsqlMetadata) GetTableInfos() []map[string]interface{} {
|
||||
res, err := pm.di.innerSelect(PGSQL_TABLE_INFO)
|
||||
func (pm *PgsqlMetadata) GetTableInfos() []Table {
|
||||
_, res, err := pm.di.SelectData(GetLocalSql(PGSQL_META_FILE, PGSQL_TABLE_INFO_KEY))
|
||||
biz.ErrIsNilAppendErr(err, "获取表信息失败: %s")
|
||||
return res
|
||||
|
||||
tables := make([]Table, 0)
|
||||
for _, re := range res {
|
||||
tables = append(tables, Table{
|
||||
TableName: re["tableName"].(string),
|
||||
TableComment: utils.Any2String(re["tableComment"]),
|
||||
CreateTime: utils.Any2String(re["createTime"]),
|
||||
TableRows: utils.Any2Int(re["tableRows"]),
|
||||
DataLength: utils.Any2Int64(re["dataLength"]),
|
||||
IndexLength: utils.Any2Int64(re["indexLength"]),
|
||||
})
|
||||
}
|
||||
return tables
|
||||
}
|
||||
|
||||
// 获取表索引信息
|
||||
func (pm *PgsqlMetadata) GetTableIndex(tableName string) []map[string]interface{} {
|
||||
res, err := pm.di.innerSelect(fmt.Sprintf(PGSQL_INDEX_INFO, tableName))
|
||||
func (pm *PgsqlMetadata) GetTableIndex(tableName string) []Index {
|
||||
_, res, err := pm.di.SelectData(fmt.Sprintf(GetLocalSql(PGSQL_META_FILE, PGSQL_INDEX_INFO_KEY), tableName))
|
||||
biz.ErrIsNilAppendErr(err, "获取表索引信息失败: %s")
|
||||
return res
|
||||
indexs := make([]Index, 0)
|
||||
for _, re := range res {
|
||||
indexs = append(indexs, Index{
|
||||
IndexName: re["indexName"].(string),
|
||||
ColumnName: utils.Any2String(re["columnName"]),
|
||||
IndexType: utils.Any2String(re["indexType"]),
|
||||
IndexComment: utils.Any2String(re["indexComment"]),
|
||||
NonUnique: utils.Any2Int(re["nonUnique"]),
|
||||
SeqInIndex: utils.Any2Int(re["seqInIndex"]),
|
||||
})
|
||||
}
|
||||
return indexs
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (pm *PgsqlMetadata) GetCreateTableDdl(tableName string) []map[string]interface{} {
|
||||
biz.IsTrue(tableName == "", "暂不支持获取pgsql建表DDL")
|
||||
return nil
|
||||
func (pm *PgsqlMetadata) GetCreateTableDdl(tableName string) string {
|
||||
_, err := pm.di.Exec(GetLocalSql(PGSQL_META_FILE, PGSQL_TABLE_DDL_KEY))
|
||||
biz.ErrIsNilAppendErr(err, "创建ddl函数失败: %s")
|
||||
|
||||
_, schemaRes, _ := pm.di.SelectData("select current_schema() as schema")
|
||||
schemaName := schemaRes[0]["schema"].(string)
|
||||
|
||||
ddlSql := fmt.Sprintf("select showcreatetable('%s','%s') as sql", schemaName, tableName)
|
||||
_, res, err := pm.di.SelectData(ddlSql)
|
||||
|
||||
biz.ErrIsNilAppendErr(err, "获取表ddl失败: %s")
|
||||
return res[0]["sql"].(string)
|
||||
}
|
||||
|
||||
func (pm *PgsqlMetadata) GetTableRecord(tableName string, pageNum, pageSize int) ([]string, []map[string]interface{}, error) {
|
||||
|
||||
@@ -22,7 +22,7 @@ DROP TABLE IF EXISTS `t_db`;
|
||||
CREATE TABLE `t_db` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '数据库实例名称',
|
||||
`host` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
|
||||
`host` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
|
||||
`port` int(8) NOT NULL,
|
||||
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
|
||||
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"mayfly-go/pkg/utils"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
func InitTokenConfig() {
|
||||
|
||||
54
server/pkg/utils/any.go
Normal file
54
server/pkg/utils/any.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// any类型转换为string, 如果any为nil则返回空字符串
|
||||
func Any2String(val any) string {
|
||||
if value, ok := val.(string); !ok {
|
||||
return ""
|
||||
} else {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
// any类型转换为int(可将字符串或int64转换), 如果any为nil则返回0
|
||||
func Any2Int(val any) int {
|
||||
switch value := val.(type) {
|
||||
case int:
|
||||
return value
|
||||
case string:
|
||||
if intV, err := strconv.Atoi(value); err == nil {
|
||||
return intV
|
||||
}
|
||||
case int64:
|
||||
return int(value)
|
||||
case uint64:
|
||||
return int(value)
|
||||
case int32:
|
||||
return int(value)
|
||||
case uint32:
|
||||
return int(value)
|
||||
case int16:
|
||||
return int(value)
|
||||
case uint16:
|
||||
return int(value)
|
||||
case int8:
|
||||
return int(value)
|
||||
case uint8:
|
||||
return int(value)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// any类型转换为int64, 如果any为nil则返回0
|
||||
func Any2Int64(val any) int64 {
|
||||
if value, ok := val.(int64); !ok {
|
||||
return int64(Any2Int(val))
|
||||
} else {
|
||||
return value
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package assert
|
||||
import "fmt"
|
||||
|
||||
// 断言条件为真,不满足的panic
|
||||
func IsTrue(condition bool, panicMsg string, params ...interface{}) {
|
||||
func IsTrue(condition bool, panicMsg string, params ...any) {
|
||||
if !condition {
|
||||
if len(params) != 0 {
|
||||
panic(fmt.Sprintf(panicMsg, params...))
|
||||
@@ -12,10 +12,10 @@ func IsTrue(condition bool, panicMsg string, params ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func State(condition bool, panicMsg string, params ...interface{}) {
|
||||
func State(condition bool, panicMsg string, params ...any) {
|
||||
IsTrue(condition, panicMsg, params...)
|
||||
}
|
||||
|
||||
func NotEmpty(str string, panicMsg string, params ...interface{}) {
|
||||
func NotEmpty(str string, panicMsg string, params ...any) {
|
||||
IsTrue(str != "", panicMsg, params...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user