初次提交
This commit is contained in:
56
scripts/README_MERGE_TABLES.md
Normal file
56
scripts/README_MERGE_TABLES.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 表合并说明文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档说明如何使用 `merge_tables.js` 脚本将 `order_allocations` 表数据合并到 `transfers` 表中,以实现数据库结构优化。
|
||||
|
||||
## 背景
|
||||
|
||||
原系统中,`order_allocations` 表和 `transfers` 表存在功能重叠,为了简化数据库结构和提高查询效率,我们决定将 `order_allocations` 表的数据合并到 `transfers` 表中,并通过 `source_type` 字段区分不同来源的转账记录。
|
||||
|
||||
## 合并策略
|
||||
|
||||
1. 为 `transfers` 表添加必要的字段,包括 `source_type`、`matching_order_id`、`cycle_number` 等
|
||||
2. 将 `order_allocations` 表中的数据迁移到 `transfers` 表
|
||||
3. 更新相关的外键引用
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 前置条件
|
||||
|
||||
1. 确保已对数据库进行备份
|
||||
2. 确保系统处于维护状态,没有用户正在使用
|
||||
|
||||
### 执行步骤
|
||||
|
||||
1. 进入项目根目录
|
||||
2. 执行以下命令运行合并脚本:
|
||||
|
||||
```bash
|
||||
node scripts/merge_tables.js
|
||||
```
|
||||
|
||||
3. 脚本执行完成后,检查控制台输出,确认迁移是否成功
|
||||
|
||||
### 验证步骤
|
||||
|
||||
1. 检查 `transfers` 表中是否包含所有 `order_allocations` 表的数据
|
||||
2. 验证系统功能是否正常,特别是与匹配订单相关的功能
|
||||
3. 确认无误后,可以考虑删除 `order_allocations` 表(可选)
|
||||
|
||||
## 回滚方案
|
||||
|
||||
如果合并过程中出现问题,或者合并后系统功能异常,可以通过以下步骤回滚:
|
||||
|
||||
1. 使用之前的数据库备份恢复数据
|
||||
2. 如果没有备份,可以手动将 `transfers` 表中 `source_type='allocation'` 的记录删除,并重新运行原有的系统
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 合并过程会自动处理已有关联的记录,避免重复迁移
|
||||
2. 合并脚本使用事务进行操作,确保数据一致性
|
||||
3. 建议在测试环境验证成功后再在生产环境执行
|
||||
|
||||
## 技术支持
|
||||
|
||||
如有问题,请联系技术支持团队。
|
||||
154
scripts/fix_sql_syntax.js
Normal file
154
scripts/fix_sql_syntax.js
Normal file
@@ -0,0 +1,154 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* SQL 语法修复脚本:修复自动替换产生的 SQL 语法错误
|
||||
*/
|
||||
|
||||
class SQLSyntaxFixer {
|
||||
constructor() {
|
||||
this.filesToFix = [
|
||||
'services/matchingService.js',
|
||||
'routes/matchingAdmin.js',
|
||||
'routes/transfers.js',
|
||||
'routes/matching.js'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 修复单个文件中的 SQL 语法错误
|
||||
* @param {string} filePath - 文件路径
|
||||
*/
|
||||
async fixFile(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. 修复 WHERE source_type = 'allocation' FROM transfers 的错误顺序
|
||||
content = content.replace(
|
||||
/WHERE source_type = 'allocation' FROM transfers/g,
|
||||
"FROM transfers WHERE source_type = 'allocation'"
|
||||
);
|
||||
|
||||
// 2. 修复多个 WHERE 子句的问题
|
||||
content = content.replace(
|
||||
/FROM transfers WHERE source_type = 'allocation'([\s\S]*?)WHERE/g,
|
||||
"FROM transfers WHERE source_type = 'allocation'$1AND"
|
||||
);
|
||||
|
||||
// 3. 修复 INSERT 语句中的引号问题
|
||||
content = content.replace(
|
||||
/'allocation'/g,
|
||||
"'allocation'"
|
||||
);
|
||||
|
||||
// 4. 修复 JOIN 语句中的表别名问题
|
||||
content = content.replace(
|
||||
/FROM transfers oa WHERE oa\.source_type = 'allocation'/g,
|
||||
"FROM transfers oa WHERE oa.source_type = 'allocation'"
|
||||
);
|
||||
|
||||
// 5. 修复复杂查询中的语法问题
|
||||
content = this.fixComplexQueries(content, filePath);
|
||||
|
||||
if (content !== originalContent) {
|
||||
fs.writeFileSync(fullPath, content);
|
||||
console.log(`✓ 已修复: ${filePath}`);
|
||||
} else {
|
||||
console.log(`- 无需修复: ${filePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修复复杂查询
|
||||
* @param {string} content - 文件内容
|
||||
* @param {string} filePath - 文件路径
|
||||
* @returns {string} 修复后的内容
|
||||
*/
|
||||
fixComplexQueries(content, filePath) {
|
||||
if (filePath.includes('matchingService.js')) {
|
||||
// 修复 matchingService.js 中的特定查询
|
||||
|
||||
// 修复获取匹配目标的查询
|
||||
content = content.replace(
|
||||
/FROM transfers oa\s+WHERE oa\.source_type = 'allocation'\s+JOIN users u ON oa\.from_user_id = u\.id/g,
|
||||
"FROM transfers oa JOIN users u ON oa.from_user_id = u.id WHERE oa.source_type = 'allocation'"
|
||||
);
|
||||
|
||||
// 修复获取用户待处理分配的查询
|
||||
content = content.replace(
|
||||
/SELECT \* FROM transfers WHERE source_type = 'allocation' WHERE matching_order_id = \? ORDER BY cycle_number, created_at/g,
|
||||
"SELECT * FROM transfers WHERE source_type = 'allocation' AND matching_order_id = ? ORDER BY cycle_number, created_at"
|
||||
);
|
||||
|
||||
// 修复检查周期完成的查询
|
||||
content = content.replace(
|
||||
/SELECT COUNT\(\*\) as count FROM transfers WHERE source_type = 'allocation' WHERE matching_order_id = \? AND cycle_number = \? AND status = "pending"/g,
|
||||
"SELECT COUNT(*) as count FROM transfers WHERE source_type = 'allocation' AND matching_order_id = ? AND cycle_number = ? AND status = 'pending'"
|
||||
);
|
||||
}
|
||||
|
||||
if (filePath.includes('matchingAdmin.js')) {
|
||||
// 修复 matchingAdmin.js 中的查询
|
||||
content = content.replace(
|
||||
/FROM transfers oa WHERE oa\.source_type = 'allocation'\s+JOIN/g,
|
||||
"FROM transfers oa JOIN"
|
||||
);
|
||||
|
||||
// 在 JOIN 后添加 WHERE 条件
|
||||
content = content.replace(
|
||||
/(FROM transfers oa JOIN[\s\S]*?)WHERE(?!.*source_type)/g,
|
||||
"$1WHERE oa.source_type = 'allocation' AND"
|
||||
);
|
||||
}
|
||||
|
||||
if (filePath.includes('matching.js')) {
|
||||
// 修复 matching.js 中的查询
|
||||
content = content.replace(
|
||||
/LEFT JOIN transfers oa ON mo\.id = oa\.matching_order_id WHERE oa\.source_type = 'allocation'/g,
|
||||
"LEFT JOIN transfers oa ON mo.id = oa.matching_order_id AND oa.source_type = 'allocation'"
|
||||
);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行所有文件的修复
|
||||
*/
|
||||
async fixAllFiles() {
|
||||
console.log('开始修复 SQL 语法错误...');
|
||||
console.log('=' .repeat(60));
|
||||
|
||||
for (const filePath of this.filesToFix) {
|
||||
try {
|
||||
await this.fixFile(filePath);
|
||||
} catch (error) {
|
||||
console.error(`修复文件 ${filePath} 失败:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n' + '=' .repeat(60));
|
||||
console.log('✓ SQL 语法修复完成!');
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const fixer = new SQLSyntaxFixer();
|
||||
await fixer.fixAllFiles();
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (require.main === module) {
|
||||
main().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = SQLSyntaxFixer;
|
||||
133
scripts/fix_table_aliases.js
Normal file
133
scripts/fix_table_aliases.js
Normal file
@@ -0,0 +1,133 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* 表别名修复脚本:修复 SQL 查询中的表别名问题
|
||||
*/
|
||||
|
||||
class TableAliasFixer {
|
||||
constructor() {
|
||||
this.filesToFix = [
|
||||
'services/matchingService.js',
|
||||
'routes/matchingAdmin.js',
|
||||
'routes/transfers.js',
|
||||
'routes/matching.js'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 修复单个文件中的表别名问题
|
||||
* @param {string} filePath - 文件路径
|
||||
*/
|
||||
async fixFile(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. 修复 "FROM transfers WHERE source_type = 'allocation' oa" 的问题
|
||||
content = content.replace(
|
||||
/FROM transfers WHERE source_type = 'allocation' (\w+)/g,
|
||||
"FROM transfers $1 WHERE $1.source_type = 'allocation'"
|
||||
);
|
||||
|
||||
// 2. 修复重复的 source_type 条件
|
||||
content = content.replace(
|
||||
/FROM transfers WHERE source_type = 'allocation' (\w+) AND \1\.source_type = 'allocation'/g,
|
||||
"FROM transfers $1 WHERE $1.source_type = 'allocation'"
|
||||
);
|
||||
|
||||
// 3. 修复 "FROM transfers WHERE source_type = 'allocation'" 后面直接跟其他子句的情况
|
||||
content = content.replace(
|
||||
/FROM transfers WHERE source_type = 'allocation'\s+(JOIN|ORDER|GROUP|LIMIT)/g,
|
||||
"FROM transfers WHERE source_type = 'allocation' $1"
|
||||
);
|
||||
|
||||
// 4. 修复子查询中的问题
|
||||
content = content.replace(
|
||||
/\(SELECT[^)]*FROM transfers WHERE source_type = 'allocation' (\w+)/g,
|
||||
(match, alias) => {
|
||||
return match.replace(
|
||||
`FROM transfers WHERE source_type = 'allocation' ${alias}`,
|
||||
`FROM transfers ${alias} WHERE ${alias}.source_type = 'allocation'`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// 5. 修复特定的查询模式
|
||||
content = this.fixSpecificPatterns(content, filePath);
|
||||
|
||||
if (content !== originalContent) {
|
||||
fs.writeFileSync(fullPath, content);
|
||||
console.log(`✓ 已修复: ${filePath}`);
|
||||
} else {
|
||||
console.log(`- 无需修复: ${filePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修复特定的查询模式
|
||||
* @param {string} content - 文件内容
|
||||
* @param {string} filePath - 文件路径
|
||||
* @returns {string} 修复后的内容
|
||||
*/
|
||||
fixSpecificPatterns(content, filePath) {
|
||||
// 修复 SELECT 语句中的表别名问题
|
||||
content = content.replace(
|
||||
/SELECT ([^F]*?) FROM transfers WHERE source_type = 'allocation' (\w+)/g,
|
||||
"SELECT $1 FROM transfers $2 WHERE $2.source_type = 'allocation'"
|
||||
);
|
||||
|
||||
// 修复 UPDATE 语句
|
||||
content = content.replace(
|
||||
/UPDATE transfers WHERE source_type = 'allocation' SET/g,
|
||||
"UPDATE transfers SET"
|
||||
);
|
||||
|
||||
// 修复 WHERE 子句中的条件
|
||||
content = content.replace(
|
||||
/WHERE source_type = 'allocation' AND (\w+)\./g,
|
||||
"WHERE $1.source_type = 'allocation' AND $1."
|
||||
);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行所有文件的修复
|
||||
*/
|
||||
async fixAllFiles() {
|
||||
console.log('开始修复表别名问题...');
|
||||
console.log('=' .repeat(60));
|
||||
|
||||
for (const filePath of this.filesToFix) {
|
||||
try {
|
||||
await this.fixFile(filePath);
|
||||
} catch (error) {
|
||||
console.error(`修复文件 ${filePath} 失败:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n' + '=' .repeat(60));
|
||||
console.log('✓ 表别名修复完成!');
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const fixer = new TableAliasFixer();
|
||||
await fixer.fixAllFiles();
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (require.main === module) {
|
||||
main().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = TableAliasFixer;
|
||||
273
scripts/update_code_references.js
Normal file
273
scripts/update_code_references.js
Normal file
@@ -0,0 +1,273 @@
|
||||
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;
|
||||
115
scripts/verify_merge.js
Normal file
115
scripts/verify_merge.js
Normal file
@@ -0,0 +1,115 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const { dbConfig } = require('../config/config');
|
||||
|
||||
/**
|
||||
* 验证表合并结果的脚本
|
||||
* 检查 order_allocations 表和 transfers 表的数据一致性
|
||||
*/
|
||||
async function verifyMerge() {
|
||||
console.log('开始验证表合并结果...');
|
||||
console.log('=' .repeat(60));
|
||||
|
||||
let connection;
|
||||
|
||||
try {
|
||||
// 创建数据库连接
|
||||
connection = await mysql.createConnection({
|
||||
host: dbConfig.host,
|
||||
user: dbConfig.user,
|
||||
password: dbConfig.password,
|
||||
database: dbConfig.database
|
||||
});
|
||||
|
||||
// 1. 检查 order_allocations 表中有多少条记录
|
||||
const [allocationCount] = await connection.execute(
|
||||
'SELECT COUNT(*) as count FROM order_allocations'
|
||||
);
|
||||
console.log(`order_allocations 表总记录数: ${allocationCount[0].count}`);
|
||||
|
||||
// 2. 检查 transfers 表中有多少条 allocation 类型的记录
|
||||
const [transferCount] = await connection.execute(
|
||||
'SELECT COUNT(*) as count FROM transfers WHERE source_type = \'allocation\''
|
||||
);
|
||||
console.log(`transfers 表中 allocation 类型记录数: ${transferCount[0].count}`);
|
||||
|
||||
// 3. 检查 order_allocations 表中有多少条记录没有关联的 transfer_id
|
||||
const [unlinkedCount] = await connection.execute(
|
||||
'SELECT COUNT(*) as count FROM order_allocations WHERE transfer_id IS NULL'
|
||||
);
|
||||
console.log(`order_allocations 表中无关联 transfer_id 的记录数: ${unlinkedCount[0].count}`);
|
||||
|
||||
// 4. 检查数据一致性 - 抽样检查
|
||||
console.log('\n数据一致性检查(抽样):');
|
||||
const [sampleAllocations] = await connection.execute(
|
||||
'SELECT * FROM order_allocations WHERE transfer_id IS NOT NULL LIMIT 5'
|
||||
);
|
||||
|
||||
for (const allocation of sampleAllocations) {
|
||||
const [transfer] = await connection.execute(
|
||||
'SELECT * FROM transfers WHERE id = ?',
|
||||
[allocation.transfer_id]
|
||||
);
|
||||
|
||||
if (transfer.length === 0) {
|
||||
console.log(` ✗ 错误: allocation_id=${allocation.id} 关联的 transfer_id=${allocation.transfer_id} 不存在`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const transferRecord = transfer[0];
|
||||
const isConsistent =
|
||||
transferRecord.from_user_id == allocation.from_user_id &&
|
||||
transferRecord.to_user_id == allocation.to_user_id &&
|
||||
transferRecord.amount == allocation.amount &&
|
||||
transferRecord.matching_order_id == allocation.matching_order_id &&
|
||||
transferRecord.cycle_number == allocation.cycle_number;
|
||||
|
||||
if (isConsistent) {
|
||||
console.log(` ✓ allocation_id=${allocation.id} 与 transfer_id=${allocation.transfer_id} 数据一致`);
|
||||
} else {
|
||||
console.log(` ✗ 错误: allocation_id=${allocation.id} 与 transfer_id=${allocation.transfer_id} 数据不一致`);
|
||||
console.log(' allocation:', {
|
||||
from_user_id: allocation.from_user_id,
|
||||
to_user_id: allocation.to_user_id,
|
||||
amount: allocation.amount,
|
||||
matching_order_id: allocation.matching_order_id,
|
||||
cycle_number: allocation.cycle_number
|
||||
});
|
||||
console.log(' transfer:', {
|
||||
from_user_id: transferRecord.from_user_id,
|
||||
to_user_id: transferRecord.to_user_id,
|
||||
amount: transferRecord.amount,
|
||||
matching_order_id: transferRecord.matching_order_id,
|
||||
cycle_number: transferRecord.cycle_number
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n' + '=' .repeat(60));
|
||||
|
||||
// 总结
|
||||
if (allocationCount[0].count === transferCount[0].count && unlinkedCount[0].count === 0) {
|
||||
console.log('✓ 验证成功! 所有 order_allocations 记录都已正确迁移到 transfers 表');
|
||||
} else {
|
||||
console.log('⚠ 验证结果: 可能存在未完全迁移的数据');
|
||||
console.log(` - order_allocations 总数: ${allocationCount[0].count}`);
|
||||
console.log(` - transfers 中 allocation 类型数: ${transferCount[0].count}`);
|
||||
console.log(` - 未关联记录数: ${unlinkedCount[0].count}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('验证失败:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
// 关闭数据库连接
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (require.main === module) {
|
||||
verifyMerge().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = verifyMerge;
|
||||
Reference in New Issue
Block a user