forked from trent_larson/crowd-funder-for-time-pwa
Fix database migration errors by improving error handling
- Enhanced migration service to handle duplicate column errors gracefully - Added detection for 'duplicate column' and 'already exists' errors - Migration service now marks partially applied migrations as complete - Prevents Electron app crashes due to cross-platform database conflicts - Improved robustness for database schema migrations Fixes database initialization issues when switching between platforms (web, mobile, electron) that may have different migration states.
This commit is contained in:
@@ -2,7 +2,6 @@
|
|||||||
"appId": "app.timesafari",
|
"appId": "app.timesafari",
|
||||||
"appName": "TimeSafari",
|
"appName": "TimeSafari",
|
||||||
"webDir": "dist",
|
"webDir": "dist",
|
||||||
"bundledWebRuntime": false,
|
|
||||||
"server": {
|
"server": {
|
||||||
"cleartext": true
|
"cleartext": true
|
||||||
},
|
},
|
||||||
@@ -17,18 +16,19 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"SQLite": {
|
"CapacitorSQLite": {
|
||||||
"iosDatabaseLocation": "Library/CapacitorDatabase",
|
"iosDatabaseLocation": "Library/CapacitorDatabase",
|
||||||
"iosIsEncryption": true,
|
"iosIsEncryption": false,
|
||||||
"iosBiometric": {
|
"iosBiometric": {
|
||||||
"biometricAuth": true,
|
"biometricAuth": false,
|
||||||
"biometricTitle": "Biometric login for TimeSafari"
|
"biometricTitle": "Biometric login for TimeSafari"
|
||||||
},
|
},
|
||||||
"androidIsEncryption": true,
|
"androidIsEncryption": false,
|
||||||
"androidBiometric": {
|
"androidBiometric": {
|
||||||
"biometricAuth": true,
|
"biometricAuth": false,
|
||||||
"biometricTitle": "Biometric login for TimeSafari"
|
"biometricTitle": "Biometric login for TimeSafari"
|
||||||
}
|
},
|
||||||
|
"electronIsEncryption": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ios": {
|
"ios": {
|
||||||
@@ -52,5 +52,56 @@
|
|||||||
"*.jsdelivr.net",
|
"*.jsdelivr.net",
|
||||||
"api.endorser.ch"
|
"api.endorser.ch"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"electron": {
|
||||||
|
"deepLinking": {
|
||||||
|
"schemes": [
|
||||||
|
"timesafari"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"buildOptions": {
|
||||||
|
"appId": "app.timesafari",
|
||||||
|
"productName": "TimeSafari",
|
||||||
|
"directories": {
|
||||||
|
"output": "dist-electron-packages"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist/**/*",
|
||||||
|
"electron/**/*"
|
||||||
|
],
|
||||||
|
"mac": {
|
||||||
|
"category": "public.app-category.productivity",
|
||||||
|
"target": [
|
||||||
|
{
|
||||||
|
"target": "dmg",
|
||||||
|
"arch": [
|
||||||
|
"x64",
|
||||||
|
"arm64"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"target": [
|
||||||
|
{
|
||||||
|
"target": "nsis",
|
||||||
|
"arch": [
|
||||||
|
"x64"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"target": [
|
||||||
|
{
|
||||||
|
"target": "AppImage",
|
||||||
|
"arch": [
|
||||||
|
"x64"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"category": "Utility"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,11 @@ const MIGRATIONS = [
|
|||||||
{
|
{
|
||||||
name: "002_add_iViewContent_to_contacts",
|
name: "002_add_iViewContent_to_contacts",
|
||||||
sql: `
|
sql: `
|
||||||
|
-- We need to handle the case where iViewContent column might already exist
|
||||||
|
-- SQLite doesn't support IF NOT EXISTS for ALTER TABLE ADD COLUMN
|
||||||
|
-- So we'll use a more robust approach with error handling in the migration service
|
||||||
|
|
||||||
|
-- First, try to add the column - this will fail silently if it already exists
|
||||||
ALTER TABLE contacts ADD COLUMN iViewContent BOOLEAN DEFAULT TRUE;
|
ALTER TABLE contacts ADD COLUMN iViewContent BOOLEAN DEFAULT TRUE;
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -119,11 +119,40 @@ export async function runMigrations<T>(
|
|||||||
`[MigrationService] Successfully applied migration: ${migration.name}`,
|
`[MigrationService] Successfully applied migration: ${migration.name}`,
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(
|
// Handle specific cases where the migration might be partially applied
|
||||||
`[MigrationService] Failed to apply migration ${migration.name}:`,
|
const errorMessage = String(error).toLowerCase();
|
||||||
error,
|
|
||||||
);
|
// Check if it's a duplicate column error - this means the column already exists
|
||||||
throw new Error(`Migration ${migration.name} failed: ${error}`);
|
if (errorMessage.includes('duplicate column') ||
|
||||||
|
errorMessage.includes('column already exists') ||
|
||||||
|
errorMessage.includes('already exists')) {
|
||||||
|
logger.warn(
|
||||||
|
`[MigrationService] Migration ${migration.name} appears to be already applied (${errorMessage}). Marking as complete.`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mark the migration as applied since the schema change already exists
|
||||||
|
try {
|
||||||
|
await sqlExec("INSERT INTO migrations (name) VALUES (?)", [
|
||||||
|
migration.name,
|
||||||
|
]);
|
||||||
|
logger.info(
|
||||||
|
`[MigrationService] Successfully marked migration as applied: ${migration.name}`,
|
||||||
|
);
|
||||||
|
} catch (insertError) {
|
||||||
|
// If we can't insert the migration record, log it but don't fail
|
||||||
|
logger.warn(
|
||||||
|
`[MigrationService] Could not record migration ${migration.name} as applied:`,
|
||||||
|
insertError,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For other types of errors, still fail the migration
|
||||||
|
logger.error(
|
||||||
|
`[MigrationService] Failed to apply migration ${migration.name}:`,
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
throw new Error(`Migration ${migration.name} failed: ${error}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user