mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 15:30:25 +08:00
feat: 数据库表操作显示表size&其他小优化
This commit is contained in:
@@ -3,21 +3,16 @@
|
||||
* @param size byte size
|
||||
* @returns
|
||||
*/
|
||||
export function formatByteSize(size: any) {
|
||||
const value = Number(size);
|
||||
if (size && !isNaN(value)) {
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', 'BB'];
|
||||
let index = 0;
|
||||
let k = value;
|
||||
if (value >= 1024) {
|
||||
while (k > 1024) {
|
||||
k = k / 1024;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return `${k.toFixed(2)}${units[index]}`;
|
||||
export function formatByteSize(size: number, fixed = 2) {
|
||||
if (size === 0) {
|
||||
return '0B';
|
||||
}
|
||||
return '-';
|
||||
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
const base = 1024;
|
||||
const exponent = Math.floor(Math.log(size) / Math.log(base));
|
||||
|
||||
return parseFloat((size / Math.pow(base, exponent)).toFixed(fixed)) + units[exponent];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -169,7 +169,6 @@ self.MonacoEnvironment = {
|
||||
};
|
||||
|
||||
const state = reactive({
|
||||
editorHeight: '500px',
|
||||
languageMode: 'shell',
|
||||
});
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
<span class="ml3">
|
||||
<slot name="label" :data="data"> {{ data.label }}</slot>
|
||||
</span>
|
||||
|
||||
<slot :node="node" :data="data" name="suffix"></slot>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
|
||||
@@ -201,7 +201,7 @@ const columns = ref([
|
||||
TableColumn.new('tagPath', '标签路径').isSlot().setAddWidth(20),
|
||||
TableColumn.new('instanceName', '实例名'),
|
||||
TableColumn.new('type', '类型'),
|
||||
TableColumn.new('host', 'ip:port').isSlot().setAddWidth(20),
|
||||
TableColumn.new('host', 'ip:port').isSlot().setAddWidth(40),
|
||||
TableColumn.new('username', 'username'),
|
||||
TableColumn.new('name', '名称'),
|
||||
TableColumn.new('database', '数据库').isSlot().setMinWidth(70),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="db-sql-exec">
|
||||
<el-row class="mb5">
|
||||
<el-col :span="4">
|
||||
<el-button
|
||||
@@ -11,6 +11,7 @@
|
||||
>新建查询</el-button
|
||||
>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="20" v-if="state.db">
|
||||
<el-descriptions :column="4" size="small" border style="height: 10px" class="ml5">
|
||||
<el-descriptions-item label-align="right" label="tag">{{ nowDbInst.tagPath }}</el-descriptions-item>
|
||||
@@ -27,6 +28,7 @@
|
||||
</el-descriptions>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row type="flex">
|
||||
<el-col :span="4">
|
||||
<tag-tree
|
||||
@@ -74,8 +76,13 @@
|
||||
|
||||
<SvgIcon name="Files" v-if="data.type == NodeType.SqlMenu || data.type == NodeType.Sql" color="#f56c6c" />
|
||||
</template>
|
||||
|
||||
<template #suffix="{ data }">
|
||||
<span class="db-table-size" v-if="data.type == NodeType.Table">{{ ` ${data.params.size}` }}</span>
|
||||
</template>
|
||||
</tag-tree>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="20">
|
||||
<el-container id="data-exec" class="mt5 ml5">
|
||||
<el-tabs @tab-remove="onRemoveTab" @tab-change="onTabChange" style="width: 100%" v-model="state.activeName">
|
||||
@@ -110,7 +117,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, onMounted, reactive, ref, toRefs, onBeforeUnmount } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import { formatByteSize } from '@/common/utils/format';
|
||||
import { DbInst, TabInfo, TabType, registerDbCompletionItemProvider } from './db';
|
||||
import { TagTreeNode } from '../component/tag';
|
||||
import TagTree from '../component/TagTree.vue';
|
||||
@@ -304,6 +311,7 @@ const getTables = async (params: any) => {
|
||||
db,
|
||||
tableName: x.tableName,
|
||||
tableComment: x.tableComment,
|
||||
size: formatByteSize(x.dataLength + x.indexLength, 1),
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -461,47 +469,54 @@ const reloadTables = (nodeKey: string) => {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.sql-file-exec {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
}
|
||||
.db-sql-exec {
|
||||
.sql-file-exec {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sqlEditor {
|
||||
font-size: 8pt;
|
||||
font-weight: 600;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.db-table-size {
|
||||
color: #c4c9c4;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.editor-move-resize {
|
||||
cursor: n-resize;
|
||||
height: 3px;
|
||||
text-align: center;
|
||||
}
|
||||
.sqlEditor {
|
||||
font-size: 8pt;
|
||||
font-weight: 600;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
#data-exec {
|
||||
min-height: calc(100vh - 155px);
|
||||
.editor-move-resize {
|
||||
cursor: n-resize;
|
||||
height: 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-tabs__header {
|
||||
margin: 0 0 5px;
|
||||
#data-exec {
|
||||
min-height: calc(100vh - 155px);
|
||||
|
||||
.el-tabs__item {
|
||||
padding: 0 5px;
|
||||
.el-tabs__header {
|
||||
margin: 0 0 5px;
|
||||
|
||||
.el-tabs__item {
|
||||
padding: 0 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.update_field_active {
|
||||
background-color: var(--el-color-success);
|
||||
}
|
||||
|
||||
.instances-pop-form {
|
||||
.el-form-item {
|
||||
margin-bottom: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.update_field_active {
|
||||
background-color: var(--el-color-success);
|
||||
}
|
||||
|
||||
.instances-pop-form {
|
||||
.el-form-item {
|
||||
margin-bottom: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,7 +10,6 @@ export const dbApi = {
|
||||
tableInfos: Api.newGet('/dbs/{id}/t-infos'),
|
||||
tableIndex: Api.newGet('/dbs/{id}/t-index'),
|
||||
tableDdl: Api.newGet('/dbs/{id}/t-create-ddl'),
|
||||
tableMetadata: Api.newGet('/dbs/{id}/t-metadata'),
|
||||
columnMetadata: Api.newGet('/dbs/{id}/c-metadata'),
|
||||
// 获取表即列提示
|
||||
hintTables: Api.newGet('/dbs/{id}/hint-tables'),
|
||||
@@ -27,7 +26,7 @@ export const dbApi = {
|
||||
|
||||
// 获取权限列表
|
||||
instances: Api.newGet('/instances'),
|
||||
getInstance: Api.newGet("/instances/{instanceId}"),
|
||||
getInstance: Api.newGet('/instances/{instanceId}'),
|
||||
getAllDatabase: Api.newGet('/instances/{instanceId}/databases'),
|
||||
saveInstance: Api.newPost('/instances'),
|
||||
getInstancePwd: Api.newGet('/instances/{id}/pwd'),
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<MonacoEditor ref="monacoEditorRef" class="mt5" v-model="state.sql" language="sql" :height="editorHeight" :id="'MonacoTextarea-' + ti.key" />
|
||||
<MonacoEditor ref="monacoEditorRef" class="mt5" v-model="state.sql" language="sql" :height="state.editorHeight" :id="'MonacoTextarea-' + ti.key" />
|
||||
|
||||
<div class="editor-move-resize" @mousedown="onDragSetHeight">
|
||||
<el-icon>
|
||||
|
||||
@@ -33,26 +33,26 @@
|
||||
<el-link @click="onDeleteData()" type="danger" icon="delete" :underline="false"></el-link>
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
|
||||
<el-tooltip class="box-item" effect="dark" content="commit" placement="top">
|
||||
<el-tooltip :show-after="500" class="box-item" effect="dark" content="commit" placement="top">
|
||||
<el-link @click="onCommit()" type="success" icon="CircleCheck" :underline="false"> </el-link>
|
||||
</el-tooltip>
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
|
||||
<el-tooltip class="box-item" effect="dark" content="生成insert sql" placement="top">
|
||||
<el-tooltip :show-after="500" class="box-item" effect="dark" content="生成insert sql" placement="top">
|
||||
<el-link @click="onGenerateInsertSql()" type="success" :underline="false">gi</el-link>
|
||||
</el-tooltip>
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
|
||||
<el-tooltip class="box-item" effect="dark" content="导出当前页的csv文件" placement="top">
|
||||
<el-tooltip :show-after="500" class="box-item" effect="dark" content="导出当前页的csv文件" placement="top">
|
||||
<el-link type="success" :underline="false" @click="exportData"><span class="f12">导出</span></el-link>
|
||||
</el-tooltip>
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
|
||||
<el-tooltip v-if="hasUpdatedFileds" class="box-item" effect="dark" content="提交修改" placement="top">
|
||||
<el-tooltip :show-after="500" v-if="hasUpdatedFileds" class="box-item" effect="dark" content="提交修改" placement="top">
|
||||
<el-link @click="submitUpdateFields()" type="success" :underline="false" class="f12">提交</el-link>
|
||||
</el-tooltip>
|
||||
<el-divider v-if="hasUpdatedFileds" direction="vertical" border-style="dashed" />
|
||||
<el-tooltip v-if="hasUpdatedFileds" class="box-item" effect="dark" content="取消修改" placement="top">
|
||||
<el-tooltip :show-after="500" v-if="hasUpdatedFileds" class="box-item" effect="dark" content="取消修改" placement="top">
|
||||
<el-link @click="cancelUpdateFields" type="warning" :underline="false" class="f12">取消</el-link>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
|
||||
@@ -88,7 +88,7 @@ export class DbInst {
|
||||
db.columnsMap?.clear();
|
||||
db.tableHints = null;
|
||||
console.log(`load tables -> dbName: ${dbName}`);
|
||||
tables = await dbApi.tableMetadata.request({ id: this.id, db: dbName });
|
||||
tables = await dbApi.tableInfos.request({ id: this.id, db: dbName });
|
||||
db.tables = tables;
|
||||
return tables;
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ const queryConfig = [TableQuery.slot('tagPath', '标签', 'tagPathSelect'), Tabl
|
||||
const columns = ref([
|
||||
TableColumn.new('tagPath', '标签路径').isSlot().setAddWidth(20),
|
||||
TableColumn.new('name', '名称'),
|
||||
TableColumn.new('ipPort', 'ip:port').isSlot().setAddWidth(45),
|
||||
TableColumn.new('ipPort', 'ip:port').isSlot().setAddWidth(50),
|
||||
TableColumn.new('username', '用户名'),
|
||||
TableColumn.new('status', '状态').isSlot().setMinWidth(85),
|
||||
TableColumn.new('remark', '备注'),
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, watch, ref, shallowReactive, reactive, computed, toRefs, onMounted } from 'vue';
|
||||
import { defineAsyncComponent, watch, ref, shallowReactive, reactive, computed, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import KeyHeader from './KeyHeader.vue';
|
||||
|
||||
@@ -107,8 +107,6 @@ watch(
|
||||
onMounted(() => {
|
||||
setKeyInfo(props.keyInfo);
|
||||
});
|
||||
|
||||
const {} = toRefs(state);
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.key-tab-container {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="key-header-item key-ttl-input">
|
||||
<el-input type="number" v-model.number="ki.timed" placeholder="单位(秒),负数永久" title="点击修改过期时间">
|
||||
<template #prepend>
|
||||
<span slot="prepend">TTL</span>
|
||||
<span>TTL</span>
|
||||
</template>
|
||||
|
||||
<template #suffix>
|
||||
@@ -37,8 +37,8 @@
|
||||
|
||||
<!-- del & refresh btn -->
|
||||
<div class="key-header-item key-header-btn-con">
|
||||
<el-button slot="reference" type="success" @click="refreshKey" icon="refresh" title="刷新"></el-button>
|
||||
<el-button v-auth="'redis:data:del'" slot="reference" type="danger" @click="delKey" icon="delete" title="删除"></el-button>
|
||||
<el-button type="success" @click="refreshKey" icon="refresh" title="刷新"></el-button>
|
||||
<el-button v-auth="'redis:data:del'" type="danger" @click="delKey" icon="delete" title="删除"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -74,6 +74,7 @@ const state = reactive({
|
||||
timed: -1,
|
||||
} as any,
|
||||
oldKey: '',
|
||||
memuse: 0,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@@ -114,14 +114,14 @@ const getListValue = async (resetTableData = false) => {
|
||||
state.loadMoreDisable = state.values.length === state.total;
|
||||
};
|
||||
|
||||
const lset = async (row: any, rowIndex: number) => {
|
||||
await redisApi.setListValue.request({
|
||||
...getBaseReqParam(),
|
||||
index: (state.pageNum - 1) * state.pageSize + rowIndex,
|
||||
value: row.value,
|
||||
});
|
||||
ElMessage.success('数据保存成功');
|
||||
};
|
||||
// const lset = async (row: any, rowIndex: number) => {
|
||||
// await redisApi.setListValue.request({
|
||||
// ...getBaseReqParam(),
|
||||
// index: (state.pageNum - 1) * state.pageSize + rowIndex,
|
||||
// value: row.value,
|
||||
// });
|
||||
// ElMessage.success('数据保存成功');
|
||||
// };
|
||||
|
||||
const showEditDialog = (row: any) => {
|
||||
state.editDialog.dataRow = row;
|
||||
|
||||
@@ -11,6 +11,7 @@ export const redisApi = {
|
||||
|
||||
keyInfo: Api.newGet('/redis/{id}/{db}/key-info'),
|
||||
keyTtl: Api.newGet('/redis/{id}/{db}/key-ttl'),
|
||||
keyMemuse: Api.newGet('/redis/{id}/{db}/key-memuse'),
|
||||
renameKey: Api.newPost('/redis/{id}/{db}/rename-key'),
|
||||
expireKey: Api.newPost('/redis/{id}/{db}/expire-key'),
|
||||
persistKey: Api.newDelete('/redis/{id}/{db}/persist-key'),
|
||||
|
||||
@@ -21,7 +21,7 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/sftp v1.13.6
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/redis/go-redis/v9 v9.2.1
|
||||
github.com/redis/go-redis/v9 v9.3.0
|
||||
github.com/robfig/cron/v3 v3.0.1 // 定时任务
|
||||
github.com/stretchr/testify v1.8.4
|
||||
go.mongodb.org/mongo-driver v1.12.1 // mongo
|
||||
|
||||
@@ -83,34 +83,6 @@ func (d *Db) DeleteDb(rc *req.Ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Db) getDbConn(g *gin.Context) *dbm.DbConn {
|
||||
dc, err := d.DbApp.GetDbConn(getDbId(g), getDbName(g))
|
||||
biz.ErrIsNil(err)
|
||||
return dc
|
||||
}
|
||||
|
||||
func (d *Db) TableInfos(rc *req.Ctx) {
|
||||
res, err := d.getDbConn(rc.GinCtx).GetMeta().GetTableInfos()
|
||||
biz.ErrIsNilAppendErr(err, "获取表信息失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (d *Db) TableIndex(rc *req.Ctx) {
|
||||
tn := rc.GinCtx.Query("tableName")
|
||||
biz.NotEmpty(tn, "tableName不能为空")
|
||||
res, err := d.getDbConn(rc.GinCtx).GetMeta().GetTableIndex(tn)
|
||||
biz.ErrIsNilAppendErr(err, "获取表索引信息失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (d *Db) GetCreateTableDdl(rc *req.Ctx) {
|
||||
tn := rc.GinCtx.Query("tableName")
|
||||
biz.NotEmpty(tn, "tableName不能为空")
|
||||
res, err := d.getDbConn(rc.GinCtx).GetMeta().GetCreateTableDdl(tn)
|
||||
biz.ErrIsNilAppendErr(err, "获取表ddl失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (d *Db) ExecSql(rc *req.Ctx) {
|
||||
g := rc.GinCtx
|
||||
form := &form.DbSqlExecForm{}
|
||||
@@ -348,7 +320,7 @@ func (d *Db) dumpDb(writer *gzipWriter, dbId uint64, dbName string, tables []str
|
||||
|
||||
dbMeta := dbConn.GetMeta()
|
||||
if len(tables) == 0 {
|
||||
ti, err := dbMeta.GetTableInfos()
|
||||
ti, err := dbMeta.GetTables()
|
||||
biz.ErrIsNil(err)
|
||||
tables = make([]string, len(ti))
|
||||
for i, table := range ti {
|
||||
@@ -396,11 +368,17 @@ func (d *Db) dumpDb(writer *gzipWriter, dbId uint64, dbName string, tables []str
|
||||
writer.WriteString(dbConn.Info.Type.StmtSetForeignKeyChecks(true))
|
||||
}
|
||||
|
||||
// @router /api/db/:dbId/t-metadata [get]
|
||||
func (d *Db) TableMA(rc *req.Ctx) {
|
||||
dbi := d.getDbConn(rc.GinCtx)
|
||||
res, err := dbi.GetMeta().GetTables()
|
||||
biz.ErrIsNilAppendErr(err, "获取表基础信息失败: %s")
|
||||
func (d *Db) TableInfos(rc *req.Ctx) {
|
||||
res, err := d.getDbConn(rc.GinCtx).GetMeta().GetTables()
|
||||
biz.ErrIsNilAppendErr(err, "获取表信息失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (d *Db) TableIndex(rc *req.Ctx) {
|
||||
tn := rc.GinCtx.Query("tableName")
|
||||
biz.NotEmpty(tn, "tableName不能为空")
|
||||
res, err := d.getDbConn(rc.GinCtx).GetMeta().GetTableIndex(tn)
|
||||
biz.ErrIsNilAppendErr(err, "获取表索引信息失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
@@ -458,6 +436,14 @@ func (d *Db) HintTables(rc *req.Ctx) {
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (d *Db) GetCreateTableDdl(rc *req.Ctx) {
|
||||
tn := rc.GinCtx.Query("tableName")
|
||||
biz.NotEmpty(tn, "tableName不能为空")
|
||||
res, err := d.getDbConn(rc.GinCtx).GetMeta().GetCreateTableDdl(tn)
|
||||
biz.ErrIsNilAppendErr(err, "获取表ddl失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
// @router /api/db/:dbId/sql [post]
|
||||
func (d *Db) SaveSql(rc *req.Ctx) {
|
||||
g := rc.GinCtx
|
||||
@@ -536,3 +522,9 @@ func getDbName(g *gin.Context) string {
|
||||
biz.NotEmpty(db, "db不能为空")
|
||||
return db
|
||||
}
|
||||
|
||||
func (d *Db) getDbConn(g *gin.Context) *dbm.DbConn {
|
||||
dc, err := d.DbApp.GetDbConn(getDbId(g), getDbName(g))
|
||||
biz.ErrIsNil(err)
|
||||
return dc
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ type Index struct {
|
||||
// 数据库元信息接口(表、列、获取表数据等元信息)
|
||||
type DbMetadata interface {
|
||||
|
||||
// 获取表基础元信息
|
||||
// 获取表信息
|
||||
GetTables() ([]Table, error)
|
||||
|
||||
// 获取指定表名的所有列元信息
|
||||
@@ -52,8 +52,8 @@ type DbMetadata interface {
|
||||
// 获取表主键字段名,没有主键标识则默认第一个字段
|
||||
GetPrimaryKey(tablename string) (string, error)
|
||||
|
||||
// 获取表信息,比GetTables获取更详细的表信息
|
||||
GetTableInfos() ([]Table, error)
|
||||
// // 获取表信息,比GetTables获取更详细的表信息
|
||||
// GetTableInfos() ([]Table, error)
|
||||
|
||||
// 获取表索引信息
|
||||
GetTableIndex(tableName string) ([]Index, error)
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
--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,
|
||||
@@ -21,7 +9,8 @@ SELECT
|
||||
FROM
|
||||
information_schema.tables
|
||||
WHERE
|
||||
table_schema = (
|
||||
table_type = 'BASE TABLE'
|
||||
AND table_schema = (
|
||||
SELECT
|
||||
database ()
|
||||
)
|
||||
|
||||
@@ -1,33 +1,22 @@
|
||||
--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 ()
|
||||
select
|
||||
c.relname as "tableName",
|
||||
obj_description (c.oid) as "tableComment",
|
||||
pg_table_size ('"' || n.nspname || '"."' || c.relname || '"') as "dataLength",
|
||||
pg_indexes_size ('"' || n.nspname || '"."' || c.relname || '"') as "indexLength",
|
||||
psut.n_live_tup as "tableRows"
|
||||
from
|
||||
pg_class c
|
||||
join pg_namespace n on
|
||||
c.relnamespace = n.oid
|
||||
join pg_stat_user_tables psut on
|
||||
psut.relid = c."oid"
|
||||
where
|
||||
n.nspname = (
|
||||
select
|
||||
current_schema ()
|
||||
)
|
||||
AND c.reltype > 0
|
||||
and c.reltype > 0
|
||||
---------------------------------------
|
||||
--PGSQL_INDEX_INFO 表索引信息
|
||||
SELECT
|
||||
|
||||
@@ -34,7 +34,6 @@ func getMysqlDB(d *DbInfo) (*sql.DB, error) {
|
||||
// ---------------------------------- mysql元数据 -----------------------------------
|
||||
const (
|
||||
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"
|
||||
@@ -46,7 +45,7 @@ type MysqlMetadata struct {
|
||||
|
||||
// 获取表基础元信息, 如表名等
|
||||
func (mm *MysqlMetadata) GetTables() ([]Table, error) {
|
||||
_, res, err := mm.dc.SelectData(GetLocalSql(MYSQL_META_FILE, MYSQL_TABLE_MA_KEY))
|
||||
_, res, err := mm.dc.SelectData(GetLocalSql(MYSQL_META_FILE, MYSQL_TABLE_INFO_KEY))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -56,6 +55,10 @@ func (mm *MysqlMetadata) GetTables() ([]Table, error) {
|
||||
tables = append(tables, Table{
|
||||
TableName: re["tableName"].(string),
|
||||
TableComment: anyx.ConvString(re["tableComment"]),
|
||||
CreateTime: anyx.ConvString(re["createTime"]),
|
||||
TableRows: anyx.ConvInt(re["tableRows"]),
|
||||
DataLength: anyx.ConvInt64(re["dataLength"]),
|
||||
IndexLength: anyx.ConvInt64(re["indexLength"]),
|
||||
})
|
||||
}
|
||||
return tables, nil
|
||||
@@ -110,27 +113,6 @@ func (mm *MysqlMetadata) GetPrimaryKey(tablename string) (string, error) {
|
||||
return columns[0].ColumnName, nil
|
||||
}
|
||||
|
||||
// 获取表信息,比GetTableMetedatas获取更详细的表信息
|
||||
func (mm *MysqlMetadata) GetTableInfos() ([]Table, error) {
|
||||
_, res, err := mm.dc.SelectData(GetLocalSql(MYSQL_META_FILE, MYSQL_TABLE_INFO_KEY))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tables := make([]Table, 0)
|
||||
for _, re := range res {
|
||||
tables = append(tables, Table{
|
||||
TableName: re["tableName"].(string),
|
||||
TableComment: anyx.ConvString(re["tableComment"]),
|
||||
CreateTime: anyx.ConvString(re["createTime"]),
|
||||
TableRows: anyx.ConvInt(re["tableRows"]),
|
||||
DataLength: anyx.ConvInt64(re["dataLength"]),
|
||||
IndexLength: anyx.ConvInt64(re["indexLength"]),
|
||||
})
|
||||
}
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
// 获取表索引信息
|
||||
func (mm *MysqlMetadata) GetTableIndex(tableName string) ([]Index, error) {
|
||||
_, res, err := mm.dc.SelectData(fmt.Sprintf(GetLocalSql(MYSQL_META_FILE, MYSQL_INDEX_INFO_KEY), tableName))
|
||||
|
||||
@@ -67,7 +67,6 @@ func (pd *PqSqlDialer) DialTimeout(network, address string, timeout time.Duratio
|
||||
// ---------------------------------- pgsql元数据 -----------------------------------
|
||||
const (
|
||||
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"
|
||||
@@ -80,7 +79,7 @@ type PgsqlMetadata struct {
|
||||
|
||||
// 获取表基础元信息, 如表名等
|
||||
func (pm *PgsqlMetadata) GetTables() ([]Table, error) {
|
||||
_, res, err := pm.dc.SelectData(GetLocalSql(PGSQL_META_FILE, PGSQL_TABLE_MA_KEY))
|
||||
_, res, err := pm.dc.SelectData(GetLocalSql(PGSQL_META_FILE, PGSQL_TABLE_INFO_KEY))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -90,6 +89,10 @@ func (pm *PgsqlMetadata) GetTables() ([]Table, error) {
|
||||
tables = append(tables, Table{
|
||||
TableName: re["tableName"].(string),
|
||||
TableComment: anyx.ConvString(re["tableComment"]),
|
||||
CreateTime: anyx.ConvString(re["createTime"]),
|
||||
TableRows: anyx.ConvInt(re["tableRows"]),
|
||||
DataLength: anyx.ConvInt64(re["dataLength"]),
|
||||
IndexLength: anyx.ConvInt64(re["indexLength"]),
|
||||
})
|
||||
}
|
||||
return tables, nil
|
||||
@@ -142,27 +145,6 @@ func (pm *PgsqlMetadata) GetPrimaryKey(tablename string) (string, error) {
|
||||
return columns[0].ColumnName, nil
|
||||
}
|
||||
|
||||
// 获取表信息,比GetTables获取更详细的表信息
|
||||
func (pm *PgsqlMetadata) GetTableInfos() ([]Table, error) {
|
||||
_, res, err := pm.dc.SelectData(GetLocalSql(PGSQL_META_FILE, PGSQL_TABLE_INFO_KEY))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tables := make([]Table, 0)
|
||||
for _, re := range res {
|
||||
tables = append(tables, Table{
|
||||
TableName: re["tableName"].(string),
|
||||
TableComment: anyx.ConvString(re["tableComment"]),
|
||||
CreateTime: anyx.ConvString(re["createTime"]),
|
||||
TableRows: anyx.ConvInt(re["tableRows"]),
|
||||
DataLength: anyx.ConvInt64(re["dataLength"]),
|
||||
IndexLength: anyx.ConvInt64(re["indexLength"]),
|
||||
})
|
||||
}
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
// 获取表索引信息
|
||||
func (pm *PgsqlMetadata) GetTableIndex(tableName string) ([]Index, error) {
|
||||
_, res, err := pm.dc.SelectData(fmt.Sprintf(GetLocalSql(PGSQL_META_FILE, PGSQL_INDEX_INFO_KEY), tableName))
|
||||
|
||||
@@ -31,10 +31,6 @@ func InitDbRouter(router *gin.RouterGroup) {
|
||||
|
||||
req.NewDelete(":dbId", d.DeleteDb).Log(req.NewLogSave("db-删除数据库信息")),
|
||||
|
||||
req.NewGet(":dbId/t-infos", d.TableInfos),
|
||||
|
||||
req.NewGet(":dbId/t-index", d.TableIndex),
|
||||
|
||||
req.NewGet(":dbId/t-create-ddl", d.GetCreateTableDdl),
|
||||
|
||||
req.NewPost(":dbId/exec-sql", d.ExecSql).Log(req.NewLog("db-执行Sql")),
|
||||
@@ -43,7 +39,9 @@ func InitDbRouter(router *gin.RouterGroup) {
|
||||
|
||||
req.NewGet(":dbId/dump", d.DumpSql).Log(req.NewLogSave("db-导出sql文件")).NoRes(),
|
||||
|
||||
req.NewGet(":dbId/t-metadata", d.TableMA),
|
||||
req.NewGet(":dbId/t-infos", d.TableInfos),
|
||||
|
||||
req.NewGet(":dbId/t-index", d.TableIndex),
|
||||
|
||||
req.NewGet(":dbId/c-metadata", d.ColumnMA),
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ func (m *MachineScript) RunMachineScript(rc *req.Ctx) {
|
||||
script := ms.Script
|
||||
// 如果有脚本参数,则用脚本参数替换脚本中的模板占位符参数
|
||||
if params := g.Query("params"); params != "" {
|
||||
script = stringx.TemplateParse(ms.Script, jsonx.ToMap(params))
|
||||
script, err = stringx.TemplateParse(ms.Script, jsonx.ToMap(params))
|
||||
biz.ErrIsNilAppendErr(err, "脚本模板参数解析失败: %s")
|
||||
}
|
||||
cli, err := m.MachineApp.GetCli(machineId)
|
||||
biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
|
||||
|
||||
@@ -131,6 +131,11 @@ func (r *Redis) TtlKey(rc *req.Ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Redis) MemoryUsage(rc *req.Ctx) {
|
||||
ri, key := r.checkKeyAndGetRedisConn(rc)
|
||||
rc.ResData = ri.GetCmdable().MemoryUsage(context.Background(), key).Val()
|
||||
}
|
||||
|
||||
func (r *Redis) DeleteKey(rc *req.Ctx) {
|
||||
ri, key := r.checkKeyAndGetRedisConn(rc)
|
||||
rc.ReqParam = collx.Kvs("redis", ri.Info, "key", key)
|
||||
|
||||
@@ -45,6 +45,8 @@ func InitRedisRouter(router *gin.RouterGroup) {
|
||||
|
||||
req.NewGet(":id/:db/key-ttl", rs.TtlKey),
|
||||
|
||||
req.NewGet(":id/:db/key-memuse", rs.MemoryUsage),
|
||||
|
||||
req.NewDelete(":id/:db/key", rs.DeleteKey).Log(req.NewLogSave("redis-删除key")).RequiredPermission(deleteDataP),
|
||||
|
||||
req.NewPost(":id/:db/rename-key", rs.RenameKey).Log(req.NewLogSave("redis-重命名key")).RequiredPermission(saveDataP),
|
||||
|
||||
@@ -5,24 +5,24 @@ import (
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func parse(t *template.Template, vars any) string {
|
||||
func parse(t *template.Template, vars any) (string, error) {
|
||||
var tmplBytes bytes.Buffer
|
||||
|
||||
err := t.Execute(&tmplBytes, vars)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return "", err
|
||||
}
|
||||
return tmplBytes.String()
|
||||
return tmplBytes.String(), nil
|
||||
}
|
||||
|
||||
// 模板字符串解析
|
||||
// @param str 模板字符串
|
||||
// @param vars 参数变量
|
||||
func TemplateParse(str string, vars any) string {
|
||||
func TemplateParse(str string, vars any) (string, error) {
|
||||
tmpl, err := template.New("tmpl").Parse(str)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return "", err
|
||||
}
|
||||
return parse(tmpl, vars)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user