first-update
This commit is contained in:
179
easy-dataset-main/electron/modules/db-updater.js
Normal file
179
easy-dataset-main/electron/modules/db-updater.js
Normal file
@@ -0,0 +1,179 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
|
||||
/**
|
||||
* 执行SQL命令
|
||||
* @param {string} dbUrl 数据库连接 URL
|
||||
* @param {string} sql SQL命令
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function executeSql(dbUrl, sql) {
|
||||
// 允许多条SQL语句分开执行,支持分号和空行分隔
|
||||
const statements = sql
|
||||
.split(';')
|
||||
.map(stmt => stmt.trim())
|
||||
.filter(stmt => stmt.length > 0);
|
||||
|
||||
if (statements.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置环境变量
|
||||
process.env.DATABASE_URL = dbUrl;
|
||||
|
||||
// 创建Prisma实例
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
try {
|
||||
// 执行每条SQL语句
|
||||
for (const statement of statements) {
|
||||
await prisma.$executeRawUnsafe(statement);
|
||||
}
|
||||
} finally {
|
||||
// 关闭连接
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地和应用的SQL配置文件
|
||||
* @param {string} userDataPath 用户数据目录
|
||||
* @param {string} resourcesPath 应用资源目录
|
||||
* @param {boolean} isDev 是否开发环境
|
||||
* @returns {Promise<{userSqlConfig: Array, appSqlConfig: Array}>}
|
||||
*/
|
||||
async function getSqlConfigs(userDataPath, resourcesPath, isDev, logger = console.log) {
|
||||
// 用户SQL配置文件路径
|
||||
const userSqlPath = path.join(userDataPath, 'sql.json');
|
||||
|
||||
// 应用SQL配置文件路径
|
||||
const appSqlPath = isDev
|
||||
? path.join(__dirname, '..', 'prisma', 'sql.json')
|
||||
: path.join(resourcesPath, 'prisma', 'sql.json');
|
||||
|
||||
let userSqlConfig = [];
|
||||
let appSqlConfig = [];
|
||||
|
||||
// 读取应用SQL配置
|
||||
try {
|
||||
if (fs.existsSync(appSqlPath)) {
|
||||
const appSqlContent = fs.readFileSync(appSqlPath, 'utf8');
|
||||
appSqlConfig = JSON.parse(appSqlContent);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`读取应用SQL配置文件失败: ${error.message}`);
|
||||
}
|
||||
|
||||
// 读取用户SQL配置(如果存在)
|
||||
try {
|
||||
if (fs.existsSync(userSqlPath)) {
|
||||
const userSqlContent = fs.readFileSync(userSqlPath, 'utf8');
|
||||
userSqlConfig = JSON.parse(userSqlContent);
|
||||
}
|
||||
} catch (error) {
|
||||
// 如果用户SQL配置不存在或无法解析,使用空数组
|
||||
userSqlConfig = [];
|
||||
}
|
||||
|
||||
logger(appSqlPath);
|
||||
// logger(JSON.stringify(appSqlConfig, null, 2));
|
||||
logger(userSqlPath);
|
||||
// logger(JSON.stringify(userSqlConfig, null, 2));
|
||||
|
||||
return { userSqlConfig, appSqlConfig };
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户SQL配置文件
|
||||
* @param {string} userDataPath 用户数据目录
|
||||
* @param {Array} sqlConfig 新的SQL配置
|
||||
*/
|
||||
function updateUserSqlConfig(userDataPath, sqlConfig) {
|
||||
const userSqlPath = path.join(userDataPath, 'sql.json');
|
||||
fs.writeFileSync(userSqlPath, JSON.stringify(sqlConfig, null, 4), 'utf8');
|
||||
}
|
||||
|
||||
// 不再需要版本比较功能
|
||||
|
||||
/**
|
||||
* 获取需要执行的SQL命令
|
||||
* @param {Array} userSqlConfig 用户SQL配置
|
||||
* @param {Array} appSqlConfig 应用SQL配置
|
||||
* @returns {Array} 需要执行的SQL命令
|
||||
*/
|
||||
function getSqlsToExecute(userSqlConfig, appSqlConfig) {
|
||||
// 创建用户已执行的SQL集合 (使用 version + sql 的组合作为唯一标识)
|
||||
const userExecutedSqlSet = new Set();
|
||||
userSqlConfig.forEach(item => {
|
||||
const key = `${item.version}:${item.sql}`;
|
||||
userExecutedSqlSet.add(key);
|
||||
});
|
||||
|
||||
// 过滤出用户需要执行的SQL (即应用SQL配置中存在但用户尚未执行的SQL)
|
||||
return appSqlConfig.filter(item => {
|
||||
const key = `${item.version}:${item.sql}`;
|
||||
return !userExecutedSqlSet.has(key);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据库
|
||||
* @param {string} userDataPath 用户数据目录
|
||||
* @param {string} resourcesPath 应用资源目录
|
||||
* @param {boolean} isDev 是否开发环境
|
||||
* @param {function} logger 日志函数
|
||||
*/
|
||||
async function updateDatabase(userDataPath, resourcesPath, isDev, logger = console.log) {
|
||||
const dbPath = path.join(userDataPath, 'local-db', 'db.sqlite');
|
||||
|
||||
try {
|
||||
// 获取SQL配置
|
||||
const { userSqlConfig, appSqlConfig } = await getSqlConfigs(userDataPath, resourcesPath, isDev, logger);
|
||||
|
||||
// 获取需要执行的SQL
|
||||
const sqlsToExecute = getSqlsToExecute(userSqlConfig, appSqlConfig);
|
||||
|
||||
if (sqlsToExecute.length === 0) {
|
||||
logger('数据库已是最新版本,无需更新');
|
||||
return { updated: false, message: '数据库已是最新版本' };
|
||||
}
|
||||
|
||||
// 设置数据库URL
|
||||
const dbUrl = `file:${dbPath}`;
|
||||
|
||||
// 执行SQL更新
|
||||
logger(`发现 ${sqlsToExecute.length} 个数据库更新,开始执行...`);
|
||||
for (const item of sqlsToExecute) {
|
||||
try {
|
||||
logger(`执行版本 ${item.version} 的SQL更新: ${item.sql.substring(0, 100)}...`);
|
||||
await executeSql(dbUrl, item.sql);
|
||||
// 添加到用户SQL配置
|
||||
userSqlConfig.push(item);
|
||||
} catch (error) {
|
||||
logger(`执行版本 ${item.version} 的SQL更新失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户SQL配置文件
|
||||
updateUserSqlConfig(userDataPath, userSqlConfig);
|
||||
|
||||
logger('数据库更新完成');
|
||||
return {
|
||||
updated: true,
|
||||
message: `成功执行了 ${sqlsToExecute.length} 个数据库更新`,
|
||||
executedVersions: sqlsToExecute.map(item => item.version)
|
||||
};
|
||||
} catch (error) {
|
||||
logger(`数据库更新失败: ${error.message}`);
|
||||
return { updated: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
updateDatabase,
|
||||
executeSql,
|
||||
getSqlConfigs,
|
||||
updateUserSqlConfig,
|
||||
getSqlsToExecute
|
||||
};
|
||||
Reference in New Issue
Block a user