Initial commit: 宁夏智慧养殖监管平台

This commit is contained in:
shenquanyi
2025-08-25 15:00:46 +08:00
commit ec72c6a8b5
177 changed files with 37263 additions and 0 deletions

View File

@@ -0,0 +1,315 @@
/**
* 数据库迁移管理器
* @file migration-manager.js
* @description 管理数据库迁移,支持版本控制和回滚
*/
const fs = require('fs');
const path = require('path');
const { sequelize } = require('../config/database-simple');
const { QueryTypes } = require('sequelize');
// 迁移文件目录
const MIGRATIONS_DIR = path.join(__dirname, '../migrations');
// 确保迁移目录存在
if (!fs.existsSync(MIGRATIONS_DIR)) {
fs.mkdirSync(MIGRATIONS_DIR, { recursive: true });
}
// 创建迁移表(如果不存在)
async function createMigrationTable() {
await sequelize.query(`
CREATE TABLE IF NOT EXISTS migrations (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
`);
}
// 获取已应用的迁移
async function getAppliedMigrations() {
await createMigrationTable();
const migrations = await sequelize.query(
'SELECT name FROM migrations ORDER BY id ASC',
{ type: QueryTypes.SELECT }
);
return migrations.map(migration => migration.name);
}
// 获取所有迁移文件
function getAllMigrations() {
return fs.readdirSync(MIGRATIONS_DIR)
.filter(file => file.endsWith('.js'))
.sort(); // 按文件名排序,通常是时间戳前缀
}
// 应用迁移
async function applyMigration(migrationName) {
const migration = require(path.join(MIGRATIONS_DIR, migrationName));
console.log(`正在应用迁移: ${migrationName}`);
// 开始事务
const transaction = await sequelize.transaction();
try {
// 执行迁移的 up 方法
await migration.up(sequelize.getQueryInterface(), sequelize);
// 记录迁移已应用
await sequelize.query(
'INSERT INTO migrations (name) VALUES (:name)',
{
replacements: { name: migrationName },
transaction
}
);
// 提交事务
await transaction.commit();
console.log(`迁移应用成功: ${migrationName}`);
} catch (error) {
// 回滚事务
await transaction.rollback();
console.error(`迁移应用失败: ${migrationName}`, error);
throw error;
}
}
// 回滚迁移
async function revertMigration(migrationName) {
const migration = require(path.join(MIGRATIONS_DIR, migrationName));
console.log(`正在回滚迁移: ${migrationName}`);
// 开始事务
const transaction = await sequelize.transaction();
try {
// 执行迁移的 down 方法
await migration.down(sequelize.getQueryInterface(), sequelize);
// 删除迁移记录
await sequelize.query(
'DELETE FROM migrations WHERE name = :name',
{
replacements: { name: migrationName },
transaction
}
);
// 提交事务
await transaction.commit();
console.log(`迁移回滚成功: ${migrationName}`);
} catch (error) {
// 回滚事务
await transaction.rollback();
console.error(`迁移回滚失败: ${migrationName}`, error);
throw error;
}
}
// 运行待处理的迁移
async function runPendingMigrations() {
const appliedMigrations = await getAppliedMigrations();
const allMigrations = getAllMigrations();
// 找出未应用的迁移
const pendingMigrations = allMigrations.filter(
migration => !appliedMigrations.includes(migration)
);
if (pendingMigrations.length === 0) {
console.log('没有待处理的迁移');
return;
}
console.log(`发现 ${pendingMigrations.length} 个待处理的迁移`);
// 按顺序应用每个待处理的迁移
for (const migration of pendingMigrations) {
await applyMigration(migration);
}
console.log('所有待处理的迁移已应用');
}
// 回滚最近的迁移
async function rollbackLastMigration() {
const appliedMigrations = await getAppliedMigrations();
if (appliedMigrations.length === 0) {
console.log('没有可回滚的迁移');
return;
}
const lastMigration = appliedMigrations[appliedMigrations.length - 1];
await revertMigration(lastMigration);
}
// 回滚到特定迁移
async function rollbackToMigration(targetMigration) {
const appliedMigrations = await getAppliedMigrations();
if (appliedMigrations.length === 0) {
console.log('没有可回滚的迁移');
return;
}
const targetIndex = appliedMigrations.indexOf(targetMigration);
if (targetIndex === -1) {
console.error(`目标迁移 ${targetMigration} 未找到或未应用`);
return;
}
// 从最新的迁移开始,回滚到目标迁移之后的所有迁移
const migrationsToRollback = appliedMigrations.slice(targetIndex + 1).reverse();
for (const migration of migrationsToRollback) {
await revertMigration(migration);
}
console.log(`已回滚到迁移: ${targetMigration}`);
}
// 创建新的迁移文件
function createMigration(name) {
const timestamp = new Date().toISOString().replace(/[-:]/g, '').replace('T', '').split('.')[0];
const fileName = `${timestamp}_${name}.js`;
const filePath = path.join(MIGRATIONS_DIR, fileName);
const template = `/**
* 迁移: ${name}
* 创建时间: ${new Date().toISOString()}
*/
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
// 在此处添加迁移代码(创建表、添加列等)
// 例如:
// await queryInterface.createTable('users', {
// id: {
// type: Sequelize.INTEGER,
// primaryKey: true,
// autoIncrement: true
// },
// name: Sequelize.STRING,
// createdAt: {
// type: Sequelize.DATE,
// defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
// field: 'created_at'
// },
// updatedAt: {
// type: Sequelize.DATE,
// defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'),
// field: 'updated_at'
// }
// });
},
down: async (queryInterface, Sequelize) => {
// 在此处添加回滚代码(删除表、删除列等)
// 例如:
// await queryInterface.dropTable('users');
}
};
`;
fs.writeFileSync(filePath, template);
console.log(`已创建迁移文件: ${fileName}`);
return fileName;
}
// 命令行接口
async function main() {
const args = process.argv.slice(2);
const command = args[0];
try {
switch (command) {
case 'create':
if (!args[1]) {
console.error('请提供迁移名称');
process.exit(1);
}
createMigration(args[1]);
break;
case 'up':
case 'migrate':
await runPendingMigrations();
break;
case 'down':
case 'rollback':
await rollbackLastMigration();
break;
case 'to':
if (!args[1]) {
console.error('请提供目标迁移名称');
process.exit(1);
}
await rollbackToMigration(args[1]);
break;
case 'status':
const applied = await getAppliedMigrations();
const all = getAllMigrations();
console.log('已应用的迁移:');
applied.forEach(m => console.log(` - ${m}`));
console.log('\n待处理的迁移:');
all.filter(m => !applied.includes(m))
.forEach(m => console.log(` - ${m}`));
break;
default:
console.log(`
数据库迁移管理器
用法:
node migration-manager.js <命令> [参数]
命令:
create <name> 创建新的迁移文件
up, migrate 应用所有待处理的迁移
down, rollback 回滚最近的一次迁移
to <migration> 回滚到指定的迁移(不包括该迁移)
status 显示迁移状态
`);
}
} catch (error) {
console.error('迁移操作失败:', error);
process.exit(1);
} finally {
// 关闭数据库连接
await sequelize.close();
}
}
// 如果直接运行此脚本则执行main函数
if (require.main === module) {
main().catch(err => {
console.error('未处理的错误:', err);
process.exit(1);
});
}
module.exports = {
createMigrationTable,
getAppliedMigrations,
getAllMigrations,
applyMigration,
revertMigration,
runPendingMigrations,
rollbackLastMigration,
rollbackToMigration,
createMigration
};