增加 druid 解析 sql,用于后续生成代码

This commit is contained in:
YunaiV
2021-02-13 01:23:52 +08:00
parent 0c8f92fa95
commit 8d6b14bc9c
3 changed files with 142 additions and 0 deletions

View File

@ -0,0 +1,108 @@
package cn.iocoder.dashboard.modules.tool.service.codegen.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolSchemaColumnDO;
import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolSchemaTableDO;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey;
import com.alibaba.druid.sql.ast.statement.SQLTableElement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
import com.alibaba.druid.sql.repository.SchemaRepository;
import org.apache.commons.collections4.KeyValue;
import org.apache.commons.collections4.keyvalue.DefaultKeyValue;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.druid.sql.SQLUtils.normalize;
/**
* SQL 解析器,将创建表的 SQL解析成 {@link ToolSchemaTableDO} 和 {@link ToolSchemaColumnDO} 对象,
* 后续可以基于它们,生成代码~
*
* @author 芋道源码
*/
public class ToolCodegenSQLParser {
/**
* 解析建表 SQL 语句,返回 {@link ToolSchemaTableDO} 和 {@link ToolSchemaColumnDO} 对象
*
* @param sql 建表 SQL 语句
* @return 解析结果
*/
public static KeyValue<ToolSchemaTableDO, List<ToolSchemaColumnDO>> parse(String sql) {
// 解析 SQL 成 Statement
SQLCreateTableStatement statement = parseCreateSQL(sql);
// 解析 Table 表
ToolSchemaTableDO table = parseTable(statement);
// 解析 Column 字段
List<ToolSchemaColumnDO> columns = parseColumns(statement);
columns.forEach(column -> column.setTableName(table.getTableName()));
// 返回
return new DefaultKeyValue<>(table, columns);
}
/**
* 使用 Druid 工具,建表 SQL 语句
*
* @param sql 建表 SQL 语句
* @return 创建 Statement
*/
private static SQLCreateTableStatement parseCreateSQL(String sql) {
// 解析 SQL
SchemaRepository repository = new SchemaRepository(DbType.mysql);
repository.console(sql);
// 获得该表对应的 MySqlCreateTableStatement 对象
String tableName = CollUtil.getFirst(repository.getDefaultSchema().getObjects()).getName();
return (MySqlCreateTableStatement) repository.findTable(tableName).getStatement();
}
private static ToolSchemaTableDO parseTable(SQLCreateTableStatement statement) {
return ToolSchemaTableDO.builder()
.tableName(statement.getTableSource().getTableName(true))
.tableComment(((SQLCharExpr) statement.getComment()).getText())
.build();
}
private static List<ToolSchemaColumnDO> parseColumns(SQLCreateTableStatement statement) {
List<ToolSchemaColumnDO> columns = new ArrayList<>();
statement.getTableElementList().forEach(element -> parseColumn(columns, element));
return columns;
}
private static void parseColumn(List<ToolSchemaColumnDO> columns, SQLTableElement element) {
// 处理主键
if (element instanceof SQLPrimaryKey) {
parsePrimaryKey(columns, (SQLPrimaryKey) element);
return;
}
// 处理字段定义
if (element instanceof SQLColumnDefinition) {
parseColumnDefinition(columns, (SQLColumnDefinition) element);
}
}
private static void parsePrimaryKey(List<ToolSchemaColumnDO> columns, SQLPrimaryKey primaryKey) {
String columnName = normalize(primaryKey.getColumns().get(0).toString()); // 暂时不考虑联合主键
// 匹配 columns 主键字段,设置为 primary
columns.stream().filter(column -> column.getColumnName().equals(columnName))
.forEach(column -> column.setPrimaryKey(true));
}
private static void parseColumnDefinition(List<ToolSchemaColumnDO> columns, SQLColumnDefinition definition) {
String text = definition.toString().toUpperCase();
columns.add(ToolSchemaColumnDO.builder()
.columnName(normalize(definition.getColumnName()))
.columnType(definition.getDataType().toString())
.columnComment(normalize(definition.getComment().toString()))
.nullable(!text.contains(" NOT NULL"))
.primaryKey(false)
.autoIncrement(text.contains("AUTO_INCREMENT"))
.ordinalPosition(columns.size() + 1)
.build());
}
}