quicklite
Version:
A lightweight ORM toolkit for SQLite in Node.js applications
210 lines • 9.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MigrationUtil = void 0;
/**
* 数据库迁移工具
*/
class MigrationUtil {
/**
* 检查模型与数据库表的差异
* @param db 数据库实例
* @param entityClass 实体类
* @returns 表结构差异信息
*/
static async checkTableDiff(db, entityClass) {
const tableInfo = entityClass.getTableInfo();
const tableName = tableInfo.name;
// 检查表是否存在
const tableExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`).get(tableName);
if (!tableExists) {
return {
addedColumns: tableInfo.columns.map(c => c.name),
alteredColumns: [],
removedColumns: [],
needsRebuild: true
};
}
// 获取表的列信息
const tableColumns = db.prepare(`PRAGMA table_info(${tableName})`).all();
// 模型定义的列集合
const modelColumnNames = new Set(tableInfo.columns.map(c => c.name));
// 数据库中的列集合
const dbColumnNames = new Set(tableColumns.map(c => c.name));
// 找出需要添加的列
const addedColumns = [...modelColumnNames].filter(name => !dbColumnNames.has(name));
// 找出需要删除的列
const removedColumns = [...dbColumnNames].filter(name => !modelColumnNames.has(name));
// 找出需要修改的列(类型、约束等变更)
const alteredColumns = [];
tableInfo.columns.forEach(modelCol => {
if (dbColumnNames.has(modelCol.name)) {
const dbCol = tableColumns.find(c => c.name === modelCol.name);
if (dbCol) {
// 检查类型是否匹配(SQLite类型系统宽松,仅检查基本类型)
const modelType = modelCol.type.toUpperCase();
const dbType = dbCol.type.toUpperCase();
// 检查约束是否匹配
const modelNotNull = modelCol.notNull === true;
const dbNotNull = dbCol.notnull === 1;
const modelPK = modelCol.primaryKey === true;
const dbPK = dbCol.pk === 1;
// 如果类型或主要约束不匹配,需要修改列
if (modelType !== dbType || modelNotNull !== dbNotNull || modelPK !== dbPK) {
alteredColumns.push(modelCol.name);
}
}
}
});
// 判断是否需要重建表
// SQLite不支持删除列或修改列的主键约束,需要重建表
const needsRebuild = removedColumns.length > 0 ||
alteredColumns.some(col => {
const modelCol = tableInfo.columns.find(c => c.name === col);
return modelCol === null || modelCol === void 0 ? void 0 : modelCol.primaryKey;
});
return {
addedColumns,
alteredColumns,
removedColumns,
needsRebuild
};
}
/**
* 执行表迁移
* @param db 数据库实例
* @param entityClass 实体类
* @param preserveData 是否保留数据
* @returns 是否成功迁移
*/
static migrateTable(db, entityClass, preserveData = true) {
const tableInfo = entityClass.getTableInfo();
const tableName = tableInfo.name;
try {
// 检查表是否存在
const tableExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`).get(tableName);
if (!tableExists) {
// 表不存在,直接创建
db.exec(entityClass.getCreateTableSQL());
return true;
}
// 获取当前表的列信息
const tableColumns = db.prepare(`PRAGMA table_info(${tableName})`).all();
// 开始事务
db.exec('BEGIN TRANSACTION');
try {
// 检查是否需要添加新列
for (const col of tableInfo.columns) {
const columnExists = tableColumns.some(c => c.name === col.name);
if (!columnExists) {
// SQLite支持添加列
let alterSql = `ALTER TABLE ${tableName} ADD COLUMN ${col.name} ${col.type}`;
// 添加约束
if (col.notNull && col.default !== undefined) {
if (typeof col.default === 'string') {
alterSql += ` NOT NULL DEFAULT '${col.default}'`;
}
else {
alterSql += ` NOT NULL DEFAULT ${col.default}`;
}
}
else if (col.notNull) {
// SQLite要求添加NOT NULL列时必须有DEFAULT值
alterSql += ` NOT NULL DEFAULT ''`;
}
if (col.unique) {
alterSql += ` UNIQUE`;
}
db.exec(alterSql);
}
}
// 创建新索引
if (tableInfo.indices) {
for (const idx of tableInfo.indices) {
// 检查索引是否存在
const indexExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='index' AND name=?`).get(idx.name);
if (!indexExists) {
const uniqueClause = idx.unique ? 'UNIQUE ' : '';
const createIndexSql = `CREATE ${uniqueClause}INDEX IF NOT EXISTS ${idx.name} ON ${tableName} (${idx.columns.join(', ')})`;
db.exec(createIndexSql);
}
}
}
// 提交事务
db.exec('COMMIT');
return true;
}
catch (err) {
// 回滚事务
db.exec('ROLLBACK');
console.error('表迁移失败:', err);
return false;
}
}
catch (error) {
console.error('表迁移失败:', error);
return false;
}
}
/**
* 重建表(用于结构变更较大时)
* @param db 数据库实例
* @param entityClass 实体类
* @returns 是否重建成功
*/
static rebuildTable(db, entityClass) {
const tableInfo = entityClass.getTableInfo();
const tableName = tableInfo.name;
const tempTableName = `${tableName}_temp`;
try {
// 开始事务
db.exec('BEGIN TRANSACTION');
try {
// 检查表是否存在
const tableExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`).get(tableName);
if (!tableExists) {
// 表不存在,直接创建
db.exec(entityClass.getCreateTableSQL());
db.exec('COMMIT');
return true;
}
// 获取当前表的列信息
const tableColumns = db.prepare(`PRAGMA table_info(${tableName})`).all();
// 创建新表结构
const createTableSql = entityClass.getCreateTableSQL()
.replace(`CREATE TABLE IF NOT EXISTS ${tableName}`, `CREATE TABLE ${tempTableName}`);
db.exec(createTableSql);
// 找出新旧表的共同列,用于数据迁移
const newTableColumns = tableInfo.columns.map(c => c.name);
const commonColumns = tableColumns
.map(c => c.name)
.filter(name => newTableColumns.includes(name));
// 复制数据到新表
if (commonColumns.length > 0) {
const copyDataSql = `
INSERT INTO ${tempTableName} (${commonColumns.join(', ')})
SELECT ${commonColumns.join(', ')} FROM ${tableName}
`;
db.exec(copyDataSql);
}
// 删除旧表并重命名新表
db.exec(`DROP TABLE ${tableName}`);
db.exec(`ALTER TABLE ${tempTableName} RENAME TO ${tableName}`);
// 提交事务
db.exec('COMMIT');
return true;
}
catch (err) {
// 回滚事务
db.exec('ROLLBACK');
console.error('表重建失败:', err);
return false;
}
}
catch (error) {
console.error('表重建失败:', error);
return false;
}
}
}
exports.MigrationUtil = MigrationUtil;
//# sourceMappingURL=MigrationUtil.js.map