Skip to content

Commit 3af24f0

Browse files
fix: Improve Migration Error Handling
1 parent 4c0e7f6 commit 3af24f0

3 files changed

Lines changed: 119 additions & 83 deletions

File tree

src/database/db.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export const db = SQLite.openDatabaseSync(dbName);
3131

3232
/**
3333
* Creates the initial database schema for fresh installations
34-
* Sets up all tables, indexes, triggers and sets version to 1
34+
* Sets up all tables, indexes, triggers and sets version to 2
3535
*/
3636
const createInitialSchema = () => {
3737
db.execSync('PRAGMA journal_mode = WAL');
@@ -52,7 +52,7 @@ const createInitialSchema = () => {
5252
db.runSync(createNovelTriggerQueryUpdate);
5353
db.runSync(createNovelTriggerQueryDelete);
5454

55-
db.execSync('PRAGMA user_version = 1');
55+
db.execSync('PRAGMA user_version = 2');
5656
});
5757
};
5858

@@ -65,9 +65,23 @@ export const initializeDatabase = () => {
6565
db.execSync('PRAGMA cache_size = 10000');
6666
db.execSync('PRAGMA foreign_keys = ON');
6767

68-
const userVersion =
69-
db.getFirstSync<{ user_version: number }>('PRAGMA user_version')
70-
?.user_version ?? 0;
68+
let userVersion = 0;
69+
try {
70+
const result = db.getFirstSync<{ user_version: number }>(
71+
'PRAGMA user_version',
72+
);
73+
userVersion = result?.user_version ?? 0;
74+
} catch (error) {
75+
// If PRAGMA query fails, assume fresh database
76+
if (__DEV__) {
77+
// eslint-disable-next-line no-console
78+
console.warn(
79+
'Failed to get database version, assuming fresh install:',
80+
error,
81+
);
82+
}
83+
userVersion = 0;
84+
}
7185

7286
if (userVersion === 0) {
7387
createInitialSchema();

src/database/migrations/002_add_novel_counters.ts

Lines changed: 87 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -27,86 +27,99 @@ export const migration002: Migration = {
2727
version: 2,
2828
description: 'Add counter columns and triggers to Novel table',
2929
migrate: db => {
30-
if (!columnExists(db, 'Novel', 'chaptersDownloaded')) {
31-
db.runSync(`
32-
ALTER TABLE Novel
33-
ADD COLUMN chaptersDownloaded INTEGER DEFAULT 0
34-
`);
35-
}
36-
37-
if (!columnExists(db, 'Novel', 'chaptersUnread')) {
38-
db.runSync(`
39-
ALTER TABLE Novel
40-
ADD COLUMN chaptersUnread INTEGER DEFAULT 0
41-
`);
42-
}
43-
44-
if (!columnExists(db, 'Novel', 'totalChapters')) {
45-
db.runSync(`
46-
ALTER TABLE Novel
47-
ADD COLUMN totalChapters INTEGER DEFAULT 0
48-
`);
49-
}
30+
const addColumnSafely = (columnName: string, columnDefinition: string) => {
31+
if (!columnExists(db, 'Novel', columnName)) {
32+
try {
33+
db.runSync(`
34+
ALTER TABLE Novel
35+
ADD COLUMN ${columnName} ${columnDefinition}
36+
`);
37+
} catch (error) {
38+
// Gracefully handle ALTER TABLE failures (e.g., table doesn't exist)
39+
// Columns will be created when table is created in initial schema
40+
if (__DEV__) {
41+
// eslint-disable-next-line no-console
42+
console.warn(
43+
`Failed to add column ${columnName} to Novel table:`,
44+
error,
45+
);
46+
}
47+
}
48+
}
49+
};
5050

51-
if (!columnExists(db, 'Novel', 'lastReadAt')) {
52-
db.runSync(`
53-
ALTER TABLE Novel
54-
ADD COLUMN lastReadAt TEXT
55-
`);
56-
}
51+
addColumnSafely('chaptersDownloaded', 'INTEGER DEFAULT 0');
52+
addColumnSafely('chaptersUnread', 'INTEGER DEFAULT 0');
53+
addColumnSafely('totalChapters', 'INTEGER DEFAULT 0');
54+
addColumnSafely('lastReadAt', 'TEXT');
55+
addColumnSafely('lastUpdatedAt', 'TEXT');
5756

58-
if (!columnExists(db, 'Novel', 'lastUpdatedAt')) {
59-
db.runSync(`
60-
ALTER TABLE Novel
61-
ADD COLUMN lastUpdatedAt TEXT
62-
`);
63-
}
57+
// Verify all columns exist before running UPDATE queries to prevent SQL errors
58+
const allColumnsExist =
59+
columnExists(db, 'Novel', 'chaptersDownloaded') &&
60+
columnExists(db, 'Novel', 'chaptersUnread') &&
61+
columnExists(db, 'Novel', 'totalChapters') &&
62+
columnExists(db, 'Novel', 'lastReadAt') &&
63+
columnExists(db, 'Novel', 'lastUpdatedAt');
6464

65-
db.runSync(`
66-
UPDATE Novel
67-
SET chaptersDownloaded = (
68-
SELECT COUNT(*)
69-
FROM Chapter
70-
WHERE Chapter.novelId = Novel.id
71-
AND Chapter.isDownloaded = 1
72-
)
73-
`);
65+
if (allColumnsExist) {
66+
try {
67+
db.runSync(`
68+
UPDATE Novel
69+
SET chaptersDownloaded = (
70+
SELECT COUNT(*)
71+
FROM Chapter
72+
WHERE Chapter.novelId = Novel.id
73+
AND Chapter.isDownloaded = 1
74+
)
75+
`);
7476

75-
db.runSync(`
76-
UPDATE Novel
77-
SET chaptersUnread = (
78-
SELECT COUNT(*)
79-
FROM Chapter
80-
WHERE Chapter.novelId = Novel.id
81-
AND Chapter.unread = 1
82-
)
83-
`);
77+
db.runSync(`
78+
UPDATE Novel
79+
SET chaptersUnread = (
80+
SELECT COUNT(*)
81+
FROM Chapter
82+
WHERE Chapter.novelId = Novel.id
83+
AND Chapter.unread = 1
84+
)
85+
`);
8486

85-
db.runSync(`
86-
UPDATE Novel
87-
SET totalChapters = (
88-
SELECT COUNT(*)
89-
FROM Chapter
90-
WHERE Chapter.novelId = Novel.id
91-
)
92-
`);
87+
db.runSync(`
88+
UPDATE Novel
89+
SET totalChapters = (
90+
SELECT COUNT(*)
91+
FROM Chapter
92+
WHERE Chapter.novelId = Novel.id
93+
)
94+
`);
9395

94-
db.runSync(`
95-
UPDATE Novel
96-
SET lastReadAt = (
97-
SELECT MAX(readTime)
98-
FROM Chapter
99-
WHERE Chapter.novelId = Novel.id
100-
)
101-
`);
96+
db.runSync(`
97+
UPDATE Novel
98+
SET lastReadAt = (
99+
SELECT MAX(readTime)
100+
FROM Chapter
101+
WHERE Chapter.novelId = Novel.id
102+
)
103+
`);
102104

103-
db.runSync(`
104-
UPDATE Novel
105-
SET lastUpdatedAt = (
106-
SELECT MAX(updatedTime)
107-
FROM Chapter
108-
WHERE Chapter.novelId = Novel.id
109-
)
110-
`);
105+
db.runSync(`
106+
UPDATE Novel
107+
SET lastUpdatedAt = (
108+
SELECT MAX(updatedTime)
109+
FROM Chapter
110+
WHERE Chapter.novelId = Novel.id
111+
)
112+
`);
113+
} catch (error) {
114+
// Gracefully handle UPDATE failures - columns already added with defaults
115+
if (__DEV__) {
116+
// eslint-disable-next-line no-console
117+
console.warn(
118+
'Failed to populate counter columns in Novel table:',
119+
error,
120+
);
121+
}
122+
}
123+
}
111124
},
112125
};

src/database/utils/migrationRunner.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,19 @@ export class MigrationRunner {
4949
}
5050

5151
private getCurrentVersion(db: SQLiteDatabase): number {
52-
return (
53-
db.getFirstSync<{ user_version: number }>('PRAGMA user_version')
54-
?.user_version ?? 0
55-
);
52+
try {
53+
const result = db.getFirstSync<{ user_version: number }>(
54+
'PRAGMA user_version',
55+
);
56+
return result?.user_version ?? 0;
57+
} catch (error) {
58+
// If PRAGMA query fails, assume version 0 (fresh database)
59+
if (__DEV__) {
60+
// eslint-disable-next-line no-console
61+
console.warn('Failed to get database version, assuming 0:', error);
62+
}
63+
return 0;
64+
}
5665
}
5766

5867
private setVersion(db: SQLiteDatabase, version: number): void {

0 commit comments

Comments
 (0)