UNPKG

quicklite

Version:

A lightweight ORM toolkit for SQLite in Node.js applications

210 lines 9.1 kB
"use strict"; 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