Add BooksSyncContext, refine database schema, and enhance synchronization support
- Introduce `BooksSyncContext` for managing book synchronization states (server-only, local-only, to-sync, etc.). - Remove `UserContext` and related dependencies. - Refine localization strings (`en.json`) with sync-related updates (e.g., "toSyncFromServer", "toSyncToServer"). - Extend database schema with additional tables and fields for syncing books, chapters, and related entities. - Add `last_update` fields and update corresponding repository methods to support synchronization logic. - Enhance IPC handlers with stricter typing, data validation, and sync-aware operations.
This commit is contained in:
@@ -18,29 +18,6 @@ export function initializeSchema(db: Database): void {
|
||||
// Enable foreign keys
|
||||
db.exec('PRAGMA foreign_keys = ON');
|
||||
|
||||
// Create sync metadata table (tracks last sync times)
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS _sync_metadata (
|
||||
table_name TEXT PRIMARY KEY,
|
||||
last_sync_at INTEGER NOT NULL,
|
||||
last_push_at INTEGER,
|
||||
pending_changes INTEGER DEFAULT 0
|
||||
);
|
||||
`);
|
||||
|
||||
// Create pending changes queue (for offline operations)
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS _pending_changes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
table_name TEXT NOT NULL,
|
||||
operation TEXT NOT NULL, -- 'INSERT', 'UPDATE', 'DELETE'
|
||||
record_id TEXT NOT NULL,
|
||||
data TEXT, -- JSON data for INSERT/UPDATE
|
||||
created_at INTEGER NOT NULL,
|
||||
retry_count INTEGER DEFAULT 0
|
||||
);
|
||||
`);
|
||||
|
||||
// AI Conversations
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS ai_conversations (
|
||||
@@ -53,7 +30,6 @@ export function initializeSchema(db: Database): void {
|
||||
user_id TEXT NOT NULL,
|
||||
summary TEXT,
|
||||
convo_meta TEXT NOT NULL,
|
||||
synced INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -66,7 +42,6 @@ export function initializeSchema(db: Database): void {
|
||||
role TEXT NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
message_date INTEGER NOT NULL,
|
||||
synced INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (conversation_id) REFERENCES ai_conversations(conversation_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -75,7 +50,8 @@ export function initializeSchema(db: Database): void {
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS book_acts (
|
||||
act_id INTEGER PRIMARY KEY,
|
||||
title TEXT NOT NULL
|
||||
title TEXT NOT NULL,
|
||||
last_update INTEGER DEFAULT 0
|
||||
);
|
||||
`);
|
||||
|
||||
@@ -87,7 +63,7 @@ export function initializeSchema(db: Database): void {
|
||||
user_id TEXT NOT NULL,
|
||||
act_index INTEGER NOT NULL,
|
||||
summary TEXT,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -106,7 +82,7 @@ export function initializeSchema(db: Database): void {
|
||||
tone TEXT,
|
||||
atmosphere TEXT,
|
||||
current_resume TEXT,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (user_id, book_id),
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
@@ -122,7 +98,7 @@ export function initializeSchema(db: Database): void {
|
||||
hashed_title TEXT,
|
||||
words_count INTEGER,
|
||||
chapter_order INTEGER,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -134,10 +110,10 @@ export function initializeSchema(db: Database): void {
|
||||
chapter_id TEXT NOT NULL,
|
||||
author_id TEXT NOT NULL,
|
||||
version INTEGER NOT NULL DEFAULT 2,
|
||||
content TEXT NOT NULL,
|
||||
content TEXT,
|
||||
words_count INTEGER NOT NULL,
|
||||
time_on_it INTEGER NOT NULL DEFAULT 0,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (chapter_id) REFERENCES book_chapters(chapter_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -152,9 +128,9 @@ export function initializeSchema(db: Database): void {
|
||||
plot_point_id TEXT,
|
||||
book_id TEXT,
|
||||
author_id TEXT,
|
||||
summary TEXT NOT NULL,
|
||||
goal TEXT NOT NULL,
|
||||
synced INTEGER DEFAULT 0,
|
||||
summary TEXT,
|
||||
goal TEXT,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (chapter_id) REFERENCES book_chapters(chapter_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (incident_id) REFERENCES book_incidents(incident_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (plot_point_id) REFERENCES book_plot_points(plot_point_id) ON DELETE CASCADE
|
||||
@@ -175,7 +151,7 @@ export function initializeSchema(db: Database): void {
|
||||
role TEXT,
|
||||
biography TEXT,
|
||||
history TEXT,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -188,7 +164,7 @@ export function initializeSchema(db: Database): void {
|
||||
user_id TEXT NOT NULL,
|
||||
attribute_name TEXT NOT NULL,
|
||||
attribute_value TEXT NOT NULL,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (character_id) REFERENCES book_characters(character_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -202,7 +178,7 @@ export function initializeSchema(db: Database): void {
|
||||
type TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
history TEXT NOT NULL,
|
||||
synced INTEGER DEFAULT 0
|
||||
last_update INTEGER DEFAULT 0
|
||||
);
|
||||
`);
|
||||
|
||||
@@ -211,17 +187,17 @@ export function initializeSchema(db: Database): void {
|
||||
CREATE TABLE IF NOT EXISTS book_guide_line (
|
||||
user_id TEXT NOT NULL,
|
||||
book_id TEXT NOT NULL,
|
||||
tone TEXT NOT NULL,
|
||||
atmosphere TEXT NOT NULL,
|
||||
writing_style TEXT NOT NULL,
|
||||
themes TEXT NOT NULL,
|
||||
symbolism TEXT NOT NULL,
|
||||
motifs TEXT NOT NULL,
|
||||
narrative_voice TEXT NOT NULL,
|
||||
pacing TEXT NOT NULL,
|
||||
intended_audience TEXT NOT NULL,
|
||||
key_messages TEXT NOT NULL,
|
||||
synced INTEGER DEFAULT 0,
|
||||
tone TEXT,
|
||||
atmosphere TEXT,
|
||||
writing_style TEXT,
|
||||
themes TEXT,
|
||||
symbolism TEXT,
|
||||
motifs TEXT,
|
||||
narrative_voice TEXT,
|
||||
pacing TEXT,
|
||||
intended_audience TEXT,
|
||||
key_messages TEXT,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (user_id, book_id),
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
@@ -236,7 +212,7 @@ export function initializeSchema(db: Database): void {
|
||||
title TEXT NOT NULL,
|
||||
hashed_title TEXT NOT NULL,
|
||||
summary TEXT,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -249,7 +225,7 @@ export function initializeSchema(db: Database): void {
|
||||
book_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
hashed_issue_name TEXT NOT NULL,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -262,7 +238,7 @@ export function initializeSchema(db: Database): void {
|
||||
user_id TEXT NOT NULL,
|
||||
loc_name TEXT NOT NULL,
|
||||
loc_original_name TEXT NOT NULL,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -277,7 +253,7 @@ export function initializeSchema(db: Database): void {
|
||||
linked_incident_id TEXT,
|
||||
author_id TEXT NOT NULL,
|
||||
book_id TEXT NOT NULL,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -295,7 +271,7 @@ export function initializeSchema(db: Database): void {
|
||||
economy TEXT,
|
||||
religion TEXT,
|
||||
languages TEXT,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -310,7 +286,7 @@ export function initializeSchema(db: Database): void {
|
||||
name TEXT NOT NULL,
|
||||
original_name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (world_id) REFERENCES book_world(world_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -324,14 +300,14 @@ export function initializeSchema(db: Database): void {
|
||||
title TEXT NOT NULL,
|
||||
hashed_title TEXT NOT NULL,
|
||||
sub_title TEXT,
|
||||
hashed_sub_title TEXT NOT NULL,
|
||||
summary TEXT NOT NULL,
|
||||
hashed_sub_title TEXT,
|
||||
summary TEXT,
|
||||
serie_id INTEGER,
|
||||
desired_release_date TEXT,
|
||||
desired_word_count INTEGER,
|
||||
words_count INTEGER,
|
||||
cover_image TEXT,
|
||||
synced INTEGER DEFAULT 0
|
||||
last_update INTEGER DEFAULT 0
|
||||
);
|
||||
`);
|
||||
|
||||
@@ -354,8 +330,7 @@ export function initializeSchema(db: Database): void {
|
||||
interline TEXT NOT NULL,
|
||||
paper_width INTEGER NOT NULL,
|
||||
theme TEXT NOT NULL,
|
||||
focus INTEGER NOT NULL,
|
||||
synced INTEGER DEFAULT 0
|
||||
focus INTEGER NOT NULL
|
||||
);
|
||||
`);
|
||||
|
||||
@@ -381,8 +356,7 @@ export function initializeSchema(db: Database): void {
|
||||
account_verified INTEGER NOT NULL DEFAULT 0,
|
||||
erite_points INTEGER NOT NULL DEFAULT 100,
|
||||
stripe_customer_id TEXT,
|
||||
credits_balance REAL DEFAULT 0,
|
||||
synced INTEGER DEFAULT 0
|
||||
credits_balance REAL DEFAULT 0
|
||||
);
|
||||
`);
|
||||
|
||||
@@ -395,7 +369,7 @@ export function initializeSchema(db: Database): void {
|
||||
element_name TEXT NOT NULL,
|
||||
original_name TEXT NOT NULL,
|
||||
element_description TEXT,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (location) REFERENCES book_location(loc_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -409,7 +383,7 @@ export function initializeSchema(db: Database): void {
|
||||
sub_elem_name TEXT NOT NULL,
|
||||
original_name TEXT NOT NULL,
|
||||
sub_elem_description TEXT,
|
||||
synced INTEGER DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (element_id) REFERENCES location_element(element_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -421,7 +395,6 @@ export function initializeSchema(db: Database): void {
|
||||
brand TEXT NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
actif INTEGER NOT NULL DEFAULT 1,
|
||||
synced INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (user_id) REFERENCES erit_users(user_id) ON DELETE CASCADE
|
||||
);
|
||||
`);
|
||||
@@ -433,7 +406,6 @@ export function initializeSchema(db: Database): void {
|
||||
book_id TEXT NOT NULL,
|
||||
chapter_id TEXT NOT NULL,
|
||||
version INTEGER NOT NULL,
|
||||
synced INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (user_id, book_id),
|
||||
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (chapter_id) REFERENCES book_chapters(chapter_id) ON DELETE CASCADE
|
||||
@@ -443,8 +415,8 @@ export function initializeSchema(db: Database): void {
|
||||
// Create indexes for better performance
|
||||
createIndexes(db);
|
||||
|
||||
// Initialize sync metadata for all tables
|
||||
initializeSyncMetadata(db);
|
||||
// Set schema version for new databases (prevents unnecessary migrations)
|
||||
initializeSchemaVersion(db);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -461,50 +433,9 @@ function createIndexes(db: Database): void {
|
||||
CREATE INDEX IF NOT EXISTS idx_character_attrs_character ON book_characters_attributes(character_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_world_book ON book_world(book_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_world_elements_world ON book_world_elements(world_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pending_changes_table ON _pending_changes(table_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_pending_changes_created ON _pending_changes(created_at);
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize sync metadata for all tables
|
||||
*/
|
||||
function initializeSyncMetadata(db: Database): void {
|
||||
const tables = [
|
||||
'ai_conversations', 'ai_messages_history', 'book_acts', 'book_act_summaries',
|
||||
'book_ai_guide_line', 'book_chapters', 'book_chapter_content', 'book_chapter_infos',
|
||||
'book_characters', 'book_characters_attributes', 'book_guide_line', 'book_incidents',
|
||||
'book_issues', 'book_location', 'book_plot_points', 'book_world', 'book_world_elements',
|
||||
'erit_books', 'erit_editor', 'erit_users', 'location_element', 'location_sub_element',
|
||||
'user_keys', 'user_last_chapter'
|
||||
];
|
||||
|
||||
for (const table of tables) {
|
||||
db.run(`
|
||||
INSERT OR IGNORE INTO _sync_metadata (table_name, last_sync_at, pending_changes)
|
||||
VALUES (?, 0, 0)
|
||||
`, [table]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all tables (for testing/reset)
|
||||
*/
|
||||
export function dropAllTables(db: Database): void {
|
||||
const tables = db.all(`
|
||||
SELECT name FROM sqlite_master
|
||||
WHERE type='table' AND name NOT LIKE 'sqlite_%'
|
||||
`, []) as unknown as { name: string }[];
|
||||
|
||||
db.exec('PRAGMA foreign_keys = OFF');
|
||||
|
||||
for (const { name } of tables) {
|
||||
db.exec(`DROP TABLE IF EXISTS ${name}`);
|
||||
}
|
||||
|
||||
db.exec('PRAGMA foreign_keys = ON');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current schema version from database
|
||||
*/
|
||||
@@ -526,6 +457,17 @@ function setDbSchemaVersion(db: Database, version: number): void {
|
||||
db.run('INSERT INTO _schema_version (version) VALUES (?)', [version]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize schema version for new databases
|
||||
* Only sets version if table doesn't exist yet (new DB)
|
||||
*/
|
||||
function initializeSchemaVersion(db: Database): void {
|
||||
const currentVersion = getDbSchemaVersion(db);
|
||||
if (currentVersion === 0) {
|
||||
setDbSchemaVersion(db, SCHEMA_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a column exists in a table
|
||||
*/
|
||||
@@ -548,6 +490,25 @@ function dropColumnIfExists(db: Database, tableName: string, columnName: string)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreate a table with a new schema while preserving data
|
||||
*/
|
||||
function recreateTable(db: Database, tableName: string, newSchema: string, columnsToKeep: string): void {
|
||||
try {
|
||||
db.exec('PRAGMA foreign_keys = OFF');
|
||||
db.exec(`CREATE TABLE ${tableName}_backup AS SELECT ${columnsToKeep} FROM ${tableName}`);
|
||||
db.exec(`DROP TABLE ${tableName}`);
|
||||
db.exec(newSchema);
|
||||
db.exec(`INSERT INTO ${tableName} (${columnsToKeep}) SELECT ${columnsToKeep} FROM ${tableName}_backup`);
|
||||
db.exec(`DROP TABLE ${tableName}_backup`);
|
||||
db.exec('PRAGMA foreign_keys = ON');
|
||||
console.log(`[Migration] Recreated table ${tableName}`);
|
||||
} catch (e) {
|
||||
console.error(`[Migration] Failed to recreate table ${tableName}:`, e);
|
||||
db.exec('PRAGMA foreign_keys = ON');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run migrations to update schema from one version to another
|
||||
*/
|
||||
@@ -560,29 +521,63 @@ export function runMigrations(db: Database): void {
|
||||
|
||||
console.log(`[Migration] Upgrading schema from version ${currentVersion} to ${SCHEMA_VERSION}`);
|
||||
|
||||
// Migration 1 -> 2: Remove all meta_* columns
|
||||
// Migration v2: Remove NOT NULL constraints to allow null values from server sync
|
||||
if (currentVersion < 2) {
|
||||
console.log('[Migration] Running migration v2: Removing meta columns...');
|
||||
console.log('[Migration] Running migration v2: Allowing NULL in certain columns...');
|
||||
|
||||
dropColumnIfExists(db, 'ai_messages_history', 'meta_message');
|
||||
dropColumnIfExists(db, 'book_act_summaries', 'meta_acts');
|
||||
dropColumnIfExists(db, 'book_ai_guide_line', 'meta');
|
||||
dropColumnIfExists(db, 'book_chapters', 'meta_chapter');
|
||||
dropColumnIfExists(db, 'book_chapter_content', 'meta_chapter_content');
|
||||
dropColumnIfExists(db, 'book_chapter_infos', 'meta_chapter_info');
|
||||
dropColumnIfExists(db, 'book_characters', 'char_meta');
|
||||
dropColumnIfExists(db, 'book_characters_attributes', 'attr_meta');
|
||||
dropColumnIfExists(db, 'book_guide_line', 'meta_guide_line');
|
||||
dropColumnIfExists(db, 'book_incidents', 'meta_incident');
|
||||
dropColumnIfExists(db, 'book_issues', 'meta_issue');
|
||||
dropColumnIfExists(db, 'book_location', 'loc_meta');
|
||||
dropColumnIfExists(db, 'book_plot_points', 'meta_plot');
|
||||
dropColumnIfExists(db, 'book_world', 'meta_world');
|
||||
dropColumnIfExists(db, 'book_world_elements', 'meta_element');
|
||||
dropColumnIfExists(db, 'erit_books', 'book_meta');
|
||||
dropColumnIfExists(db, 'erit_users', 'user_meta');
|
||||
dropColumnIfExists(db, 'location_element', 'element_meta');
|
||||
dropColumnIfExists(db, 'location_sub_element', 'sub_elem_meta');
|
||||
// Recreate erit_books with nullable hashed_sub_title and summary
|
||||
recreateTable(db, 'erit_books', `
|
||||
CREATE TABLE erit_books (
|
||||
book_id TEXT PRIMARY KEY,
|
||||
type TEXT NOT NULL,
|
||||
author_id TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
hashed_title TEXT NOT NULL,
|
||||
sub_title TEXT,
|
||||
hashed_sub_title TEXT,
|
||||
summary TEXT,
|
||||
serie_id INTEGER,
|
||||
desired_release_date TEXT,
|
||||
desired_word_count INTEGER,
|
||||
words_count INTEGER,
|
||||
cover_image TEXT,
|
||||
last_update INTEGER DEFAULT 0
|
||||
)
|
||||
`, 'book_id, type, author_id, title, hashed_title, sub_title, hashed_sub_title, summary, serie_id, desired_release_date, desired_word_count, words_count, cover_image, last_update');
|
||||
|
||||
// Recreate book_chapter_content with nullable content
|
||||
recreateTable(db, 'book_chapter_content', `
|
||||
CREATE TABLE book_chapter_content (
|
||||
content_id TEXT PRIMARY KEY,
|
||||
chapter_id TEXT NOT NULL,
|
||||
author_id TEXT NOT NULL,
|
||||
version INTEGER NOT NULL DEFAULT 2,
|
||||
content TEXT,
|
||||
words_count INTEGER NOT NULL,
|
||||
time_on_it INTEGER NOT NULL DEFAULT 0,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (chapter_id) REFERENCES book_chapters(chapter_id) ON DELETE CASCADE
|
||||
)
|
||||
`, 'content_id, chapter_id, author_id, version, content, words_count, time_on_it, last_update');
|
||||
|
||||
// Recreate book_chapter_infos with nullable summary and goal
|
||||
recreateTable(db, 'book_chapter_infos', `
|
||||
CREATE TABLE book_chapter_infos (
|
||||
chapter_info_id TEXT PRIMARY KEY,
|
||||
chapter_id TEXT,
|
||||
act_id INTEGER,
|
||||
incident_id TEXT,
|
||||
plot_point_id TEXT,
|
||||
book_id TEXT,
|
||||
author_id TEXT,
|
||||
summary TEXT,
|
||||
goal TEXT,
|
||||
last_update INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (chapter_id) REFERENCES book_chapters(chapter_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (incident_id) REFERENCES book_incidents(incident_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (plot_point_id) REFERENCES book_plot_points(plot_point_id) ON DELETE CASCADE
|
||||
)
|
||||
`, 'chapter_info_id, chapter_id, act_id, incident_id, plot_point_id, book_id, author_id, summary, goal, last_update');
|
||||
|
||||
console.log('[Migration] Migration v2 completed');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user