fix(db): detect duplicate-column from nested migration error cause

This commit is contained in:
ciat-777
2026-03-14 19:25:55 +08:00
parent 7bdcf27c41
commit 7d431d3ccd
2 changed files with 85 additions and 2 deletions
+61
View File
@@ -125,4 +125,65 @@ describe('sqlite migrate bootstrap', () => {
sqlite.close(); sqlite.close();
}); });
it('recovers when duplicate-column message appears only in error cause', async () => {
const dataDir = mkdtempSync(join(tmpdir(), 'metapi-migrate-recover-cause-'));
process.env.DATA_DIR = dataDir;
vi.resetModules();
const migrateModule = await import('./migrate.js');
const { __migrateTestUtils } = migrateModule;
const sqlite = new Database(':memory:');
sqlite.exec(`
CREATE TABLE account_tokens (
id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
token_group text
);
`);
const tempMigrationsDir = mkdtempSync(join(tmpdir(), 'metapi-migration-files-cause-'));
mkdirSync(join(tempMigrationsDir, 'meta'), { recursive: true });
writeFileSync(
join(tempMigrationsDir, 'meta', '_journal.json'),
JSON.stringify({
entries: [
{
tag: '0007_account_token_group',
when: 1772500000001,
},
],
}),
);
writeFileSync(
join(tempMigrationsDir, '0007_account_token_group.sql'),
'ALTER TABLE `account_tokens` ADD `token_group` text;\n',
);
const drizzleLikeError = {
message: "DrizzleError: Failed to run the query 'ALTER TABLE `account_tokens` ADD `token_group` text;\n'",
cause: {
message: 'SqliteError: duplicate column name: token_group',
},
};
const recovered = __migrateTestUtils.tryRecoverDuplicateColumnMigrationError(
sqlite,
tempMigrationsDir,
drizzleLikeError,
);
expect(recovered).toBe(true);
const applied = sqlite
.prepare('SELECT hash, created_at FROM __drizzle_migrations')
.all() as Array<{ hash: string; created_at: number }>;
expect(applied).toHaveLength(1);
expect(Number(applied[0].created_at)).toBe(1772500000001);
sqlite.close();
});
}); });
+24 -2
View File
@@ -197,9 +197,31 @@ function markMigrationRecordIfMissing(sqlite: Database.Database, record: Migrati
} }
function normalizeSchemaErrorMessage(error: unknown): string { function normalizeSchemaErrorMessage(error: unknown): string {
if (typeof error === 'object' && error && 'message' in error) { if (!error || typeof error !== 'object') {
return String((error as { message?: unknown }).message || ''); return String(error || '');
} }
const collected: string[] = [];
let cursor: unknown = error;
let depth = 0;
while (cursor && typeof cursor === 'object' && depth < 8) {
const current = cursor as { message?: unknown; cause?: unknown };
if (current.message !== undefined && current.message !== null) {
const text = String(current.message).trim();
if (text.length > 0) {
collected.push(text);
}
}
cursor = current.cause;
depth += 1;
}
if (collected.length > 0) {
return collected.join(' | ');
}
return String(error || ''); return String(error || '');
} }