diff --git a/.github/workflows/pushdocker.yml b/.github/workflows/pushdocker.yml index 10a55bbc1..fbad111a8 100644 --- a/.github/workflows/pushdocker.yml +++ b/.github/workflows/pushdocker.yml @@ -50,6 +50,7 @@ jobs: yarn install yarn run build:web:prod --app_version=${{ steps.chat2db_version.outputs.substring }} cp -r dist ../chat2db-server/chat2db-server-start/src/main/resources/static/front + cp -r dist/index.html ../chat2db-server/chat2db-server-start/src/main/resources/thymeleaf # 安装java - name: Install Java and Maven diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 730645742..71c096913 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -140,6 +140,7 @@ jobs: yarn install yarn run build:web:prod --app_version=${{ steps.chat2db_version.outputs.substring }} cp -r dist ../chat2db-server/chat2db-server-start/src/main/resources/static/front + cp -r dist/index.html ../chat2db-server/chat2db-server-start/src/main/resources/thymeleaf # 编译服务端java版本 - name: Build Java diff --git a/.github/workflows/release_test.yml b/.github/workflows/release_test.yml index e518c8093..2f0d40be9 100644 --- a/.github/workflows/release_test.yml +++ b/.github/workflows/release_test.yml @@ -134,6 +134,7 @@ jobs: yarn install yarn run build:web:prod --app_version=99.0.${{ github.run_id }} --app_port=10822 cp -r dist ../chat2db-server/chat2db-server-start/src/main/resources/static/front + cp -r dist/index.html ../chat2db-server/chat2db-server-start/src/main/resources/thymeleaf # 编译服务端java版本 - name: Build Java diff --git a/.vscode/settings.json b/.vscode/settings.json index a2df678b3..fcf08b845 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -32,6 +32,8 @@ "mkdir", "monaco", "msgtype", + "Navciat", + "Navicat", "nsis", "OPENAI", "ossutil", @@ -44,6 +46,7 @@ "Sercurity", "sortablejs", "temurin", + "thymeleaf", "Tigger", "togglefullscreen", "umijs", diff --git a/CHANGELOG.md b/CHANGELOG.md index 82d30cee4..7b1573ff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,40 @@ -# 2.2.0 - -## ⭐ New Features - -## 🐞 Bug Fixes - -- - -## ⭐ 新特性 - -- 🔥新增**表结构**编辑功能 -- 🔥新增**表数据**编辑功能 -- - - -## 🐞 问题修复 - +# 3.0.0 +`2023-10-17` + +## Changelog +- 🔥【New Features】Support for team collaboration mode +- 🔥【New Features】Support for visual table structure creation, editing, and deletion +- 🔥【New Features】Support for editing, adding, and deleting query data results +- ⭐【New Features】Support the feature of importing Navicat/DBever data source links +- ⭐【New Features】Support for AI automatic sync table structure。 +- ⭐【New Features】Support export table structure +- ⭐【New Features】Support importing SQL files +- ⭐【New Features】Support the connection supports adding an environment,better distinguishing between online and daily +- ⚡️【Optimize】Optimize Editor Intellisense +- ⚡️【Optimize】Optimize AI Input +- ⚡️【Optimize】Sql query support is stopped +- ⚡️【Optimize】Sql execution supports viewing the number of affected rows +- ⚡️【Optimize】Reclaiming non-administrator permissions to edit shared connections +- ⚡️【Optimize】`Cmd/Ctrl + R` Run SQL, `Cmd/Ctrl + Shift + R` Refresh Page +- 🐞【Fixed】Table operation columns are overridden by table comments +- 🐞【Fixed】The last Tab in the query result cannot be closed +## 更新日志 +- 🔥【新功能】支持团队协作模式 +- 🔥【新功能】支持可视化表结构新增、编辑、删除 +- 🔥【新功能】支持查询数据结果编辑、新增、删除 +- ⭐【新功能】支持导入Navicat/DBeaver数据源链接的功能 +- ⭐【新功能】支持AI自动同步表结构 +- ⭐【新功能】支持导出表结构 +- ⭐【新功能】支持导入sql文件 +- ⭐【新功能】连接支持添加环境标识,更好地区分在线和日常 +- ⚡️【优化】优化编辑器提示功能 +- ⚡️【优化】优化AI输入 +- ⚡️【优化】sql查询支持停止 +- ⚡️【优化】sql执行支持查看影响行数 +- ⚡️【优化】回收非管理员编辑共享连接权限 +- ⚡️【优化】`Cmd/Ctrl + R` 运行SQL, `Cmd/Ctrl + Shift + R` 刷新页面 +- 🐞【修复】表操作列被表注释覆盖问题 +- 🐞【修复】查询结果最后一个Tab无法关闭问题 # 2.1.0 @@ -27,10 +47,9 @@ ## ⭐ 新特性 --🔥新推出团队功能,支持团队协作。研发不需要知道在线数据库 -密码,解决企业数据库帐号的安全问题。建议直接部署团队 -使用'docker'的函数 --增加了环境选择的支持,更好地区分在线和日常 +-🔥 新推出团队功能,支持团队协作。研发不需要知道在线数据库 +密码,解决企业数据库帐号的安全问题。建议直接部署团队 +使用'docker'的函数 -增加了环境选择的支持,更好地区分在线和日常 # 2.0.14 @@ -41,13 +60,13 @@ ## ⭐ 新特性 -- 🔥团队功能全新上线,支持团队协作,研发无需知道线上数据库密码,解决企业数据库账号安全问题,团队功能建议直接使用 `docker` 部署 +- 🔥 团队功能全新上线,支持团队协作,研发无需知道线上数据库密码,解决企业数据库账号安全问题,团队功能建议直接使用 `docker` 部署 - 新增支持环境选择,更好的区分线上、日常环境 ## 🐞 问题修复 - 修复 `Oracle` 查询 `Blob` 报错的问题 -- 修改分页逻辑,修复部分SQL无法查询 +- 修改分页逻辑,修复部分 SQL 无法查询 # 2.0.13 @@ -62,6 +81,7 @@ - Fixed a bug where sql formatting was not selected - Fixed open view lag issue - Solve the white screen problem of connected non-relational databases (non-relational databases are not supported) + ## ⭐ 新特性 ## 🐞 问题修复 diff --git a/chat2db-client/.umirc.prod.desktop.ts b/chat2db-client/.umirc.prod.desktop.ts index 8fc0c0132..6207631e9 100644 --- a/chat2db-client/.umirc.prod.desktop.ts +++ b/chat2db-client/.umirc.prod.desktop.ts @@ -10,6 +10,7 @@ const chainWebpack = (config: any, { webpack }: any) => { languages: ['mysql', 'pgsql', 'sql'], }, ]); + config.output.filename(`[name].${yarn_config.app_version || new Date().getTime()}.js`); }; export default defineConfig({ diff --git a/chat2db-client/.umirc.prod.ts b/chat2db-client/.umirc.prod.ts index c0ff508ed..b7c86ba41 100644 --- a/chat2db-client/.umirc.prod.ts +++ b/chat2db-client/.umirc.prod.ts @@ -10,6 +10,7 @@ const chainWebpack = (config: any, { webpack }: any) => { languages: ['mysql', 'pgsql', 'sql'], }, ]); + config.output.filename(`[name].${yarn_config.app_version || new Date().getTime()}.js`); }; export default defineConfig({ diff --git a/chat2db-client/.umirc.ts b/chat2db-client/.umirc.ts index 089dd0931..063056d9c 100644 --- a/chat2db-client/.umirc.ts +++ b/chat2db-client/.umirc.ts @@ -12,6 +12,7 @@ const chainWebpack = (config: any, { webpack }: any) => { languages: ['mysql', 'pgsql', 'sql'], }, ]); + config.output.filename(`[name].${yarn_config.app_version || new Date().getTime()}.js`); }; export default defineConfig({ @@ -50,10 +51,17 @@ export default defineConfig({ // rel: 'manifest', // href: 'manifest.json', // }], + links: [ + { rel:"icon", + type:"image/ico", + sizes:"32x32", + href:"/static/front/logo.ico" + } + ], headScripts: [ - `if (localStorage.getItem('app-local-storage-versions') !== 'v2') { + `if (localStorage.getItem('app-local-storage-versions') !== 'v3') { localStorage.clear(); - localStorage.setItem('app-local-storage-versions', 'v2'); + localStorage.setItem('app-local-storage-versions', 'v3'); }`, `if (window.myAPI) { window.myAPI.startServerForSpawn() }`, // `if ("serviceWorker" in navigator) { diff --git a/chat2db-client/src/blocks/DatabaseTableEditor/IndexList/index.tsx b/chat2db-client/src/blocks/DatabaseTableEditor/IndexList/index.tsx index 9fda707f5..a2982e08f 100644 --- a/chat2db-client/src/blocks/DatabaseTableEditor/IndexList/index.tsx +++ b/chat2db-client/src/blocks/DatabaseTableEditor/IndexList/index.tsx @@ -79,6 +79,7 @@ const Row = ({ children, ...props }: RowProps) => { const IndexList = forwardRef((props: IProps, ref: ForwardedRef) => { const { databaseSupportField, tableDetails, databaseType } = useContext(Context); const [dataSource, setDataSource] = useState([createInitialData()]); + const [oldDataSource, setOldDataSource] = useState([]); // 用于记录上一次的数据,用于对比是否有变化 const [form] = Form.useForm(); const [editingData, setEditingData] = useState(null); const [includeColModalOpen, setIncludeColModalOpen] = useState(false); @@ -96,13 +97,16 @@ const IndexList = forwardRef((props: IProps, ref: ForwardedRef) = useEffect(() => { const data = tableDetails.indexList?.map((i) => { + const key = uuidv4(); return { ...i, oldName: i.name, - key: uuidv4(), + key, }; }); - setDataSource(data || []); + + setOldDataSource(lodash.cloneDeep(data) || []); + setDataSource(lodash.cloneDeep(data) || []); }, [tableDetails]); const addData = () => { @@ -115,19 +119,22 @@ const IndexList = forwardRef((props: IProps, ref: ForwardedRef) = }; const deleteData = (record) => { - setDataSource(dataSource.filter((i) => i.key !== record?.key)); - setDataSource( - dataSource.map((i) => { + const newList: any[] = dataSource + ?.map((i) => { if (i.key === record?.key) { setEditingData(null); + if (i.editStatus === EditColumnOperationType.Add) { + return null; + } return { ...i, editStatus: EditColumnOperationType.Delete, }; } return i; - }), - ); + }) + ?.filter((i) => i); + setDataSource(newList || []); }; const handelFieldsChange = (field: any) => { @@ -321,8 +328,18 @@ const IndexList = forwardRef((props: IProps, ref: ForwardedRef) = setDataSource( dataSource.map((i) => { const columnList = includeColRef.current?.getIncludeColInfo(); + // 对比新老的IncludeColInfo有没有变化 if (i.key === editingData?.key && columnList) { i.columnList = columnList; + oldDataSource.map((old) => { + if (old.key === editingData?.key) { + if (!lodash.isEqual(old.columnList, columnList)) { + i.editStatus = EditColumnOperationType.Modify; + } else { + i.editStatus = null; + } + } + }); } return i; }), diff --git a/chat2db-client/src/components/Console/index.tsx b/chat2db-client/src/components/Console/index.tsx index a4ca2326d..2eb830ba1 100644 --- a/chat2db-client/src/components/Console/index.tsx +++ b/chat2db-client/src/components/Console/index.tsx @@ -452,13 +452,12 @@ function Console(props: IProps, ref: ForwardedRef) { const handleSelectTableSyncModel = () => { const syncModel: SyncModelType | null = Number(localStorage.getItem('syncTableModel')) ?? null; const hasAiAccess = aiModel.hasWhite; - - if (!hasAiAccess || isEmpty(syncModel)) { - setSyncTableModel(SyncModelType.MANUAL); + if (syncModel !== null) { + setSyncTableModel(syncModel); return; } - setSyncTableModel(syncModel); + setSyncTableModel(hasAiAccess ? SyncModelType.AUTO : SyncModelType.MANUAL); }; return ( diff --git a/chat2db-client/src/components/Iconfont/index.tsx b/chat2db-client/src/components/Iconfont/index.tsx index f8b0862ef..975f31027 100644 --- a/chat2db-client/src/components/Iconfont/index.tsx +++ b/chat2db-client/src/components/Iconfont/index.tsx @@ -9,9 +9,9 @@ if (__ENV__ === 'local') { /* 在线链接服务仅供平台体验和调试使用,平台不承诺服务的稳定性,企业客户需下载字体包自行发布使用并做好备份。 */ @font-face { font-family: 'iconfont'; /* Project id 3633546 */ - src: url('//at.alicdn.com/t/c/font_3633546_wmiaztua9a.woff2?t=1697545878708') format('woff2'), - url('//at.alicdn.com/t/c/font_3633546_wmiaztua9a.woff?t=1697545878708') format('woff'), - url('//at.alicdn.com/t/c/font_3633546_wmiaztua9a.ttf?t=1697545878708') format('truetype'); + src: url('//at.alicdn.com/t/c/font_3633546_sze67iyjern.woff2?t=1697545966975') format('woff2'), + url('//at.alicdn.com/t/c/font_3633546_sze67iyjern.woff?t=1697545966975') format('woff'), + url('//at.alicdn.com/t/c/font_3633546_sze67iyjern.ttf?t=1697545966975') format('truetype'); } `; const style = document.createElement('style'); diff --git a/chat2db-client/src/components/SearchResult/TableBox/index.less b/chat2db-client/src/components/SearchResult/TableBox/index.less index 4f4d893a2..df6101022 100644 --- a/chat2db-client/src/components/SearchResult/TableBox/index.less +++ b/chat2db-client/src/components/SearchResult/TableBox/index.less @@ -1,15 +1,13 @@ @import '../../../styles/var.less'; .tableBox { - height: calc(100% - 26px); + height: 100%; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; :global { .art-table { - --header-bgcolor: #fafafa; - --header-color: #000; table colgroup col { min-width: 120px; } @@ -53,6 +51,25 @@ position: sticky; bottom: 26px !important; } + .art-loading-wrapper,.art-loading-content-wrapper,.art-table{ + height: 100%; + } + .art-table-body{ + height: calc(100% - 32px); + overflow-y: auto !important; + } + .art-table-row{ + height: 32px; + } + .art-table-header-cell{ + padding: 0px 4px; + } + } +} + +.noDataTableBox{ + table { + height: 100%; } } @@ -67,6 +84,7 @@ background-color: var(--color-bg-subtle); padding: 0px 4px 0px 0px; height: 30px; + flex-shrink: 0; } .toolBarItem { margin: 4px 0; @@ -125,26 +143,31 @@ } .table { - // height: 100%; + height: 0px; flex: 1; } .tableItem { - width: calc(100% + 8px); height: 100%; cursor: pointer; display: flex; align-items: center; justify-content: space-between; position: relative; - padding: 0px 4px; - margin: 0px -4px; - max-height: 120px; - overflow-y: auto; + padding-left: 4px; + overflow: hidden; user-select: none; + background-color: var(--color-bg-base); - &:hover .tableHoverBox { - display: block; + &:hover { + .tableHoverBox{ + display: flex; + } + overflow: auto; + } + + .cellValueNull{ + color: var(--color-text-tertiary); } input { @@ -154,6 +177,27 @@ .tableItemEdit { background-color: var(--color-success-bg); + .tableHoverBox{ + background-color: var(--color-success-bg); + } +} +.tableItemEditing { + background-color: var(--color-primary-bg-hover); + .tableHoverBox{ + background-color: var(--color-primary-bg-hover); + } +} +.tableItemSuccess { + background-color: var(--color-success-bg); + .tableHoverBox{ + background-color: var(--color-success-bg); + } +} +.tableItemError{ + background-color: var(--color-error-bg); + .tableHoverBox{ + background-color: var(--color-error-bg); + } } .tableItemNo { @@ -162,14 +206,15 @@ } .tableHoverBox { - position: absolute; - top: 50%; + position: sticky; + top: 0px; + bottom: 0px; right: 0px; width: 40px; display: none; align-items: center; - transform: translateY(-50%); cursor: pointer; + background-color: var(--color-bg-base); i { font-size: 15px; @@ -204,6 +249,7 @@ border-radius: 4px; overflow: hidden; height: 60vh; + margin-top: -15px; } .errorDetail { diff --git a/chat2db-client/src/components/SearchResult/TableBox/index.tsx b/chat2db-client/src/components/SearchResult/TableBox/index.tsx index c1db4285c..4b08195be 100644 --- a/chat2db-client/src/components/SearchResult/TableBox/index.tsx +++ b/chat2db-client/src/components/SearchResult/TableBox/index.tsx @@ -51,7 +51,7 @@ const SupportBaseTable: any = styled(BaseTable)` --header-color: var(--color-text); --lock-shadow: rgb(37 37 37 / 0.5) 0 0 6px 2px; --border-color: var(--color-border-secondary); - --cell-padding: 0px 4px; + --cell-padding: 0px; --row-height: 32px; } `; @@ -270,7 +270,10 @@ export default function TableBox(props: ITableProps) { // 渲染单元格的值 const renderTableCellValue = (value) => { if (value === null) { - return ''; + return {''} + } else if (!value) { + // 如果为空需要展位 + return } else { return value; } @@ -280,11 +283,25 @@ export default function TableBox(props: ITableProps) { const tableCellStyle = (value, colIndex, rowNo) => { // 单元格的基础样式 const styleList = [styles.tableItem]; - // 如果当前单元格所在的行被选中了,则需要把单元格的背景色设置为透明 - if (curOperationRowNo === rowNo) { + // 当前单元格所在的行被选中了 + if (rowNo === curOperationRowNo) { + styleList.push(styles.tableItemEditing); + return classnames(...styleList); + } + // 新添加的行 + const index2 = updateData.findIndex((item) => { + return item.rowNo === rowNo && item.type === CRUD.CREATE; + }); + if (index2 !== -1) { + styleList.push(styles.tableItemSuccess); + return classnames(...styleList); + } + // 如果是删除过的行 + const index = updateData.findIndex((item) => item.rowNo === rowNo && item.type === CRUD.DELETE); + if (index !== -1) { + styleList.push(styles.tableItemError); return classnames(...styleList); } - // 编辑过的单元格的样式 let oldValue = ''; oldDataList.forEach((item) => { @@ -325,9 +342,10 @@ export default function TableBox(props: ITableProps) { lock: true, width: 60, features: { sortable: compareStrings }, - render: (value: any) => { + render: (value: any, rowData) => { + const rowNo = rowData[`${preCode}0No.`]; return ( -
+
{value}
); @@ -577,47 +595,47 @@ export default function TableBox(props: ITableProps) { return sqlService.executeSql(executeSQLParams).then((res) => { setQueryResultData(res?.[0]); + setUpdateData([]); }); }; // 不同状态下的表格行样式 - const tableRowStyle = (rowNo: string) => { - // 如果是当前操作的行 - if (rowNo === curOperationRowNo) { - return { - '--hover-bgcolor': 'transparent', - '--bgcolor': 'transparent', - background: 'var(--color-primary-bg-hover)', - }; - } - // 如果是删除过的行 - const index = updateData.findIndex((item) => item.rowNo === rowNo && item.type === CRUD.DELETE); - if (index !== -1) { - return { - '--hover-bgcolor': 'transparent', - '--bgcolor': 'transparent', - background: 'var(--color-error-bg)', - }; - } - // 如果是新增的行 - const index2 = updateData.findIndex((item) => { - return item.rowNo === rowNo && item.type === CRUD.CREATE; - }); - if (index2 !== -1) { - return { - '--hover-bgcolor': 'transparent', - '--bgcolor': 'transparent', - background: 'var(--color-success-bg)', - }; - } - return {}; - }; + // const tableRowStyle = (rowNo: string) => { + // // 如果是当前操作的行 + // if (rowNo === curOperationRowNo) { + // return { + // '--hover-bgcolor': 'transparent', + // '--bgcolor': 'transparent', + // background: 'var(--color-primary-bg-hover)', + // }; + // } + // // 如果是删除过的行 + // const index = updateData.findIndex((item) => item.rowNo === rowNo && item.type === CRUD.DELETE); + // if (index !== -1) { + // return { + // '--hover-bgcolor': 'transparent', + // '--bgcolor': 'transparent', + // background: 'var(--color-error-bg)', + // }; + // } + // // 如果是新增的行 + // const index2 = updateData.findIndex((item) => { + // return item.rowNo === rowNo && item.type === CRUD.CREATE; + // }); + // if (index2 !== -1) { + // return { + // '--hover-bgcolor': 'transparent', + // '--bgcolor': 'transparent', + // background: 'var(--color-success-bg)', + // }; + // } + // return {}; + // }; // sql执行成功后的回调 const executeSuccessCallBack = () => { getTableData().then(() => { setViewUpdateDataSqlModal(false); message.success(i18n('common.text.successfulExecution')); - setUpdateData([]); }); }; @@ -734,7 +752,7 @@ export default function TableBox(props: ITableProps) { getRowProps={(record) => { const rowNo = record[`${preCode}0No.`]; return { - style: tableRowStyle(rowNo), + // style: tableRowStyle(rowNo), onClick() { setCurOperationRowNo(rowNo); }, @@ -751,7 +769,14 @@ export default function TableBox(props: ITableProps) { }; return ( -
+
{renderContent()} diff --git a/chat2db-client/src/components/TabsNew/index.less b/chat2db-client/src/components/TabsNew/index.less index 32fa718db..0d221e68c 100644 --- a/chat2db-client/src/components/TabsNew/index.less +++ b/chat2db-client/src/components/TabsNew/index.less @@ -36,6 +36,7 @@ .tabsContent { flex: 1; + height: 0px; .tabsContentItem { height: 100%; width: 100%; diff --git a/chat2db-client/src/i18n/en-us/common.ts b/chat2db-client/src/i18n/en-us/common.ts index cd8006d56..182121d9b 100644 --- a/chat2db-client/src/i18n/en-us/common.ts +++ b/chat2db-client/src/i18n/en-us/common.ts @@ -1,6 +1,6 @@ export default { - 'common.text.no': 'is', - 'common.text.is': 'no', + 'common.text.no': 'no', + 'common.text.is': 'is', 'common.button.affirm': 'Affirm', 'common.button.edit': 'Edit', 'common.button.modify': 'Modify', diff --git a/chat2db-client/src/pages/main/connection/index.tsx b/chat2db-client/src/pages/main/connection/index.tsx index 9bd8b9fb6..82c01756c 100644 --- a/chat2db-client/src/pages/main/connection/index.tsx +++ b/chat2db-client/src/pages/main/connection/index.tsx @@ -255,7 +255,7 @@ function Connections(props: IProps) {
{Object.keys(curConnection).length ? ( - curConnection.environmentId === 2 ? ( + (curConnection.kind === ConnectionKind.Private && curConnection.id) || !curConnection.id ? (
{ - monacoEditorRef.current?.setValue(res); setMonacoVerifyDialog(true); + setTimeout(() => { + monacoEditorRef.current?.setValue(res,'cover'); + }, 0); }); }, }; @@ -315,7 +317,7 @@ function TreeNodeRightClick(props: IProps) { maskClosable={false} title={`${data.key}-DDL`} open={monacoVerifyDialog} - width="600px" + width="650px" onCancel={() => { setMonacoVerifyDialog(false); }} diff --git a/chat2db-client/src/pages/main/workspace/components/Tree/index.less b/chat2db-client/src/pages/main/workspace/components/Tree/index.less index 53cf5d703..fee863964 100644 --- a/chat2db-client/src/pages/main/workspace/components/Tree/index.less +++ b/chat2db-client/src/pages/main/workspace/components/Tree/index.less @@ -14,7 +14,7 @@ cursor: pointer; transition: opacity 0.05s ease-in, height 0.1s ease-in; user-select: none; - + &:hover { background-color: var(--color-hover-bg); .right { @@ -39,17 +39,32 @@ display: flex; align-items: center; height: 100%; - padding: 0px 10px; + padding-left: 10px; border-radius: 2px; // color: var(--color-text-secondary); + .moreBox{ + width: 22px; + height: 100%; + display: none; + justify-content: center; + align-items: center; + } + .moreButton { flex-shrink: 0; - display: none; transform: rotate(90deg); } &:hover { background-color: var(--color-hover-bg); + .moreBox{ + width: 22px; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + } + .moreButton { display: block; } diff --git a/chat2db-client/src/pages/main/workspace/components/Tree/index.tsx b/chat2db-client/src/pages/main/workspace/components/Tree/index.tsx index f2097fbc8..c2c3bd2f6 100644 --- a/chat2db-client/src/pages/main/workspace/components/Tree/index.tsx +++ b/chat2db-client/src/pages/main/workspace/components/Tree/index.tsx @@ -81,6 +81,23 @@ const TreeNode = (props: TreeNodeIProps) => { const [showChildren, setShowChildren] = useState(false); const [isLoading, setIsLoading] = useState(false); const indentArr = new Array(level).fill('indent'); + const [openTooltipComment, setOpenTooltipComment] = useState(false); + const contentTextRef = React.useRef(null); + + useEffect(() => { + if(!data.comment){ + return + } + if (contentTextRef.current) { + const contentTextRefDom = contentTextRef.current; + contentTextRefDom.addEventListener('mouseenter', () => { + setOpenTooltipComment(true); + }); + contentTextRefDom.addEventListener('mouseleave', () => { + setOpenTooltipComment(false); + }); + } + }, [contentTextRef]); function loadData(data: ITreeNode) { const treeNodeConfig: ITreeConfigItem = treeConfig[data.treeNodeType]; @@ -177,7 +194,7 @@ const TreeNode = (props: TreeNodeIProps) => { return show ? ( <> - +
{indentArr.map((item, i) => { @@ -206,12 +223,12 @@ const TreeNode = (props: TreeNodeIProps) => {
-
+
{data.treeNodeType === TreeNodeType.COLUMN &&
{data.columnType}
}
-
+
(list: T[], key: K, value: // 清理就版本不兼容的LocalStorage export function clearOlderLocalStorage() { - if (localStorage.getItem('app-local-storage-versions') !== 'v2') { + if (localStorage.getItem('app-local-storage-versions') !== 'v3') { localStorage.clear(); - localStorage.setItem('app-local-storage-versions', 'v2'); + localStorage.setItem('app-local-storage-versions', 'v3'); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java index 4d126de9d..aa404f466 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/builder/MysqlSqlBuilder.java @@ -95,9 +95,10 @@ public String buildModifyTaleSql(Table oldTable, Table newTable) { script.append("\t").append(mysqlIndexTypeEnum.buildModifyIndex(tableIndex)).append(",\n"); } } - - script = new StringBuilder(script.substring(0, script.length() - 2)); - script.append(";"); + if(script.length()>2) { + script = new StringBuilder(script.substring(0, script.length() - 2)); + script.append(";"); + } return script.toString(); } diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/type/MysqlIndexTypeEnum.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/type/MysqlIndexTypeEnum.java index de0162239..a03c29a69 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/type/MysqlIndexTypeEnum.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/type/MysqlIndexTypeEnum.java @@ -88,7 +88,11 @@ private String buildIndexColumn(TableIndex tableIndex) { script.append("("); for (TableIndexColumn column : tableIndex.getColumnList()) { if(StringUtils.isNotBlank(column.getColumnName())) { - script.append("`").append(column.getColumnName()).append("`").append(","); + script.append("`").append(column.getColumnName()).append("`"); + if (!StringUtils.isBlank(column.getAscOrDesc()) && !PRIMARY_KEY.equals(this)) { + script.append(" ").append(column.getAscOrDesc()); + } + script.append(","); } } script.deleteCharAt(script.length() - 1); diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/builder/OracleSqlBuilder.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/builder/OracleSqlBuilder.java index 1a7eb5895..85096d600 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/builder/OracleSqlBuilder.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/builder/OracleSqlBuilder.java @@ -67,10 +67,10 @@ public String buildModifyTaleSql(Table oldTable, Table newTable) { if (!StringUtils.equalsIgnoreCase(oldTable.getName(), newTable.getName())) { script.append("ALTER TABLE "). append("\"").append(oldTable.getSchemaName()).append("\".\"").append(oldTable.getName()).append("\""); - script.append(" ").append("RENAME TO ").append("\"").append(newTable.getName()).append("\"").append(";"); + script.append(" ").append("RENAME TO ").append("\"").append(newTable.getName()).append("\"").append(";\n"); } if (!StringUtils.equalsIgnoreCase(oldTable.getComment(), newTable.getComment())) { - script.append("\n").append(buildTableComment(newTable)).append(";"); + script.append("").append(buildTableComment(newTable)).append(";\n"); } @@ -92,9 +92,10 @@ public String buildModifyTaleSql(Table oldTable, Table newTable) { script.append("\t").append(mysqlIndexTypeEnum.buildModifyIndex(tableIndex)).append(";\n"); } } - - script = new StringBuilder(script.substring(0, script.length() - 2)); - script.append(";"); + if(script.length()>2) { + script = new StringBuilder(script.substring(0, script.length() - 2)); + script.append(";"); + } return script.toString(); } diff --git a/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/type/SqlServerIndexTypeEnum.java b/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/type/SqlServerIndexTypeEnum.java index 8547f6eaa..0d76e380d 100644 --- a/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/type/SqlServerIndexTypeEnum.java +++ b/chat2db-server/chat2db-plugins/chat2db-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/type/SqlServerIndexTypeEnum.java @@ -92,7 +92,7 @@ private String buildIndexColumn(TableIndex tableIndex) { for (TableIndexColumn column : tableIndex.getColumnList()) { if (StringUtils.isNotBlank(column.getColumnName())) { script.append("[").append(column.getColumnName()).append("]"); - if (!StringUtils.isBlank(column.getAscOrDesc())) { + if (!StringUtils.isBlank(column.getAscOrDesc()) && !PRIMARY_KEY.equals(this)) { script.append(" ").append(column.getAscOrDesc()); } script.append(","); diff --git a/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DlTemplateServiceImpl.java b/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DlTemplateServiceImpl.java index 9323d7212..7352202d2 100644 --- a/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DlTemplateServiceImpl.java +++ b/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/DlTemplateServiceImpl.java @@ -151,9 +151,9 @@ private ExecuteResult executeSQL(String originalSql, DbType dbType, DlExecutePar executeResult.setSqlType(sqlType); executeResult.setOriginalSql(originalSql); try { - executeResult.setCanEdit(SqlUtils.canEdit(originalSql)); - executeResult.setTableName(SqlUtils.getTableName(originalSql, dbType)); + SqlUtils.buildCanEditResult(originalSql, dbType,executeResult); } catch (Exception e) { + } if (SqlTypeEnum.SELECT.getCode().equals(sqlType)) { executeResult.setPageNo(pageNo); @@ -258,8 +258,7 @@ public DataResult updateSelectResult(UpdateSelectResultParam param) { private String getDeleteSql(UpdateSelectResultParam param, List row, MetaData metaSchema) { StringBuilder script = new StringBuilder(); - script.append("DELETE FROM ").append(metaSchema.getMetaDataName(param.getDatabaseName(), param.getSchemaName(), param.getTableName())) - .append(""); + script.append("DELETE FROM ").append( param.getTableName()).append(""); script.append(buildWhere(param.getHeaderList(), row, metaSchema)); return script.toString(); @@ -292,7 +291,7 @@ private String getInsertSql(UpdateSelectResultParam param, List row, Met return ""; } StringBuilder script = new StringBuilder(); - script.append("INSERT INTO ").append(metaSchema.getMetaDataName(param.getDatabaseName(), param.getSchemaName(), param.getTableName())) + script.append("INSERT INTO ").append( param.getTableName()) .append(" ("); for (int i = 1; i < row.size(); i++) { Header header = param.getHeaderList().get(i); @@ -319,8 +318,7 @@ private String getUpdateSql(UpdateSelectResultParam param, List row, Lis if (CollectionUtils.isEmpty(row) || CollectionUtils.isEmpty(odlRow)) { return ""; } - script.append("UPDATE ").append(metaSchema.getMetaDataName(param.getDatabaseName(), param.getSchemaName(), param.getTableName())) - .append(" set "); + script.append("UPDATE ").append(param.getTableName()).append(" set "); for (int i = 1; i < row.size(); i++) { String newValue = row.get(i); String oldValue = odlRow.get(i); diff --git a/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/TableServiceImpl.java b/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/TableServiceImpl.java index 4a0a62fc8..1d73fea5b 100644 --- a/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/TableServiceImpl.java +++ b/chat2db-server/chat2db-server-domain/chat2db-server-domain-core/src/main/java/ai/chat2db/server/domain/core/impl/TableServiceImpl.java @@ -252,7 +252,7 @@ private long addDBCache(Long dataSourceId, String databaseName, String schemaNam Connection connection = Chat2DBContext.getConnection(); long n = 0; try (ResultSet resultSet = connection.getMetaData().getTables(databaseName, schemaName, null, - new String[]{"TABLE"})) { + new String[]{"TABLE","SYSTEM TABLE"})) { List cacheDOS = new ArrayList<>(); while (resultSet.next()) { TableCacheDO tableCacheDO = new TableCacheDO(); diff --git a/chat2db-server/chat2db-server-start/src/main/resources/thymeleaf/index.html b/chat2db-server/chat2db-server-start/src/main/resources/thymeleaf/index.html index 9916759a3..9d238cfc2 100644 --- a/chat2db-server/chat2db-server-start/src/main/resources/thymeleaf/index.html +++ b/chat2db-server/chat2db-server-start/src/main/resources/thymeleaf/index.html @@ -1,52 +1,23 @@ - - - - - - Chat2DB - - - - - - - + + + + + +Chat2DB + + + -
- + - - - + \ No newline at end of file diff --git a/chat2db-server/chat2db-server-tools/chat2db-server-tools-common/src/main/java/ai/chat2db/server/tools/common/util/ConfigUtils.java b/chat2db-server/chat2db-server-tools/chat2db-server-tools-common/src/main/java/ai/chat2db/server/tools/common/util/ConfigUtils.java index 9f09d226f..ac0780ce8 100644 --- a/chat2db-server/chat2db-server-tools/chat2db-server-tools-common/src/main/java/ai/chat2db/server/tools/common/util/ConfigUtils.java +++ b/chat2db-server/chat2db-server-tools/chat2db-server-tools-common/src/main/java/ai/chat2db/server/tools/common/util/ConfigUtils.java @@ -1,16 +1,15 @@ package ai.chat2db.server.tools.common.util; -import ai.chat2db.server.tools.common.config.GlobalDict; import ai.chat2db.server.tools.common.model.ConfigJson; import cn.hutool.core.io.FileUtil; import com.alibaba.fastjson2.JSON; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.core.io.ClassPathResource; -import org.springframework.util.DigestUtils; import java.io.File; -import java.util.Collections; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.util.Arrays; import java.util.List; /** @@ -28,6 +27,10 @@ public class ConfigUtils { public static File versionFile = null; public static File configFile; private static ConfigJson config = null; + /** + * 模板文件 + **/ + public static final List TEMPLATE_FILE = Arrays.asList("template.html", "template_diy.docx", "sub_template_diy.docx"); static { String environment = StringUtils.defaultString(System.getProperty("spring.profiles.active"), "dev"); @@ -96,29 +99,35 @@ private static String getAppPath() { } public static void copyTemplateFile() { - try { - ClassPathResource resourceFolder = new ClassPathResource("template"); - // 复制文件夹到目标路径 - if (!getMD5(resourceFolder.getFile().getPath()).equals(getMD5(GlobalDict.templateDir))) { - File targetFolder = new File(CONFIG_BASE_PATH); - FileUtil.copy(resourceFolder.getFile(), targetFolder, true); - } - } catch (Exception e) { - log.error("copy error", e); + String templateDir = CONFIG_BASE_PATH + File.separator + "template"; + File file = new File(templateDir); + if (!file.exists()) { + file.mkdir(); + } + for (String template : TEMPLATE_FILE) { + saveFile(templateDir, template, true); } } - public static String getMD5(String folderPath) { - File folder = new File(folderPath); - List files = FileUtil.loopFiles(folder); - // 对文件列表进行排序 - Collections.sort(files); - // 拼接文件内容 - StringBuilder stringBuilder = new StringBuilder(); - for (File file : files) { - stringBuilder.append(FileUtil.readUtf8String(file)); + public static void saveFile(String dir, String path, boolean isOverride) { + if (!isOverride) { + File file = new File(dir + File.separator + path); + if (file.exists()) { + return; + } + } + try (// 模板文件输入输出地址 读取resources下文件 + FileOutputStream outputStream = new FileOutputStream(dir + File.separator + path); + //返回读取指定资源的输入流 + InputStream inputStream = ConfigUtils.class.getClassLoader().getResourceAsStream("template" + File.separator + path)) { + byte[] buffer = new byte[4096]; + int n = 0; + while (-1 != (n = inputStream.read(buffer))) { + outputStream.write(buffer, 0, n); + } + outputStream.flush(); + } catch (Exception e) { + log.error("saveFile error", e); } - // 计算 MD5 值 - return DigestUtils.md5DigestAsHex(stringBuilder.toString().getBytes()); } } diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/DefaultMetaService.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/DefaultMetaService.java index 6ec6b09d0..8f39e9205 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/DefaultMetaService.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/DefaultMetaService.java @@ -34,7 +34,7 @@ public String tableDDL(Connection connection, String databaseName, String schema @Override public List tables(Connection connection, String databaseName, String schemaName, String tableName) { - return SQLExecutor.getInstance().tables(connection, StringUtils.isEmpty(databaseName) ? null : databaseName, StringUtils.isEmpty(schemaName) ? null : schemaName, tableName, new String[]{"TABLE"}); + return SQLExecutor.getInstance().tables(connection, StringUtils.isEmpty(databaseName) ? null : databaseName, StringUtils.isEmpty(schemaName) ? null : schemaName, tableName, new String[]{"TABLE","SYSTEM TABLE"}); } @Override diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SqlUtils.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SqlUtils.java index f40311fe2..e6aef38de 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SqlUtils.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/SqlUtils.java @@ -1,60 +1,17 @@ package ai.chat2db.spi.util; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -import ai.chat2db.server.tools.common.util.EasyIntegerUtils; +import ai.chat2db.server.tools.base.excption.BusinessException; import ai.chat2db.spi.enums.DataTypeEnum; +import ai.chat2db.spi.model.ExecuteResult; import com.alibaba.druid.DbType; import com.alibaba.druid.sql.SQLUtils; -import com.alibaba.druid.sql.ast.SQLDataTypeImpl; import com.alibaba.druid.sql.ast.SQLStatement; -import com.alibaba.druid.sql.ast.expr.SQLCharExpr; -import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddConstraint; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropPrimaryKey; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement; -import com.alibaba.druid.sql.ast.statement.SQLAssignItem; -import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; -import com.alibaba.druid.sql.ast.statement.SQLColumnPrimaryKey; -import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement; -import com.alibaba.druid.sql.ast.statement.SQLDropIndexStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource; -import com.alibaba.druid.sql.ast.statement.SQLNotNullConstraint; -import com.alibaba.druid.sql.ast.statement.SQLNullConstraint; -import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLTableSource; -import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; -import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique; -import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlCharExpr; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableChangeColumn; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableModifyColumn; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement.Item; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlTableIndex; import com.alibaba.druid.sql.parser.SQLParserUtils; - -import ai.chat2db.server.tools.base.excption.BusinessException; -import ai.chat2db.server.tools.common.util.EasyBooleanUtils; -import ai.chat2db.server.tools.common.util.EasyCollectionUtils; -import ai.chat2db.server.tools.common.util.EasyEnumUtils; -import ai.chat2db.spi.enums.CollationEnum; -import ai.chat2db.spi.enums.IndexTypeEnum; -import ai.chat2db.spi.model.Sql; -import ai.chat2db.spi.model.Table; -import ai.chat2db.spi.model.TableColumn; -import ai.chat2db.spi.model.TableIndex; -import ai.chat2db.spi.model.TableIndexColumn; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.Statements; @@ -62,10 +19,13 @@ import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectExpressionItem; import net.sf.jsqlparser.statement.select.SelectItem; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + /** * @author jipengfei * @version : SqlUtils.java @@ -74,8 +34,7 @@ public class SqlUtils { public static final String DEFAULT_TABLE_NAME = "table1"; - - public static boolean canEdit(String sql) { + public static void buildCanEditResult(String sql, DbType dbType, ExecuteResult executeResult) { try { Statement statement = CCJSqlParserUtil.parse(sql); if (statement instanceof Select) { @@ -86,388 +45,28 @@ public static boolean canEdit(String sql) { if (item instanceof SelectExpressionItem) { SelectExpressionItem expressionItem = (SelectExpressionItem) item; if (expressionItem.getAlias() != null) { - return false; // 找到了一个别名 + //canEdit = false; // 找到了一个别名 + executeResult.setCanEdit(false); + return ; } } } - return true; - } - } - } catch (Exception e) { - return false; - } - return false; - } - - public static List buildSql(Table oldTable, Table newTable) { - List sqlList = new ArrayList<>(); - // 创建表 - if (oldTable == null) { - MySqlCreateTableStatement mySqlCreateTableStatement = new MySqlCreateTableStatement(); - mySqlCreateTableStatement.setDbType(DbType.mysql); - mySqlCreateTableStatement.setTableName(newTable.getName()); - if (!Objects.isNull(newTable.getComment())) { - mySqlCreateTableStatement.setComment(new MySqlCharExpr(newTable.getComment())); - } - List columnList = newTable.getColumnList(); - if (!CollectionUtils.isEmpty(columnList)) { - for (TableColumn tableColumn : columnList) { - SQLColumnDefinition sqlColumnDefinition = new SQLColumnDefinition(); - mySqlCreateTableStatement.addColumn(sqlColumnDefinition); - sqlColumnDefinition.setName(tableColumn.getName()); - sqlColumnDefinition.setDataType(new SQLDataTypeImpl(tableColumn.getColumnType())); - if (tableColumn.getNullable() == 1) { - sqlColumnDefinition.addConstraint(new SQLNullConstraint()); - } else { - sqlColumnDefinition.addConstraint(new SQLNotNullConstraint()); - } - if (!Objects.isNull(tableColumn.getDefaultValue())) { - sqlColumnDefinition.setDefaultExpr(new MySqlCharExpr(tableColumn.getDefaultValue())); - } - sqlColumnDefinition.setAutoIncrement(BooleanUtils.isTrue(tableColumn.getAutoIncrement())); - if (!Objects.isNull(tableColumn.getComment())) { - sqlColumnDefinition.setComment(tableColumn.getComment()); - } - if (BooleanUtils.isTrue(tableColumn.getPrimaryKey())) { - sqlColumnDefinition.addConstraint(new SQLColumnPrimaryKey()); - } - } - //// 主键 - //List primaryKeyColumnList = EasyCollectionUtils.stream(columnList) - // .filter(tableColumn -> BooleanUtils.isTrue(tableColumn.getPrimaryKey())) - // .collect(Collectors.toList()); - //if (!CollectionUtils.isEmpty(primaryKeyColumnList)) { - // MySqlPrimaryKey mySqlPrimaryKey = new MySqlPrimaryKey(); - // mySqlCreateTableStatement.getTableElementList().add(mySqlPrimaryKey); - // for (TableColumn tableColumn : primaryKeyColumnList) { - // mySqlPrimaryKey.addColumn(new SQLIdentifierExpr(tableColumn.getName())); - // } - //} - } - - // 索引 - List indexList = newTable.getIndexList(); - if (!CollectionUtils.isEmpty(indexList)) { - for (TableIndex tableIndex : indexList) { - if (IndexTypeEnum.UNIQUE.getCode().equals(tableIndex.getType())) { - MySqlUnique mySqlUnique = new MySqlUnique(); - mySqlCreateTableStatement.getTableElementList().add(mySqlUnique); - mySqlUnique.setName(tableIndex.getName()); - mySqlUnique.setComment(new SQLCharExpr(tableIndex.getComment())); - mySqlUnique.getIndexDefinition().setType("unique"); - if (!CollectionUtils.isEmpty(tableIndex.getColumnList())) { - for (TableIndexColumn tableIndexColumn : tableIndex.getColumnList()) { - SQLSelectOrderByItem sqlSelectOrderByItem = new SQLSelectOrderByItem(); - sqlSelectOrderByItem.setExpr(new SQLIdentifierExpr(tableIndexColumn.getColumnName())); - CollationEnum collation = EasyEnumUtils.getEnum(CollationEnum.class, - tableIndexColumn.getCollation()); - if (collation != null) { - sqlSelectOrderByItem.setType(collation.getSqlOrderingSpecification()); - } - mySqlUnique.addColumn(sqlSelectOrderByItem); - } - } - } else { - MySqlTableIndex mySqlTableIndex = new MySqlTableIndex(); - mySqlCreateTableStatement.getTableElementList().add(mySqlTableIndex); - mySqlTableIndex.setName(tableIndex.getName()); - mySqlTableIndex.setComment(new SQLCharExpr(tableIndex.getComment())); - if (!CollectionUtils.isEmpty(tableIndex.getColumnList())) { - for (TableIndexColumn tableIndexColumn : tableIndex.getColumnList()) { - SQLSelectOrderByItem sqlSelectOrderByItem = new SQLSelectOrderByItem(); - sqlSelectOrderByItem.setExpr(new SQLIdentifierExpr(tableIndexColumn.getColumnName())); - CollationEnum collation = EasyEnumUtils.getEnum(CollationEnum.class, - tableIndexColumn.getCollation()); - if (collation != null) { - sqlSelectOrderByItem.setType(collation.getSqlOrderingSpecification()); - } - mySqlTableIndex.addColumn(sqlSelectOrderByItem); - } - } + executeResult.setCanEdit(true); + SQLStatement sqlStatement = SQLUtils.parseSingleStatement(sql, dbType); + if ((sqlStatement instanceof SQLSelectStatement sqlSelectStatement)) { + SQLExprTableSource sqlExprTableSource = (SQLExprTableSource) getSQLExprTableSource( + sqlSelectStatement.getSelect().getFirstQueryBlock().getFrom()); + executeResult.setTableName(getMetaDataTableName(sqlExprTableSource.getCatalog(), sqlExprTableSource.getSchema(), sqlExprTableSource.getTableName())); } } } - - sqlList.add(Sql.builder().sql(mySqlCreateTableStatement + ";").build()); - return sqlList; - } - - // 修改表结构 - // 修改表名字 - if (!StringUtils.equals(oldTable.getName(), newTable.getName())) { - MySqlRenameTableStatement mySqlRenameTableStatement = new MySqlRenameTableStatement(); - mySqlRenameTableStatement.setDbType(DbType.mysql); - Item item = new Item(); - item.setName(new SQLIdentifierExpr(oldTable.getName())); - item.setTo(new SQLIdentifierExpr(newTable.getName())); - mySqlRenameTableStatement.addItem(item); - sqlList.add(Sql.builder().sql(mySqlRenameTableStatement + ";").build()); - } - // 修改注释 - if (!StringUtils.equals(oldTable.getComment(), newTable.getComment())) { - SQLAlterTableStatement sqlAlterTableStatement = new SQLAlterTableStatement(); - sqlAlterTableStatement.setDbType(DbType.mysql); - SQLAssignItem sqlAssignItem = new SQLAssignItem(); - sqlAssignItem.setTarget(new SQLIdentifierExpr("COMMENT")); - sqlAssignItem.setValue(new MySqlCharExpr(newTable.getComment())); - sqlAlterTableStatement.getTableOptions().add(sqlAssignItem); - sqlList.add(Sql.builder().sql(sqlAlterTableStatement + ";").build()); - } - // 修改字段 - modifyColumn(sqlList, oldTable, newTable); - - // 修改索引 - modifyIndex(sqlList, oldTable, newTable); - return sqlList; - } - - private static void modifyColumn(List sqlList, Table oldTable, Table newTable) { - Map oldColumnMap = EasyCollectionUtils.toIdentityMap(oldTable.getColumnList(), - tableColumn -> { - if (tableColumn.getOldName() != null) { - return tableColumn.getOldName(); - } - return tableColumn.getName(); - }); - Map newColumnMap = EasyCollectionUtils.toIdentityMap(newTable.getColumnList(), - tableColumn -> { - if (tableColumn.getOldName() != null) { - return tableColumn.getOldName(); - } - return tableColumn.getName(); - }); - - SQLAlterTableStatement sqlAlterTableStatement = new SQLAlterTableStatement(); - sqlAlterTableStatement.setDbType(DbType.mysql); - sqlAlterTableStatement.setTableSource(new SQLIdentifierExpr(newTable.getName())); - - newColumnMap.forEach((newTableColumnName, newTableColumn) -> { - TableColumn oldTableColumn = oldColumnMap.get(newTableColumnName); - // 代表新增字段 - if (oldTableColumn == null) { - - SQLAlterTableAddColumn sqlAlterTableAddColumn = new SQLAlterTableAddColumn(); - sqlAlterTableStatement.addItem(sqlAlterTableAddColumn); - SQLColumnDefinition sqlColumnDefinition = new SQLColumnDefinition(); - sqlAlterTableAddColumn.addColumn(sqlColumnDefinition); - sqlColumnDefinition.setName(newTableColumn.getName()); - sqlColumnDefinition.setDataType(new SQLDataTypeImpl(newTableColumn.getColumnType())); - if (newTableColumn.getNullable() != 1) { - sqlColumnDefinition.addConstraint(new SQLNotNullConstraint()); - } - if (!Objects.isNull(newTableColumn.getDefaultValue())) { - sqlColumnDefinition.setDefaultExpr(new MySqlCharExpr(newTableColumn.getDefaultValue())); - } - sqlColumnDefinition.setAutoIncrement(BooleanUtils.isTrue(newTableColumn.getAutoIncrement())); - if (!Objects.isNull(newTableColumn.getComment())) { - sqlColumnDefinition.setComment(newTableColumn.getComment()); - } - return; - } - // 代表可能修改字段 或者没变 - boolean hasChange = !StringUtils.equals(oldTableColumn.getName(), newTableColumn.getName()) - || !StringUtils.equals(oldTableColumn.getColumnType(), newTableColumn.getColumnType()) - || !EasyIntegerUtils.equals(oldTableColumn.getNullable(), newTableColumn.getNullable(), 1) - || !StringUtils.equals(oldTableColumn.getDefaultValue(), newTableColumn.getDefaultValue()) - || !EasyBooleanUtils.equals(oldTableColumn.getAutoIncrement(), newTableColumn.getAutoIncrement(), - Boolean.FALSE) - || !StringUtils.equals(oldTableColumn.getComment(), newTableColumn.getComment()); - - // 没有修改字段 - if (!hasChange) { - return; - } - - // 修改字段包含字段名 - if (!StringUtils.equals(oldTableColumn.getName(), newTableColumn.getName())) { - MySqlAlterTableChangeColumn mySqlAlterTableChangeColumn = new MySqlAlterTableChangeColumn(); - sqlAlterTableStatement.addItem(mySqlAlterTableChangeColumn); - mySqlAlterTableChangeColumn.setColumnName(new SQLIdentifierExpr(newTableColumn.getOldName())); - SQLColumnDefinition sqlColumnDefinition = new SQLColumnDefinition(); - mySqlAlterTableChangeColumn.setNewColumnDefinition(sqlColumnDefinition); - sqlColumnDefinition.setName(newTableColumn.getName()); - sqlColumnDefinition.setDataType(new SQLDataTypeImpl(newTableColumn.getColumnType())); - if (newTableColumn.getNullable() != 1) { - sqlColumnDefinition.addConstraint(new SQLNotNullConstraint()); - } - if (!Objects.isNull(newTableColumn.getDefaultValue())) { - sqlColumnDefinition.setDefaultExpr(new MySqlCharExpr(newTableColumn.getDefaultValue())); - } - sqlColumnDefinition.setAutoIncrement(BooleanUtils.isTrue(newTableColumn.getAutoIncrement())); - if (!Objects.isNull(newTableColumn.getComment())) { - sqlColumnDefinition.setComment(newTableColumn.getComment()); - } - } else { - // 修改字段不包括字段名 - MySqlAlterTableModifyColumn mySqlAlterTableModifyColumn = new MySqlAlterTableModifyColumn(); - sqlAlterTableStatement.addItem(mySqlAlterTableModifyColumn); - SQLColumnDefinition sqlColumnDefinition = new SQLColumnDefinition(); - mySqlAlterTableModifyColumn.setNewColumnDefinition(sqlColumnDefinition); - sqlColumnDefinition.setName(newTableColumn.getName()); - sqlColumnDefinition.setDataType(new SQLDataTypeImpl(newTableColumn.getColumnType())); - if (newTableColumn.getNullable() != 1) { - sqlColumnDefinition.addConstraint(new SQLNotNullConstraint()); - } - if (!Objects.isNull(newTableColumn.getDefaultValue())) { - sqlColumnDefinition.setDefaultExpr(new MySqlCharExpr(newTableColumn.getDefaultValue())); - } - sqlColumnDefinition.setAutoIncrement(BooleanUtils.isTrue(newTableColumn.getAutoIncrement())); - if (!Objects.isNull(newTableColumn.getComment())) { - sqlColumnDefinition.setComment(newTableColumn.getComment()); - } - } - }); - - oldColumnMap.forEach((oldTableColumnName, oldTableColumn) -> { - TableColumn newTableColumn = newColumnMap.get(oldTableColumnName); - // 代表删除字段 - if (newTableColumn == null) { - SQLAlterTableDropColumnItem sqlAlterTableDropColumnItem = new SQLAlterTableDropColumnItem(); - sqlAlterTableStatement.addItem(sqlAlterTableDropColumnItem); - sqlAlterTableDropColumnItem.addColumn(new SQLIdentifierExpr(oldTableColumn.getName())); - } - }); - - // 比较主键是否有修改 - // 主键 - Set oldPrimaryKeySet = EasyCollectionUtils.stream(oldTable.getColumnList()) - .filter(tableColumn -> BooleanUtils.isTrue(tableColumn.getPrimaryKey())) - .map(TableColumn::getName) - .collect(Collectors.toSet()); - Set newPrimaryKeySet = EasyCollectionUtils.stream(newTable.getColumnList()) - .filter(tableColumn -> BooleanUtils.isTrue(tableColumn.getPrimaryKey())) - .map(TableColumn::getName) - .collect(Collectors.toSet()); - boolean primaryKeyChange = oldPrimaryKeySet.stream() - .anyMatch(oldPrimaryKey -> !newPrimaryKeySet.contains(oldPrimaryKey)) - || newPrimaryKeySet.stream() - .anyMatch(newPrimaryKey -> !oldPrimaryKeySet.contains(newPrimaryKey)); - if (primaryKeyChange) { - sqlAlterTableStatement.addItem(new SQLAlterTableDropPrimaryKey()); - SQLAlterTableAddConstraint sqlAlterTableAddConstraint = new SQLAlterTableAddConstraint(); - sqlAlterTableStatement.addItem(sqlAlterTableAddConstraint); - MySqlPrimaryKey mySqlPrimaryKey = new MySqlPrimaryKey(); - sqlAlterTableAddConstraint.setConstraint(mySqlPrimaryKey); - mySqlPrimaryKey.setIndexType("PRIMARY"); - // 排序 - EasyCollectionUtils.stream(newTable.getColumnList()) - .filter(tableColumn -> BooleanUtils.isTrue(tableColumn.getPrimaryKey())) - .map(TableColumn::getName) - .forEach(tableColumnName -> mySqlPrimaryKey.addColumn( - new SQLSelectOrderByItem(new SQLIdentifierExpr(tableColumnName)))); - } - - if (CollectionUtils.isNotEmpty(sqlAlterTableStatement.getItems())) { - sqlList.add(Sql.builder().sql(sqlAlterTableStatement + ";").build()); + } catch (Exception e) { + executeResult.setCanEdit(false); } } - private static void modifyIndex(List sqlList, Table oldTable, Table newTable) { - Map oldIndexMap = EasyCollectionUtils.toIdentityMap(oldTable.getIndexList(), - TableIndex::getName); - Map newIndexMap = EasyCollectionUtils.toIdentityMap(newTable.getIndexList(), - TableIndex::getName); - newIndexMap.forEach((newTableIndexName, newTableIndex) -> { - TableIndex oldTableIndex = oldIndexMap.get(newTableIndexName); - // 代表新增索引 - if (oldTableIndex == null) { - SQLCreateIndexStatement sqlCreateIndexStatement = new SQLCreateIndexStatement(); - sqlCreateIndexStatement.setTable(new SQLExprTableSource(newTable.getName())); - sqlCreateIndexStatement.setName(new SQLIdentifierExpr(newTableIndex.getName())); - if (!Objects.isNull(newTableIndex.getComment())) { - sqlCreateIndexStatement.setComment(new SQLCharExpr(newTableIndex.getComment())); - } - if (!CollectionUtils.isEmpty(newTableIndex.getColumnList())) { - for (TableIndexColumn tableIndexColumn : newTableIndex.getColumnList()) { - SQLSelectOrderByItem sqlSelectOrderByItem = new SQLSelectOrderByItem(); - sqlSelectOrderByItem.setExpr(new SQLIdentifierExpr(tableIndexColumn.getColumnName())); - CollationEnum collation = EasyEnumUtils.getEnum(CollationEnum.class, - tableIndexColumn.getCollation()); - if (collation != null) { - sqlSelectOrderByItem.setType(collation.getSqlOrderingSpecification()); - } - sqlCreateIndexStatement.getColumns().add(sqlSelectOrderByItem); - } - } - sqlList.add(Sql.builder().sql(sqlCreateIndexStatement + ";").build()); - return; - } - // 代表可能修改索引 或者没变 - boolean hasChange = !StringUtils.equals(oldTableIndex.getName(), newTableIndex.getName()) - || !StringUtils.equals(oldTableIndex.getComment(), newTableIndex.getComment()) - || !Objects.equals(oldTableIndex.getUnique(), newTableIndex.getUnique()); - if (!hasChange) { - Map oldTableIndexColumnMap = EasyCollectionUtils.toIdentityMap( - oldTableIndex.getColumnList(), TableIndexColumn::getColumnName); - Map newTableIndexColumnMap = EasyCollectionUtils.toIdentityMap( - newTableIndex.getColumnList(), TableIndexColumn::getColumnName); - hasChange = oldTableIndexColumnMap.entrySet() - .stream() - .anyMatch(oldTableIndexColumnEntry -> { - TableIndexColumn newTableIndexColumn = newTableIndexColumnMap.get( - oldTableIndexColumnEntry.getKey()); - if (newTableIndexColumn == null) { - return true; - } - TableIndexColumn oldTableIndexColumn = oldTableIndexColumnEntry.getValue(); - return !StringUtils.equals(oldTableIndexColumn.getColumnName(), - newTableIndexColumn.getColumnName()) - || !CollationEnum.equals(oldTableIndexColumn.getCollation(), - newTableIndexColumn.getCollation()); - }) - || newTableIndexColumnMap.entrySet() - .stream() - .anyMatch(newTableIndexColumnEntry -> { - TableIndexColumn oldTableIndexColumn = oldTableIndexColumnMap.get( - newTableIndexColumnEntry.getKey()); - return oldTableIndexColumn == null; - }); - } - - // 没有修改索引 - if (!hasChange) { - return; - } - // 先删除 - SQLDropIndexStatement sqlDropIndexStatement = new SQLDropIndexStatement(); - sqlDropIndexStatement.setDbType(DbType.mysql); - sqlDropIndexStatement.setTableName(new SQLExprTableSource(newTable.getName())); - sqlDropIndexStatement.setIndexName(new SQLIdentifierExpr(newTableIndex.getName())); - sqlList.add(Sql.builder().sql(sqlDropIndexStatement + ";").build()); - - // 再新增 - SQLCreateIndexStatement sqlCreateIndexStatement = new SQLCreateIndexStatement(); - sqlCreateIndexStatement.setTable(new SQLExprTableSource(newTable.getName())); - sqlCreateIndexStatement.setName(new SQLIdentifierExpr(newTableIndex.getName())); - if (!Objects.isNull(newTableIndex.getComment())) { - sqlCreateIndexStatement.setComment(new SQLCharExpr(newTableIndex.getComment())); - } - if (!CollectionUtils.isEmpty(newTableIndex.getColumnList())) { - for (TableIndexColumn tableIndexColumn : newTableIndex.getColumnList()) { - SQLSelectOrderByItem sqlSelectOrderByItem = new SQLSelectOrderByItem(); - sqlSelectOrderByItem.setExpr(new SQLIdentifierExpr(tableIndexColumn.getColumnName())); - CollationEnum collation = EasyEnumUtils.getEnum(CollationEnum.class, - tableIndexColumn.getCollation()); - if (collation != null) { - sqlSelectOrderByItem.setType(collation.getSqlOrderingSpecification()); - } - sqlCreateIndexStatement.getColumns().add(sqlSelectOrderByItem); - } - } - sqlList.add(Sql.builder().sql(sqlCreateIndexStatement + ";").build()); - }); - - oldIndexMap.forEach((oldTableIndexName, oldTableIndex) -> { - TableIndex newTableIndex = newIndexMap.get(oldTableIndexName); - // 代表删除索引 - if (newTableIndex == null) { - SQLDropIndexStatement sqlDropIndexStatement = new SQLDropIndexStatement(); - sqlDropIndexStatement.setDbType(DbType.mysql); - sqlDropIndexStatement.setTableName(new SQLExprTableSource(newTable.getName())); - sqlDropIndexStatement.setIndexName(new SQLIdentifierExpr(oldTableIndex.getName())); - sqlList.add(Sql.builder().sql(sqlDropIndexStatement + ";").build()); - } - }); + private static String getMetaDataTableName(String... names) { + return Arrays.stream(names).filter(name -> StringUtils.isNotBlank(name)).map(name -> name ).collect(Collectors.joining(".")); } public static String formatSQLString(Object para) { @@ -511,7 +110,7 @@ public static List parse(String sql, DbType dbType) { } public static String getSqlValue(String value, String dataType) { - if(value == null){ + if (value == null) { return null; } DataTypeEnum dataTypeEnum = DataTypeEnum.getByCode(dataType);