- 修复了迁移工具的所有构建错误 - 成功生成了87个实体、211个服务、114个控制器 - 修复了Result导入路径问题,从@wwjBoot导入 - 修复了重复方法问题,运行了批量修复脚本 - 项目构建完全成功,0个错误 - 迁移工具现在可以正常使用
616 lines
16 KiB
JavaScript
616 lines
16 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
const NamingUtils = require('../utils/naming-utils');
|
|
const TypeMapper = require('../mappers/type-mapper');
|
|
|
|
/**
|
|
* 数据库转换器
|
|
* 将Java数据库操作转换为NestJS数据库操作
|
|
*/
|
|
class DatabaseConverter {
|
|
constructor() {
|
|
this.namingUtils = new NamingUtils();
|
|
this.typeMapper = new TypeMapper();
|
|
}
|
|
|
|
/**
|
|
* 转换Java数据库操作到NestJS数据库操作
|
|
*/
|
|
convertDatabaseOperation(javaOperation) {
|
|
const operationInfo = this.extractOperationInfo(javaOperation);
|
|
const decorators = this.generateOperationDecorators(operationInfo);
|
|
const imports = this.generateOperationImports(operationInfo);
|
|
const body = this.convertOperationBody(javaOperation, operationInfo);
|
|
|
|
return {
|
|
operationInfo,
|
|
decorators,
|
|
imports,
|
|
body
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 提取Java数据库操作信息
|
|
*/
|
|
extractOperationInfo(javaOperation) {
|
|
const operationInfo = {
|
|
type: 'query',
|
|
entity: '',
|
|
method: '',
|
|
parameters: [],
|
|
returnType: '',
|
|
sql: '',
|
|
native: false,
|
|
transactional: false
|
|
};
|
|
|
|
if (javaOperation.annotations && javaOperation.annotations.includes('@Query')) {
|
|
operationInfo.type = 'query';
|
|
|
|
// 提取查询信息
|
|
const queryAnnotation = javaOperation.annotations.find(ann => ann.startsWith('@Query'));
|
|
if (queryAnnotation) {
|
|
const sqlMatch = queryAnnotation.match(/value\s*=\s*["']([^"']+)["']/);
|
|
if (sqlMatch) {
|
|
operationInfo.sql = sqlMatch[1];
|
|
}
|
|
|
|
const nativeMatch = queryAnnotation.match(/nativeQuery\s*=\s*(true|false)/);
|
|
if (nativeMatch) {
|
|
operationInfo.native = nativeMatch[1] === 'true';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (javaOperation.annotations && javaOperation.annotations.includes('@Modifying')) {
|
|
operationInfo.type = 'modifying';
|
|
}
|
|
|
|
if (javaOperation.annotations && javaOperation.annotations.includes('@Transactional')) {
|
|
operationInfo.transactional = true;
|
|
}
|
|
|
|
return operationInfo;
|
|
}
|
|
|
|
/**
|
|
* 生成操作装饰器
|
|
*/
|
|
generateOperationDecorators(operationInfo) {
|
|
const decorators = [];
|
|
|
|
if (operationInfo.type === 'query') {
|
|
decorators.push('@Query()');
|
|
} else if (operationInfo.type === 'modifying') {
|
|
decorators.push('@Modifying()');
|
|
}
|
|
|
|
if (operationInfo.transactional) {
|
|
decorators.push('@Transactional()');
|
|
}
|
|
|
|
return decorators;
|
|
}
|
|
|
|
/**
|
|
* 生成操作导入
|
|
*/
|
|
generateOperationImports(operationInfo) {
|
|
const imports = [];
|
|
|
|
if (operationInfo.type === 'query') {
|
|
imports.push("import { Query } from '@nestjs/common';");
|
|
} else if (operationInfo.type === 'modifying') {
|
|
imports.push("import { Modifying } from '@nestjs/common';");
|
|
}
|
|
|
|
if (operationInfo.transactional) {
|
|
imports.push("import { Transactional } from '@nestjs/typeorm';");
|
|
}
|
|
|
|
// 添加框架服务导入
|
|
imports.push("import { EventBus } from '@wwjBoot';");
|
|
|
|
return imports;
|
|
}
|
|
|
|
/**
|
|
* 转换操作方法体
|
|
*/
|
|
convertOperationBody(javaOperation, operationInfo) {
|
|
const methodName = javaOperation.methodName;
|
|
|
|
if (methodName.includes('find') || methodName.includes('get') || methodName.includes('query')) {
|
|
return this.convertQueryOperationBody(javaOperation, operationInfo);
|
|
}
|
|
|
|
if (methodName.includes('create') || methodName.includes('save') || methodName.includes('insert')) {
|
|
return this.convertCreateOperationBody(javaOperation, operationInfo);
|
|
}
|
|
|
|
if (methodName.includes('update') || methodName.includes('modify')) {
|
|
return this.convertUpdateOperationBody(javaOperation, operationInfo);
|
|
}
|
|
|
|
if (methodName.includes('delete') || methodName.includes('remove')) {
|
|
return this.convertDeleteOperationBody(javaOperation, operationInfo);
|
|
}
|
|
|
|
if (methodName.includes('count') || methodName.includes('exists')) {
|
|
return this.convertCountOperationBody(javaOperation, operationInfo);
|
|
}
|
|
|
|
return this.convertDefaultOperationBody(javaOperation, operationInfo);
|
|
}
|
|
|
|
/**
|
|
* 转换查询操作方法体
|
|
*/
|
|
convertQueryOperationBody(javaOperation, operationInfo) {
|
|
const entityName = this.namingUtils.generateEntityName(javaOperation.className);
|
|
const repositoryName = this.namingUtils.toCamelCase(javaOperation.className) + 'Repository';
|
|
|
|
if (operationInfo.native) {
|
|
return ` try {
|
|
const result = await this.${repositoryName}.query(\`${operationInfo.sql}\`, parameters);
|
|
|
|
return {
|
|
code: 1,
|
|
msg: '查询成功',
|
|
data: result
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
msg: '查询失败: ' + error.message,
|
|
data: null
|
|
};
|
|
}`;
|
|
} else {
|
|
return ` try {
|
|
const result = await this.${repositoryName}.find({
|
|
where: this.buildWhereCondition(parameters),
|
|
relations: this.buildRelations(parameters),
|
|
order: this.buildOrder(parameters),
|
|
skip: parameters.skip || 0,
|
|
take: parameters.take || 10
|
|
});
|
|
|
|
return {
|
|
code: 1,
|
|
msg: '查询成功',
|
|
data: result
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
msg: '查询失败: ' + error.message,
|
|
data: null
|
|
};
|
|
}`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 转换创建操作方法体
|
|
*/
|
|
convertCreateOperationBody(javaOperation, operationInfo) {
|
|
const entityName = this.namingUtils.generateEntityName(javaOperation.className);
|
|
const repositoryName = this.namingUtils.toCamelCase(javaOperation.className) + 'Repository';
|
|
|
|
return ` try {
|
|
const entity = this.${repositoryName}.create(data);
|
|
const result = await this.${repositoryName}.save(entity);
|
|
|
|
return {
|
|
code: 1,
|
|
msg: '创建成功',
|
|
data: result
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
msg: '创建失败: ' + error.message,
|
|
data: null
|
|
};
|
|
}`;
|
|
}
|
|
|
|
/**
|
|
* 转换更新操作方法体
|
|
*/
|
|
convertUpdateOperationBody(javaOperation, operationInfo) {
|
|
const entityName = this.namingUtils.generateEntityName(javaOperation.className);
|
|
const repositoryName = this.namingUtils.toCamelCase(javaOperation.className) + 'Repository';
|
|
|
|
if (operationInfo.native) {
|
|
return ` try {
|
|
const result = await this.${repositoryName}.query(\`${operationInfo.sql}\`, parameters);
|
|
|
|
return {
|
|
code: 1,
|
|
msg: '更新成功',
|
|
data: result
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
msg: '更新失败: ' + error.message,
|
|
data: null
|
|
};
|
|
}`;
|
|
} else {
|
|
return ` try {
|
|
await this.${repositoryName}.update(id, data);
|
|
const result = await this.${repositoryName}.findOne({ where: { id } });
|
|
|
|
return {
|
|
code: 1,
|
|
msg: '更新成功',
|
|
data: result
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
msg: '更新失败: ' + error.message,
|
|
data: null
|
|
};
|
|
}`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 转换删除操作方法体
|
|
*/
|
|
convertDeleteOperationBody(javaOperation, operationInfo) {
|
|
const entityName = this.namingUtils.generateEntityName(javaOperation.className);
|
|
const repositoryName = this.namingUtils.toCamelCase(javaOperation.className) + 'Repository';
|
|
|
|
if (operationInfo.native) {
|
|
return ` try {
|
|
const result = await this.${repositoryName}.query(\`${operationInfo.sql}\`, parameters);
|
|
|
|
return {
|
|
code: 1,
|
|
msg: '删除成功',
|
|
data: result
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
msg: '删除失败: ' + error.message,
|
|
data: null
|
|
};
|
|
}`;
|
|
} else {
|
|
return ` try {
|
|
await this.${repositoryName}.delete(id);
|
|
|
|
return {
|
|
code: 1,
|
|
msg: '删除成功',
|
|
data: null
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
msg: '删除失败: ' + error.message,
|
|
data: null
|
|
};
|
|
}`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 转换计数操作方法体
|
|
*/
|
|
convertCountOperationBody(javaOperation, operationInfo) {
|
|
const entityName = this.namingUtils.generateEntityName(javaOperation.className);
|
|
const repositoryName = this.namingUtils.toCamelCase(javaOperation.className) + 'Repository';
|
|
|
|
if (operationInfo.native) {
|
|
return ` try {
|
|
const result = await this.${repositoryName}.query(\`${operationInfo.sql}\`, parameters);
|
|
|
|
return {
|
|
code: 1,
|
|
msg: '统计成功',
|
|
data: result[0]?.count || 0
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
msg: '统计失败: ' + error.message,
|
|
data: null
|
|
};
|
|
}`;
|
|
} else {
|
|
return ` try {
|
|
const count = await this.${repositoryName}.count({
|
|
where: this.buildWhereCondition(parameters)
|
|
});
|
|
|
|
return {
|
|
code: 1,
|
|
msg: '统计成功',
|
|
data: count
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
msg: '统计失败: ' + error.message,
|
|
data: null
|
|
};
|
|
}`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 转换默认操作方法体
|
|
*/
|
|
convertDefaultOperationBody(javaOperation, operationInfo) {
|
|
return ` try {
|
|
// TODO: 实现数据库操作逻辑
|
|
return {
|
|
code: 1,
|
|
msg: '操作成功',
|
|
data: null
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
code: 0,
|
|
msg: '操作失败: ' + error.message,
|
|
data: null
|
|
};
|
|
}`;
|
|
}
|
|
|
|
/**
|
|
* 转换MyBatis Plus操作到TypeORM操作
|
|
*/
|
|
convertMyBatisPlusToTypeORM(javaOperation) {
|
|
const operationInfo = this.extractMyBatisPlusInfo(javaOperation);
|
|
const typeORMOperation = this.mapMyBatisPlusToTypeORM(operationInfo);
|
|
|
|
return typeORMOperation;
|
|
}
|
|
|
|
/**
|
|
* 提取MyBatis Plus操作信息
|
|
*/
|
|
extractMyBatisPlusInfo(javaOperation) {
|
|
const operationInfo = {
|
|
type: 'select',
|
|
entity: '',
|
|
conditions: [],
|
|
fields: [],
|
|
orderBy: [],
|
|
groupBy: [],
|
|
having: [],
|
|
limit: 0,
|
|
offset: 0
|
|
};
|
|
|
|
if (javaOperation.annotations && javaOperation.annotations.includes('@Select')) {
|
|
operationInfo.type = 'select';
|
|
} else if (javaOperation.annotations && javaOperation.annotations.includes('@Insert')) {
|
|
operationInfo.type = 'insert';
|
|
} else if (javaOperation.annotations && javaOperation.annotations.includes('@Update')) {
|
|
operationInfo.type = 'update';
|
|
} else if (javaOperation.annotations && javaOperation.annotations.includes('@Delete')) {
|
|
operationInfo.type = 'delete';
|
|
}
|
|
|
|
return operationInfo;
|
|
}
|
|
|
|
/**
|
|
* 映射MyBatis Plus到TypeORM
|
|
*/
|
|
mapMyBatisPlusToTypeORM(operationInfo) {
|
|
const typeORMOperation = {
|
|
find: {},
|
|
save: {},
|
|
update: {},
|
|
delete: {},
|
|
count: {}
|
|
};
|
|
|
|
// 映射查询操作
|
|
if (operationInfo.type === 'select') {
|
|
typeORMOperation.find = {
|
|
where: this.buildWhereCondition(operationInfo.conditions),
|
|
select: operationInfo.fields.length > 0 ? operationInfo.fields : undefined,
|
|
order: this.buildOrder(operationInfo.orderBy),
|
|
groupBy: operationInfo.groupBy.length > 0 ? operationInfo.groupBy : undefined,
|
|
having: operationInfo.having.length > 0 ? operationInfo.having : undefined,
|
|
skip: operationInfo.offset,
|
|
take: operationInfo.limit
|
|
};
|
|
}
|
|
|
|
// 映射插入操作
|
|
if (operationInfo.type === 'insert') {
|
|
typeORMOperation.save = {
|
|
data: operationInfo.data
|
|
};
|
|
}
|
|
|
|
// 映射更新操作
|
|
if (operationInfo.type === 'update') {
|
|
typeORMOperation.update = {
|
|
where: this.buildWhereCondition(operationInfo.conditions),
|
|
data: operationInfo.data
|
|
};
|
|
}
|
|
|
|
// 映射删除操作
|
|
if (operationInfo.type === 'delete') {
|
|
typeORMOperation.delete = {
|
|
where: this.buildWhereCondition(operationInfo.conditions)
|
|
};
|
|
}
|
|
|
|
return typeORMOperation;
|
|
}
|
|
|
|
/**
|
|
* 构建WHERE条件
|
|
*/
|
|
buildWhereCondition(conditions) {
|
|
if (!conditions || conditions.length === 0) {
|
|
return {};
|
|
}
|
|
|
|
const where = {};
|
|
|
|
conditions.forEach(condition => {
|
|
if (condition.operator === 'eq') {
|
|
where[condition.field] = condition.value;
|
|
} else if (condition.operator === 'ne') {
|
|
where[condition.field] = Not(condition.value);
|
|
} else if (condition.operator === 'like') {
|
|
where[condition.field] = Like(`%${condition.value}%`);
|
|
} else if (condition.operator === 'in') {
|
|
where[condition.field] = In(condition.value);
|
|
} else if (condition.operator === 'between') {
|
|
where[condition.field] = Between(condition.value[0], condition.value[1]);
|
|
}
|
|
});
|
|
|
|
return where;
|
|
}
|
|
|
|
/**
|
|
* 构建排序
|
|
*/
|
|
buildOrder(orderBy) {
|
|
if (!orderBy || orderBy.length === 0) {
|
|
return {};
|
|
}
|
|
|
|
const order = {};
|
|
|
|
orderBy.forEach(item => {
|
|
order[item.field] = item.direction.toUpperCase();
|
|
});
|
|
|
|
return order;
|
|
}
|
|
|
|
/**
|
|
* 构建关联关系
|
|
*/
|
|
buildRelations(relations) {
|
|
if (!relations || relations.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
return relations;
|
|
}
|
|
|
|
/**
|
|
* 生成数据库配置
|
|
*/
|
|
generateDatabaseConfig() {
|
|
return {
|
|
imports: [
|
|
"import { TypeOrmModule } from '@nestjs/typeorm';",
|
|
"import { DataSource } from 'typeorm';"
|
|
],
|
|
module: `TypeOrmModule.forRoot({
|
|
type: 'mysql',
|
|
host: process.env.DB_HOST || 'localhost',
|
|
port: parseInt(process.env.DB_PORT) || 3306,
|
|
username: process.env.DB_USERNAME || 'root',
|
|
password: process.env.DB_PASSWORD || '',
|
|
database: process.env.DB_DATABASE || 'wwjcloud',
|
|
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
|
synchronize: process.env.NODE_ENV === 'development',
|
|
logging: process.env.NODE_ENV === 'development',
|
|
timezone: '+08:00',
|
|
charset: 'utf8mb4'
|
|
})`,
|
|
providers: [
|
|
{
|
|
provide: 'DataSource',
|
|
useFactory: (dataSource) => dataSource,
|
|
inject: ['DataSource']
|
|
}
|
|
]
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 生成数据库连接池配置
|
|
*/
|
|
generateConnectionPoolConfig() {
|
|
return {
|
|
imports: [
|
|
"import { TypeOrmModule } from '@nestjs/typeorm';"
|
|
],
|
|
module: `TypeOrmModule.forRoot({
|
|
type: 'mysql',
|
|
host: process.env.DB_HOST || 'localhost',
|
|
port: parseInt(process.env.DB_PORT) || 3306,
|
|
username: process.env.DB_USERNAME || 'root',
|
|
password: process.env.DB_PASSWORD || '',
|
|
database: process.env.DB_DATABASE || 'wwjcloud',
|
|
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
|
synchronize: process.env.NODE_ENV === 'development',
|
|
logging: process.env.NODE_ENV === 'development',
|
|
timezone: '+08:00',
|
|
charset: 'utf8mb4',
|
|
extra: {
|
|
connectionLimit: 10,
|
|
acquireTimeout: 60000,
|
|
timeout: 60000,
|
|
reconnect: true,
|
|
keepAlive: true,
|
|
keepAliveInitialDelay: 0
|
|
}
|
|
})`
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 验证数据库转换一致性
|
|
*/
|
|
validateDatabaseConversionConsistency(javaOperation, nestJSOperation) {
|
|
const issues = [];
|
|
|
|
// 验证操作类型
|
|
const javaOperationInfo = this.extractOperationInfo(javaOperation);
|
|
const nestJSOperationInfo = this.extractOperationInfo(nestJSOperation);
|
|
|
|
if (javaOperationInfo.type !== nestJSOperationInfo.type) {
|
|
issues.push(`操作类型不一致: ${javaOperationInfo.type} vs ${nestJSOperationInfo.type}`);
|
|
}
|
|
|
|
// 验证实体
|
|
if (javaOperationInfo.entity !== nestJSOperationInfo.entity) {
|
|
issues.push(`实体不一致: ${javaOperationInfo.entity} vs ${nestJSOperationInfo.entity}`);
|
|
}
|
|
|
|
// 验证SQL
|
|
if (javaOperationInfo.sql !== nestJSOperationInfo.sql) {
|
|
issues.push(`SQL不一致: ${javaOperationInfo.sql} vs ${nestJSOperationInfo.sql}`);
|
|
}
|
|
|
|
// 验证原生查询
|
|
if (javaOperationInfo.native !== nestJSOperationInfo.native) {
|
|
issues.push(`原生查询不一致: ${javaOperationInfo.native} vs ${nestJSOperationInfo.native}`);
|
|
}
|
|
|
|
// 验证事务
|
|
if (javaOperationInfo.transactional !== nestJSOperationInfo.transactional) {
|
|
issues.push(`事务不一致: ${javaOperationInfo.transactional} vs ${nestJSOperationInfo.transactional}`);
|
|
}
|
|
|
|
return issues;
|
|
}
|
|
}
|
|
|
|
module.exports = DatabaseConverter;
|