Initial commit: 宁夏智慧养殖监管平台
This commit is contained in:
282
backend/scripts/seed-manager.js
Normal file
282
backend/scripts/seed-manager.js
Normal file
@@ -0,0 +1,282 @@
|
||||
/**
|
||||
* 数据库种子数据管理器
|
||||
* @file seed-manager.js
|
||||
* @description 管理数据库种子数据,用于初始化和测试
|
||||
*/
|
||||
require('dotenv').config();
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { sequelize } = require('../config/database-simple');
|
||||
const { QueryTypes } = require('sequelize');
|
||||
|
||||
// 种子文件目录
|
||||
const SEEDS_DIR = path.join(__dirname, '../seeds');
|
||||
|
||||
// 确保种子目录存在
|
||||
if (!fs.existsSync(SEEDS_DIR)) {
|
||||
fs.mkdirSync(SEEDS_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
// 创建种子记录表(如果不存在)
|
||||
async function createSeedTable() {
|
||||
await sequelize.query(`
|
||||
CREATE TABLE IF NOT EXISTS seeds (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`);
|
||||
}
|
||||
|
||||
// 获取已应用的种子
|
||||
async function getAppliedSeeds() {
|
||||
await createSeedTable();
|
||||
|
||||
const seeds = await sequelize.query(
|
||||
'SELECT name FROM seeds ORDER BY id ASC',
|
||||
{ type: QueryTypes.SELECT }
|
||||
);
|
||||
|
||||
return seeds.map(seed => seed.name);
|
||||
}
|
||||
|
||||
// 获取所有种子文件
|
||||
function getAllSeeds() {
|
||||
return fs.readdirSync(SEEDS_DIR)
|
||||
.filter(file => file.endsWith('.js'))
|
||||
.sort(); // 按文件名排序
|
||||
}
|
||||
|
||||
// 应用种子数据
|
||||
async function applySeed(seedName) {
|
||||
const seed = require(path.join(SEEDS_DIR, seedName));
|
||||
|
||||
console.log(`正在应用种子数据: ${seedName}`);
|
||||
|
||||
// 开始事务
|
||||
const transaction = await sequelize.transaction();
|
||||
|
||||
try {
|
||||
// 执行种子的 up 方法
|
||||
await seed.up(sequelize.getQueryInterface(), sequelize);
|
||||
|
||||
// 记录种子已应用
|
||||
await sequelize.query(
|
||||
'INSERT INTO seeds (name) VALUES (:name)',
|
||||
{
|
||||
replacements: { name: seedName },
|
||||
transaction
|
||||
}
|
||||
);
|
||||
|
||||
// 提交事务
|
||||
await transaction.commit();
|
||||
console.log(`种子数据应用成功: ${seedName}`);
|
||||
} catch (error) {
|
||||
// 回滚事务
|
||||
await transaction.rollback();
|
||||
console.error(`种子数据应用失败: ${seedName}`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 回滚种子数据
|
||||
async function revertSeed(seedName) {
|
||||
const seed = require(path.join(SEEDS_DIR, seedName));
|
||||
|
||||
console.log(`正在回滚种子数据: ${seedName}`);
|
||||
|
||||
// 开始事务
|
||||
const transaction = await sequelize.transaction();
|
||||
|
||||
try {
|
||||
// 执行种子的 down 方法
|
||||
await seed.down(sequelize.getQueryInterface(), sequelize);
|
||||
|
||||
// 删除种子记录
|
||||
await sequelize.query(
|
||||
'DELETE FROM seeds WHERE name = :name',
|
||||
{
|
||||
replacements: { name: seedName },
|
||||
transaction
|
||||
}
|
||||
);
|
||||
|
||||
// 提交事务
|
||||
await transaction.commit();
|
||||
console.log(`种子数据回滚成功: ${seedName}`);
|
||||
} catch (error) {
|
||||
// 回滚事务
|
||||
await transaction.rollback();
|
||||
console.error(`种子数据回滚失败: ${seedName}`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 运行所有种子数据
|
||||
async function runAllSeeds() {
|
||||
const appliedSeeds = await getAppliedSeeds();
|
||||
const allSeeds = getAllSeeds();
|
||||
|
||||
// 找出未应用的种子
|
||||
const pendingSeeds = allSeeds.filter(
|
||||
seed => !appliedSeeds.includes(seed)
|
||||
);
|
||||
|
||||
if (pendingSeeds.length === 0) {
|
||||
console.log('没有待处理的种子数据');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`发现 ${pendingSeeds.length} 个待处理的种子数据`);
|
||||
|
||||
// 按顺序应用每个待处理的种子
|
||||
for (const seed of pendingSeeds) {
|
||||
await applySeed(seed);
|
||||
}
|
||||
|
||||
console.log('所有待处理的种子数据已应用');
|
||||
}
|
||||
|
||||
// 回滚所有种子数据
|
||||
async function revertAllSeeds() {
|
||||
const appliedSeeds = await getAppliedSeeds();
|
||||
|
||||
if (appliedSeeds.length === 0) {
|
||||
console.log('没有可回滚的种子数据');
|
||||
return;
|
||||
}
|
||||
|
||||
// 从最新的种子开始,回滚所有种子
|
||||
const seedsToRevert = [...appliedSeeds].reverse();
|
||||
|
||||
for (const seed of seedsToRevert) {
|
||||
await revertSeed(seed);
|
||||
}
|
||||
|
||||
console.log('所有种子数据已回滚');
|
||||
}
|
||||
|
||||
// 创建新的种子文件
|
||||
function createSeed(name) {
|
||||
const timestamp = new Date().toISOString().replace(/[-:]/g, '').replace('T', '').split('.')[0];
|
||||
const fileName = `${timestamp}_${name}.js`;
|
||||
const filePath = path.join(SEEDS_DIR, fileName);
|
||||
|
||||
const template = `/**
|
||||
* 种子数据: ${name}
|
||||
* 创建时间: ${new Date().toISOString()}
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: async (queryInterface, Sequelize) => {
|
||||
// 在此处添加种子数据
|
||||
// 例如:
|
||||
// await queryInterface.bulkInsert('users', [
|
||||
// {
|
||||
// username: 'admin',
|
||||
// email: 'admin@example.com',
|
||||
// password: '$2b$10$rVHMOB./a2mFmE4EEdI3QO4f./bN3LYb.dpDvtX9gRUM9gNwspj1a', // 123456
|
||||
// created_at: new Date(),
|
||||
// updated_at: new Date()
|
||||
// },
|
||||
// {
|
||||
// username: 'user',
|
||||
// email: 'user@example.com',
|
||||
// password: '$2b$10$rVHMOB./a2mFmE4EEdI3QO4f./bN3LYb.dpDvtX9gRUM9gNwspj1a', // 123456
|
||||
// created_at: new Date(),
|
||||
// updated_at: new Date()
|
||||
// }
|
||||
// ]);
|
||||
},
|
||||
|
||||
down: async (queryInterface, Sequelize) => {
|
||||
// 在此处添加回滚代码
|
||||
// 例如:
|
||||
// await queryInterface.bulkDelete('users', null, {});
|
||||
}
|
||||
};
|
||||
`;
|
||||
|
||||
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);
|
||||
}
|
||||
createSeed(args[1]);
|
||||
break;
|
||||
|
||||
case 'run':
|
||||
await runAllSeeds();
|
||||
break;
|
||||
|
||||
case 'revert':
|
||||
await revertAllSeeds();
|
||||
break;
|
||||
|
||||
case 'status':
|
||||
const applied = await getAppliedSeeds();
|
||||
const all = getAllSeeds();
|
||||
|
||||
console.log('已应用的种子数据:');
|
||||
applied.forEach(s => console.log(` - ${s}`));
|
||||
|
||||
console.log('\n待处理的种子数据:');
|
||||
all.filter(s => !applied.includes(s))
|
||||
.forEach(s => console.log(` - ${s}`));
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(`
|
||||
数据库种子数据管理器
|
||||
|
||||
用法:
|
||||
node seed-manager.js <命令> [参数]
|
||||
|
||||
命令:
|
||||
create <name> 创建新的种子文件
|
||||
run 应用所有待处理的种子数据
|
||||
revert 回滚所有种子数据
|
||||
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 = {
|
||||
createSeedTable,
|
||||
getAppliedSeeds,
|
||||
getAllSeeds,
|
||||
applySeed,
|
||||
revertSeed,
|
||||
runAllSeeds,
|
||||
revertAllSeeds,
|
||||
createSeed
|
||||
};
|
||||
Reference in New Issue
Block a user