Commit 4e75b7b0 authored by wenmo's avatar wenmo

元数据表信息和字段

parent 6bd35351
......@@ -21,13 +21,15 @@ public class Column implements Serializable {
private String type;
private String comment;
private boolean keyFlag;
/**
* 主键是否为自增类型
*/
private boolean keyIdentityFlag;
private String fill;
private String isNotNull;
private boolean autoIncrement;
private String defaultValue;
private boolean isNullable;
private String javaType;
private String columnFamily;
private Integer position;
private Integer precision;
private Integer scale;
private String characterSet;
private String collation;
}
\ No newline at end of file
......@@ -5,6 +5,7 @@ import lombok.Setter;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
/**
......@@ -26,10 +27,9 @@ public class Table implements Serializable, Comparable<Table> {
private String type;
private String engine;
private String options;
private String collation;
private Long rows;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private Date createTime;
private Date updateTime;
private List<Column> columns;
public Table() {
......
......@@ -7,6 +7,7 @@ import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.parser.Token;
import com.dlink.assertion.Asserts;
import com.dlink.constant.CommonConstant;
import com.dlink.metadata.query.IDBQuery;
import com.dlink.metadata.result.JdbcSelectResult;
import com.dlink.model.Column;
import com.dlink.model.Schema;
......@@ -118,18 +119,25 @@ public abstract class AbstractJdbcDriver extends AbstractDriver {
List<Table> tableList = new ArrayList<>();
PreparedStatement preparedStatement = null;
ResultSet results = null;
String sql = getDBQuery().tablesSql(schemaName);
IDBQuery dbQuery = getDBQuery();
String sql = dbQuery.tablesSql(schemaName);
try {
preparedStatement = conn.prepareStatement(sql);
results = preparedStatement.executeQuery();
while (results.next()) {
String tableName = results.getString(getDBQuery().tableName());
String tableName = results.getString(dbQuery.tableName());
if (Asserts.isNotNullString(tableName)) {
Table tableInfo = new Table();
tableInfo.setName(tableName);
String tableComment = results.getString(getDBQuery().tableComment());
tableInfo.setComment(tableComment);
tableInfo.setComment(results.getString(dbQuery.tableComment()));
tableInfo.setSchema(schemaName);
tableInfo.setType(results.getString(dbQuery.tableType()));
tableInfo.setCatalog(results.getString(dbQuery.catalogName()));
tableInfo.setEngine(results.getString(dbQuery.engine()));
tableInfo.setOptions(results.getString(dbQuery.options()));
tableInfo.setRows(results.getLong(dbQuery.rows()));
tableInfo.setCreateTime(results.getDate(dbQuery.createTime()));
tableInfo.setUpdateTime(results.getDate(dbQuery.updateTime()));
tableList.add(tableInfo);
}
}
......@@ -146,27 +154,28 @@ public abstract class AbstractJdbcDriver extends AbstractDriver {
List<Column> columns = new ArrayList<>();
PreparedStatement preparedStatement = null;
ResultSet results = null;
String tableFieldsSql = getDBQuery().columnsSql(schemaName, tableName);
IDBQuery dbQuery = getDBQuery();
String tableFieldsSql = dbQuery.columnsSql(schemaName, tableName);
tableFieldsSql = String.format(tableFieldsSql, tableName);
try {
preparedStatement = conn.prepareStatement(tableFieldsSql);
results = preparedStatement.executeQuery();
while (results.next()) {
Column field = new Column();
String columnName = results.getString(getDBQuery().columnName());
boolean isId;
String key = results.getString(getDBQuery().columnKey());
isId = Asserts.isNotNullString(key) && "PRI".equals(key.toUpperCase());
if (isId) {
field.setKeyFlag(true);
} else {
field.setKeyFlag(false);
}
String columnName = results.getString(dbQuery.columnName());
String key = results.getString(dbQuery.columnKey());
field.setKeyFlag(Asserts.isNotNullString(key) && Asserts.isEqualsIgnoreCase("PRI",key));
field.setName(columnName);
field.setType(results.getString(getDBQuery().columnType()));
field.setType(results.getString(dbQuery.columnType()));
field.setJavaType(getTypeConvert().convert(field.getType()).getType());
field.setComment(results.getString(getDBQuery().columnComment()));
field.setIsNotNull(results.getString(getDBQuery().isNotNull()));
field.setComment(results.getString(dbQuery.columnComment()));
field.setNullable(Asserts.isEqualsIgnoreCase(results.getString(dbQuery.isNullable()),"YES"));
field.setCharacterSet(results.getString(dbQuery.characterSet()));
field.setCollation(results.getString(dbQuery.collation()));
field.setPosition(results.getInt(dbQuery.columnPosition()));
field.setPrecision(results.getInt(dbQuery.precision()));
field.setScale(results.getInt(dbQuery.scale()));
field.setAutoIncrement(Asserts.isEqualsIgnoreCase(results.getString(dbQuery.autoIncrement()),"auto_increment"));
columns.add(field);
}
} catch (SQLException e) {
......
......@@ -55,28 +55,78 @@ public abstract class AbstractDBQuery implements IDBQuery {
return "OPTIONS";
}
@Override
public String rows() {
return "ROWS";
}
@Override
public String createTime() {
return "CREATE_TIME";
}
@Override
public String updateTime() {
return "UPDATE_TIME";
}
@Override
public String columnName() {
return "FIELD";
return "COLUMN_NAME";
}
@Override
public String columnPosition() {
return "ORDINAL_POSITION";
}
@Override
public String columnType() {
return "TYPE";
return "DATA_TYPE";
}
@Override
public String columnComment() {
return "COMMENT";
return "COLUMN_COMMENT";
}
@Override
public String columnKey() {
return "KEY";
return "COLUMN_KEY";
}
@Override
public String autoIncrement() {
return "AUTO_INCREMENT";
}
@Override
public String defaultValue() {
return "COLUMN_DEFAULT";
}
@Override
public String isNullable() {
return "IS_NULLABLE";
}
@Override
public String precision() {
return "NUMERIC_PRECISION";
}
@Override
public String scale() {
return "NUMERIC_SCALE";
}
@Override
public String characterSet() {
return "CHARACTER_SET_NAME";
}
@Override
public String isNotNull() {
return "NULL";
public String collation() {
return "COLLATION_NAME";
}
}
......@@ -50,10 +50,26 @@ public interface IDBQuery {
* 表配置
*/
String options();
/**
* 表记录数
*/
String rows();
/**
* 创建时间
*/
String createTime();
/**
* 更新时间
*/
String updateTime();
/**
* 字段名称
*/
String columnName();
/**
* 字段序号
*/
String columnPosition();
/**
* 字段类型
*/
......@@ -67,21 +83,43 @@ public interface IDBQuery {
*/
String columnKey();
/**
* 判断主键是否为identity,目前仅对mysql进行检查
*
* @param results ResultSet
* @return 主键是否为identity
* @throws SQLException ignore
* 主键自增
*/
boolean isKeyIdentity(ResultSet results) throws SQLException;
String autoIncrement();
/**
* 判断字段是否不为null,目前仅对mysql进行检查
*
* @return 主键是否不为bull
* 默认值
*/
String defaultValue();
/**
* @return 是否允许为 NULL
*/
String isNotNull();
String isNullable();
/**
* @return 精度
*/
String precision();
/**
* @return 小数范围
*/
String scale();
/**
* @return 字符集名称
*/
String characterSet();
/**
* @return 排序规则
*/
String collation();
/**
* 自定义字段名称
*/
String[] columnCustom();
/**
* 判断主键是否为identity,目前仅对mysql进行检查
*
* @param results ResultSet
* @return 主键是否为identity
* @throws SQLException ignore
*/
boolean isKeyIdentity(ResultSet results) throws SQLException;
}
......@@ -54,7 +54,7 @@ public class MySqlDriver extends AbstractJdbcDriver {
sb.append(",");
}
sb.append("`"+columns.get(i).getName() + "` " + getTypeConvert().convertToDB(columns.get(i)));
if("YES".equals(columns.get(i).getIsNotNull())){
if(columns.get(i).isNullable()){
sb.append(" NOT NULL");
}else{
sb.append(" NULL");
......
package com.dlink.metadata.query;
import com.dlink.assertion.Asserts;
import java.sql.ResultSet;
import java.sql.SQLException;
......@@ -21,13 +19,18 @@ public class MySqlQuery extends AbstractDBQuery {
@Override
public String tablesSql(String schemaName) {
return "select TABLE_NAME AS `NAME`,TABLE_SCHEMA AS `Database`,TABLE_COMMENT AS COMMENT,TABLE_CATALOG AS `CATALOG`" +
",TABLE_TYPE AS `TYPE`,ENGINE AS `ENGINE`,CREATE_OPTIONS AS `OPTIONS` from information_schema.tables" +
" where TABLE_SCHEMA = '"+schemaName+"'";
",TABLE_TYPE AS `TYPE`,ENGINE AS `ENGINE`,CREATE_OPTIONS AS `OPTIONS`,TABLE_ROWS AS `ROWS`" +
",CREATE_TIME,UPDATE_TIME from information_schema.tables" +
" where TABLE_SCHEMA = '" + schemaName + "'";
}
@Override
public String columnsSql(String schemaName,String tableName) {
return "show full columns from `"+tableName+"`";
public String columnsSql(String schemaName, String tableName) {
return "select COLUMN_NAME,DATA_TYPE,COLUMN_COMMENT,COLUMN_KEY,EXTRA AS AUTO_INCREMENT" +
",COLUMN_DEFAULT,IS_NULLABLE,NUMERIC_PRECISION,NUMERIC_SCALE,CHARACTER_SET_NAME" +
",COLLATION_NAME,ORDINAL_POSITION from INFORMATION_SCHEMA.COLUMNS " +
"where TABLE_SCHEMA = '" + schemaName + "' and TABLE_NAME = '" + tableName + "' " +
"order by ORDINAL_POSITION";
}
@Override
......
......@@ -55,7 +55,7 @@ public class OracleDriver extends AbstractJdbcDriver {
sb.append(",");
}
sb.append(columns.get(i).getName() + " " + getTypeConvert().convertToDB(columns.get(i).getType()));
if("YES".equals(columns.get(i).getIsNotNull())){
if(columns.get(i).isNullable()){
sb.append(" NOT NULL");
}
}
......
......@@ -79,7 +79,7 @@ public class OracleQuery extends AbstractDBQuery {
}
@Override
public String isNotNull() {
public String isNullable() {
return "NULLABLE";
}
}
import {
message, Button,Tree, Empty, Select,Tag,
Tabs, Button,Tree, Empty, Select,Tag,
Tooltip
} from "antd";
import {StateType} from "@/pages/FlinkSqlStudio/model";
......@@ -7,10 +7,10 @@ import {connect} from "umi";
import {useState} from "react";
import styles from "./index.less";
import {
ReloadOutlined,
TableOutlined,
DatabaseOutlined,
DownOutlined,
TableOutlined, FireOutlined
OrderedListOutlined, FireOutlined
} from '@ant-design/icons';
import React from "react";
import {showMetaDataTable} from "@/components/Studio/StudioEvent/DDL";
......@@ -18,24 +18,25 @@ import { Scrollbars } from 'react-custom-scrollbars';
import {
ModalForm,
} from '@ant-design/pro-form';
import ProDescriptions from "@ant-design/pro-descriptions";
import StudioPreview from "@/components/Studio/StudioConsole/StudioPreview";
import Columns from "@/pages/DataBase/Columns";
import Tables from "@/pages/DataBase/Tables";
import {TreeDataNode} from "@/components/Studio/StudioTree/Function";
const { DirectoryTree } = Tree;
const {Option} = Select;
const { TabPane } = Tabs;
const StudioMetaData = (props: any) => {
const {database,toolHeight, dispatch} = props;
const [databaseId, setDataBaseId] = useState<number>();
const [databaseId, setDatabaseId] = useState<number>();
const [treeData, setTreeData] = useState<[]>([]);
const [modalVisit, setModalVisit] = useState(false);
const [row, setRow] = useState<TreeDataNode>();
const onRefreshTreeData = ()=>{
const onRefreshTreeData = (databaseId: number)=>{
if(!databaseId)return;
setDatabaseId(databaseId);
const res = showMetaDataTable(databaseId);
res.then((result) => {
let tables = result.datas;
......@@ -58,23 +59,18 @@ const StudioMetaData = (props: any) => {
};
const onChangeDataBase = (value: number)=>{
setDataBaseId(value);
onRefreshTreeData();
onRefreshTreeData(value);
};
const getDataBaseOptions = ()=>{
let itemList = [];
for (let item of database) {
let tag = (<><Tag color={item.enabled ? "processing" : "error"}>{item.type}</Tag>{item.alias}</>);
itemList.push(<Option value={item.id} label={tag}>
{tag}
</Option>)
}
return itemList;
return <>{database.map(({ id, alias, type, enabled }) => (
<Option value={id} label={<><Tag color={enabled ? "processing" : "error"}>{type}</Tag>{alias}</>}>
<Tag color={enabled ? "processing" : "error"}>{type}</Tag>{alias}
</Option>
))}</>
};
const openColumnInfo = (e: React.MouseEvent, node: TreeDataNode) => {
console.log(node);
if(node.isLeaf){
setRow(node);
setModalVisit(true);
......@@ -91,13 +87,6 @@ const StudioMetaData = (props: any) => {
>
{getDataBaseOptions()}
</Select>
<Tooltip title="刷新元数据">
<Button
type="text"
icon={<ReloadOutlined/>}
onClick={onRefreshTreeData}
/>
</Tooltip>
<Scrollbars style={{height: (toolHeight - 32)}}>
{treeData.length>0?(
<DirectoryTree
......@@ -110,15 +99,18 @@ const StudioMetaData = (props: any) => {
/>):(<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />)}
</Scrollbars>
<ModalForm
// title="新建表单"
title={ (row?(row.key)+'的':'')+'字段信息'}
title={row?.key}
visible={modalVisit}
width={1000}
onFinish={async () => {
// setRow(undefined);
// setModalVisit(false);
}}
modalProps={{
maskClosable:false
maskClosable:false,
bodyStyle:{
padding: '5px'
}
}}
onVisibleChange={setModalVisit}
submitter={{
......@@ -128,10 +120,33 @@ const StudioMetaData = (props: any) => {
},
},
}}
>
{row?
(<Columns dbId={databaseId} schema={row.schema} table={row.table}/>) : (<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />)}
</ModalForm>
<Tabs defaultActiveKey="2">
<TabPane
tab={
<span>
<TableOutlined />
表信息
</span>
}
key="tableInfo"
>
{row?<Tables table={row}/>:<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
</TabPane>
<TabPane
tab={
<span>
<OrderedListOutlined />
字段信息
</span>
}
key="columnInfo"
>
{row? <Columns dbId={databaseId} schema={row.schema} table={row.table}/> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
</TabPane>
</Tabs>
</ModalForm>
</>
);
};
......
......@@ -412,8 +412,6 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
setTaskFormValues({});
openByKey(datas.id);
showEnv(dispatch);
// getTreeData();
// onSelect([],openByKey(datas.id));
}
}}
onCancel={() => {
......
This diff is collapsed.
......@@ -49,9 +49,9 @@
}
/* --- list toolbar修改内偏移 --- end */
/* --- prodescription item宽度 --- start */
.ant-descriptions-item-content {
/*.ant-descriptions-item-content {
width: 100%;
}
}*/
/* --- prodescription item宽度 --- end */
/* --- table 宽度 --- start */
.ant-table-wrapper {
......
export type Column = {
name: string,
type: string,
comment: string,
keyFlag: boolean,
keyIdentityFlag: boolean,
fill: string,
isNotNull: string,
javaType: string,
columnFamily: string,
};
import React from "react";
import { Button, Tooltip } from 'antd';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { KeyOutlined,CheckSquareOutlined } from '@ant-design/icons';
import type { ProColumns } from '@ant-design/pro-table';
import ProTable, { TableDropdown } from '@ant-design/pro-table';
import { Column } from "./data";
import { Column } from "../data";
import {getData, queryData} from "@/components/Common/crud";
......@@ -13,19 +13,22 @@ const Columns = (props: any) => {
const {dbId,table,schema} = props;
const columns: ProColumns<Column>[] = [
{
title: '序号',
dataIndex: 'position',
sorter: (a, b) => a.position - b.position,
},
{
title: '列名',
dataIndex: 'name',
render: (_) => <a>{_}</a>,
/*formItemProps: {
lightProps: {
labelFormatter: (value) => `app-${value}`,
},
},*/
// sorter: (a, b) => a.name - b.name,
copyable: true,
},
{
title: '注释',
dataIndex: 'comment',
// ellipsis: true,
},
{
title: '类型',
......@@ -34,15 +37,42 @@ const Columns = (props: any) => {
{
title: '主键',
dataIndex: 'keyFlag',
render: (_, record) => (
<>
{record.keyFlag?<KeyOutlined style={{ color:'#FAA100'}} />:undefined}
</>
),
},{
title: '自增',
dataIndex: 'keyIdentityFlag',
dataIndex: 'autoIncrement',
render: (_, record) => (
<>
{record.autoIncrement?<CheckSquareOutlined style={{ color:'#1296db'}} />:undefined}
</>
),
},{
title: '非空',
dataIndex: 'nullable',
render: (_, record) => (
<>
{!record.nullable?<CheckSquareOutlined style={{ color:'#1296db'}} />:undefined}
</>
),
},{
title: '默认值',
dataIndex: 'fill',
dataIndex: 'defaultValue',
},{
title: '非空',
dataIndex: 'isNotNull',
title: '精度',
dataIndex: 'precision',
},{
title: '小数范围',
dataIndex: 'scale',
},{
title: '字符集',
dataIndex: 'characterSet',
},{
title: '排序规则',
dataIndex: 'collation',
},{
title: 'Java 类型',
dataIndex: 'javaType',
......@@ -92,15 +122,15 @@ const Columns = (props: any) => {
data: msg.datas,
success: msg.code===0,
};
}
}
}}
rowKey="name"
pagination={{
pageSize: 10,
}}
search={{
/*search={{
filterType: 'light',
}}
}}*/
search={false}
/*toolBarRender={() => [
<Button key="show">查看日志</Button>,
<Button type="primary" key="primary">
......
import { Descriptions, Badge } from 'antd';
const Tables = (props: any) => {
const {table} = props;
return (<Descriptions bordered>
<Descriptions.Item label="Name">{table.name}</Descriptions.Item>
<Descriptions.Item label="Schema">{table.schema}</Descriptions.Item>
<Descriptions.Item label="Catalog">{table.catalog}</Descriptions.Item>
<Descriptions.Item label="Rows">{table.rows}</Descriptions.Item>
<Descriptions.Item label="Type">{table.type}</Descriptions.Item>
<Descriptions.Item label="Engine">{table.engine}</Descriptions.Item>
<Descriptions.Item label="Options" span={3}>
{table.options}
</Descriptions.Item>
<Descriptions.Item label="Status"><Badge status="processing" text="Running" /></Descriptions.Item>
<Descriptions.Item label="CreateTime">{table.createTime}</Descriptions.Item>
<Descriptions.Item label="UpdateTime">{table.updateTime}</Descriptions.Item>
<Descriptions.Item label="Comment" span={3}>{table.comment}</Descriptions.Item>
</Descriptions>)
};
export default Tables;
......@@ -17,7 +17,6 @@ export type DataBaseItem = {
updateTime: Date,
};
export type DataBaseFormProps = {
name: string,
alias: string,
......@@ -32,3 +31,33 @@ export type DataBaseFormProps = {
dbVersion: string,
enabled: boolean,
}
export type Column = {
name: string,
type: string,
comment: string,
keyFlag: boolean,
autoIncrement: boolean,
defaultValue: string,
nullable: string,
javaType: string,
columnFamily: string,
position: number,
precision: number,
scale: number,
characterSet: string,
collation: string,
};
export type Table = {
name: string,
schema: string,
catalog: string,
comment: string,
type: string,
engine: string,
options: string,
rows: number,
createTime: string,
updateTime: string,
};
......@@ -515,7 +515,7 @@ export default (): React.ReactNode => {
<Link>新增 Mysql,Oracle,PostGreSql,ClickHouse,Doris,Java 方言及图标</Link>
</li>
<li>
<Link>新增 元数据查看信息</Link>
<Link>新增 元数据查看表和字段信息</Link>
</li>
</ul>
</Paragraph>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment