273 lines
8.0 KiB
JavaScript
273 lines
8.0 KiB
JavaScript
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
/**
|
||
* 代码更新脚本:将所有 order_allocations 表引用更新为 transfers 表
|
||
*
|
||
* 更新策略:
|
||
* 1. 将 order_allocations 表名替换为 transfers
|
||
* 2. 更新相关的字段映射和查询逻辑
|
||
* 3. 添加必要的 WHERE 条件来过滤 allocation 类型的记录
|
||
*/
|
||
|
||
class CodeUpdater {
|
||
constructor() {
|
||
this.filesToUpdate = [
|
||
'services/matchingService.js',
|
||
'routes/matchingAdmin.js',
|
||
'routes/transfers.js',
|
||
'routes/matching.js'
|
||
];
|
||
|
||
// 字段映射关系
|
||
this.fieldMappings = {
|
||
// order_allocations 字段 -> transfers 字段
|
||
'matching_order_id': 'matching_order_id',
|
||
'from_user_id': 'from_user_id',
|
||
'to_user_id': 'to_user_id',
|
||
'amount': 'amount',
|
||
'cycle_number': 'cycle_number',
|
||
'status': 'status',
|
||
'transfer_id': 'id', // order_allocations.transfer_id 对应 transfers.id
|
||
'created_at': 'created_at',
|
||
'updated_at': 'updated_at',
|
||
'confirmed_at': 'confirmed_at',
|
||
'outbound_date': 'outbound_date',
|
||
'return_date': 'return_date',
|
||
'can_return_after': 'can_return_after'
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 更新单个文件
|
||
* @param {string} filePath - 文件路径
|
||
*/
|
||
async updateFile(filePath) {
|
||
const fullPath = path.join(process.cwd(), filePath);
|
||
|
||
if (!fs.existsSync(fullPath)) {
|
||
console.log(`文件不存在: ${filePath}`);
|
||
return;
|
||
}
|
||
|
||
console.log(`正在更新文件: ${filePath}`);
|
||
|
||
let content = fs.readFileSync(fullPath, 'utf8');
|
||
let originalContent = content;
|
||
|
||
// 1. 替换表名
|
||
content = content.replace(/\border_allocations\b/g, 'transfers');
|
||
|
||
// 2. 添加 source_type 过滤条件
|
||
content = this.addSourceTypeFilters(content);
|
||
|
||
// 3. 更新 INSERT 语句
|
||
content = this.updateInsertStatements(content);
|
||
|
||
// 4. 更新特定的查询逻辑
|
||
content = this.updateSpecificQueries(content, filePath);
|
||
|
||
// 5. 更新注释
|
||
content = this.updateComments(content);
|
||
|
||
if (content !== originalContent) {
|
||
// 创建备份
|
||
fs.writeFileSync(fullPath + '.backup', originalContent);
|
||
|
||
// 写入更新后的内容
|
||
fs.writeFileSync(fullPath, content);
|
||
|
||
console.log(`✓ 已更新: ${filePath}`);
|
||
console.log(`✓ 备份已创建: ${filePath}.backup`);
|
||
} else {
|
||
console.log(`- 无需更新: ${filePath}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 添加 source_type 过滤条件
|
||
* @param {string} content - 文件内容
|
||
* @returns {string} 更新后的内容
|
||
*/
|
||
addSourceTypeFilters(content) {
|
||
// 在 FROM transfers 后添加 WHERE source_type = 'allocation' 条件
|
||
// 但要避免重复添加
|
||
|
||
// 匹配 FROM transfers 但不包含 source_type 的情况
|
||
content = content.replace(
|
||
/FROM transfers(?!.*source_type)([\s\S]*?)(?=WHERE|ORDER|GROUP|LIMIT|;|$)/gi,
|
||
(match, afterFrom) => {
|
||
// 如果已经有 WHERE 子句,添加 AND 条件
|
||
if (afterFrom.includes('WHERE')) {
|
||
return match.replace(/WHERE/, 'WHERE source_type = \'allocation\' AND');
|
||
} else {
|
||
// 如果没有 WHERE 子句,添加新的 WHERE 条件
|
||
const beforeNextClause = match.match(/(ORDER|GROUP|LIMIT|;|$)/);
|
||
if (beforeNextClause) {
|
||
return match.replace(beforeNextClause[0], ` WHERE source_type = 'allocation' ${beforeNextClause[0]}`);
|
||
} else {
|
||
return match + " WHERE source_type = 'allocation'";
|
||
}
|
||
}
|
||
}
|
||
);
|
||
|
||
return content;
|
||
}
|
||
|
||
/**
|
||
* 更新 INSERT 语句
|
||
* @param {string} content - 文件内容
|
||
* @returns {string} 更新后的内容
|
||
*/
|
||
updateInsertStatements(content) {
|
||
// 更新 INSERT INTO transfers 语句,添加必要的字段
|
||
content = content.replace(
|
||
/INSERT INTO transfers\s*\(([^)]+)\)\s*VALUES\s*\(([^)]+)\)/gi,
|
||
(match, fields, values) => {
|
||
// 如果字段列表中没有 source_type,添加它
|
||
if (!fields.includes('source_type')) {
|
||
const fieldList = fields.trim() + ', source_type';
|
||
const valueList = values.trim() + ', \'allocation\'';
|
||
return `INSERT INTO transfers (${fieldList}) VALUES (${valueList})`;
|
||
}
|
||
return match;
|
||
}
|
||
);
|
||
|
||
return content;
|
||
}
|
||
|
||
/**
|
||
* 更新特定的查询逻辑
|
||
* @param {string} content - 文件内容
|
||
* @param {string} filePath - 文件路径
|
||
* @returns {string} 更新后的内容
|
||
*/
|
||
updateSpecificQueries(content, filePath) {
|
||
// 根据不同文件进行特定更新
|
||
|
||
if (filePath.includes('matchingService.js')) {
|
||
// 更新 matchingService.js 中的特定逻辑
|
||
content = this.updateMatchingServiceQueries(content);
|
||
}
|
||
|
||
if (filePath.includes('matchingAdmin.js')) {
|
||
// 更新 matchingAdmin.js 中的特定逻辑
|
||
content = this.updateMatchingAdminQueries(content);
|
||
}
|
||
|
||
return content;
|
||
}
|
||
|
||
/**
|
||
* 更新 matchingService.js 中的查询
|
||
* @param {string} content - 文件内容
|
||
* @returns {string} 更新后的内容
|
||
*/
|
||
updateMatchingServiceQueries(content) {
|
||
// 更新确认分配的逻辑
|
||
content = content.replace(
|
||
/UPDATE transfers SET status = "confirmed", transfer_id = \?, confirmed_at = NOW\(\) WHERE id = \?/g,
|
||
'UPDATE transfers SET status = "confirmed", confirmed_at = NOW() WHERE id = ? AND source_type = \'allocation\''
|
||
);
|
||
|
||
// 更新获取分配记录的查询
|
||
content = content.replace(
|
||
/SELECT \* FROM transfers WHERE id = \? AND from_user_id = \?/g,
|
||
'SELECT * FROM transfers WHERE id = ? AND from_user_id = ? AND source_type = \'allocation\''
|
||
);
|
||
|
||
return content;
|
||
}
|
||
|
||
/**
|
||
* 更新 matchingAdmin.js 中的查询
|
||
* @param {string} content - 文件内容
|
||
* @returns {string} 更新后的内容
|
||
*/
|
||
updateMatchingAdminQueries(content) {
|
||
// 更新管理员查询逻辑,确保只查询 allocation 类型的记录
|
||
content = content.replace(
|
||
/FROM transfers oa/g,
|
||
'FROM transfers oa WHERE oa.source_type = \'allocation\''
|
||
);
|
||
|
||
return content;
|
||
}
|
||
|
||
/**
|
||
* 更新注释
|
||
* @param {string} content - 文件内容
|
||
* @returns {string} 更新后的内容
|
||
*/
|
||
updateComments(content) {
|
||
content = content.replace(/order_allocations/g, 'transfers (allocation type)');
|
||
content = content.replace(/订单分配/g, '转账分配');
|
||
content = content.replace(/分配表/g, '转账表(分配类型)');
|
||
|
||
return content;
|
||
}
|
||
|
||
/**
|
||
* 执行所有文件的更新
|
||
*/
|
||
async updateAllFiles() {
|
||
console.log('开始更新代码引用...');
|
||
console.log('=' .repeat(60));
|
||
|
||
for (const filePath of this.filesToUpdate) {
|
||
try {
|
||
await this.updateFile(filePath);
|
||
} catch (error) {
|
||
console.error(`更新文件 ${filePath} 失败:`, error.message);
|
||
}
|
||
}
|
||
|
||
console.log('\n' + '=' .repeat(60));
|
||
console.log('✓ 代码更新完成!');
|
||
console.log('\n注意事项:');
|
||
console.log('1. 所有原始文件已备份为 .backup 文件');
|
||
console.log('2. 请测试更新后的代码功能是否正常');
|
||
console.log('3. 如有问题,可以使用备份文件恢复');
|
||
console.log('4. 确认无误后可删除 .backup 文件');
|
||
}
|
||
|
||
/**
|
||
* 恢复所有备份文件
|
||
*/
|
||
async restoreBackups() {
|
||
console.log('开始恢复备份文件...');
|
||
|
||
for (const filePath of this.filesToUpdate) {
|
||
const fullPath = path.join(process.cwd(), filePath);
|
||
const backupPath = fullPath + '.backup';
|
||
|
||
if (fs.existsSync(backupPath)) {
|
||
fs.copyFileSync(backupPath, fullPath);
|
||
console.log(`✓ 已恢复: ${filePath}`);
|
||
}
|
||
}
|
||
|
||
console.log('✓ 备份恢复完成!');
|
||
}
|
||
}
|
||
|
||
async function main() {
|
||
const updater = new CodeUpdater();
|
||
|
||
const args = process.argv.slice(2);
|
||
|
||
if (args.includes('--restore')) {
|
||
await updater.restoreBackups();
|
||
} else {
|
||
await updater.updateAllFiles();
|
||
}
|
||
}
|
||
|
||
// 如果直接运行此脚本
|
||
if (require.main === module) {
|
||
main().catch(console.error);
|
||
}
|
||
|
||
module.exports = CodeUpdater; |