Upgrade database schema to version 2 and remove unused meta_* columns

- Increment `SCHEMA_VERSION` to 2 in `schema.ts`.
- Remove all `meta_*` columns from database tables.
- Add migration logic to handle schema upgrades and clean up unused columns.
- Modify database models and repository methods to exclude `meta_*` fields for stricter typings and improved structure.
- Refactor and optimize query statements across repositories to align with new schema changes.
This commit is contained in:
natreex
2025-11-26 19:17:40 -05:00
parent 736b9a3609
commit 9648d9e9be
13 changed files with 178 additions and 131 deletions

View File

@@ -8,7 +8,7 @@ type Database = sqlite3.Database;
* Data is encrypted before storage and decrypted on retrieval
*/
export const SCHEMA_VERSION = 1;
export const SCHEMA_VERSION = 2;
/**
* Initialize the local SQLite database with all required tables
@@ -66,7 +66,6 @@ export function initializeSchema(db: Database): void {
role TEXT NOT NULL,
message TEXT NOT NULL,
message_date INTEGER NOT NULL,
meta_message TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (conversation_id) REFERENCES ai_conversations(conversation_id) ON DELETE CASCADE
);
@@ -88,7 +87,6 @@ export function initializeSchema(db: Database): void {
user_id TEXT NOT NULL,
act_index INTEGER NOT NULL,
summary TEXT,
meta_acts TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
);
@@ -108,7 +106,6 @@ export function initializeSchema(db: Database): void {
tone TEXT,
atmosphere TEXT,
current_resume TEXT,
meta TEXT NOT NULL,
synced INTEGER DEFAULT 0,
PRIMARY KEY (user_id, book_id),
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
@@ -125,7 +122,6 @@ export function initializeSchema(db: Database): void {
hashed_title TEXT,
words_count INTEGER,
chapter_order INTEGER,
meta_chapter TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
);
@@ -140,7 +136,6 @@ export function initializeSchema(db: Database): void {
version INTEGER NOT NULL DEFAULT 2,
content TEXT NOT NULL,
words_count INTEGER NOT NULL,
meta_chapter_content TEXT NOT NULL,
time_on_it INTEGER NOT NULL DEFAULT 0,
synced INTEGER DEFAULT 0,
FOREIGN KEY (chapter_id) REFERENCES book_chapters(chapter_id) ON DELETE CASCADE
@@ -159,7 +154,6 @@ export function initializeSchema(db: Database): void {
author_id TEXT,
summary TEXT NOT NULL,
goal TEXT NOT NULL,
meta_chapter_info TEXT NOT NULL,
synced 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,
@@ -181,7 +175,6 @@ export function initializeSchema(db: Database): void {
role TEXT,
biography TEXT,
history TEXT,
char_meta TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
);
@@ -195,7 +188,6 @@ export function initializeSchema(db: Database): void {
user_id TEXT NOT NULL,
attribute_name TEXT NOT NULL,
attribute_value TEXT NOT NULL,
attr_meta TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (character_id) REFERENCES book_characters(character_id) ON DELETE CASCADE
);
@@ -229,7 +221,6 @@ export function initializeSchema(db: Database): void {
pacing TEXT NOT NULL,
intended_audience TEXT NOT NULL,
key_messages TEXT NOT NULL,
meta_guide_line TEXT NOT NULL,
synced INTEGER DEFAULT 0,
PRIMARY KEY (user_id, book_id),
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
@@ -245,7 +236,6 @@ export function initializeSchema(db: Database): void {
title TEXT NOT NULL,
hashed_title TEXT NOT NULL,
summary TEXT,
meta_incident TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
);
@@ -259,7 +249,6 @@ export function initializeSchema(db: Database): void {
book_id TEXT NOT NULL,
name TEXT NOT NULL,
hashed_issue_name TEXT NOT NULL,
meta_issue TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
);
@@ -273,7 +262,6 @@ export function initializeSchema(db: Database): void {
user_id TEXT NOT NULL,
loc_name TEXT NOT NULL,
loc_original_name TEXT NOT NULL,
loc_meta TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
);
@@ -289,7 +277,6 @@ export function initializeSchema(db: Database): void {
linked_incident_id TEXT,
author_id TEXT NOT NULL,
book_id TEXT NOT NULL,
meta_plot TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
);
@@ -308,7 +295,6 @@ export function initializeSchema(db: Database): void {
economy TEXT,
religion TEXT,
languages TEXT,
meta_world TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (book_id) REFERENCES erit_books(book_id) ON DELETE CASCADE
);
@@ -324,7 +310,6 @@ export function initializeSchema(db: Database): void {
name TEXT NOT NULL,
original_name TEXT NOT NULL,
description TEXT,
meta_element TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (world_id) REFERENCES book_world(world_id) ON DELETE CASCADE
);
@@ -346,7 +331,6 @@ export function initializeSchema(db: Database): void {
desired_word_count INTEGER,
words_count INTEGER,
cover_image TEXT,
book_meta TEXT,
synced INTEGER DEFAULT 0
);
`);
@@ -395,7 +379,6 @@ export function initializeSchema(db: Database): void {
verify_code TEXT,
reg_date INTEGER NOT NULL,
account_verified INTEGER NOT NULL DEFAULT 0,
user_meta TEXT NOT NULL,
erite_points INTEGER NOT NULL DEFAULT 100,
stripe_customer_id TEXT,
credits_balance REAL DEFAULT 0,
@@ -412,7 +395,6 @@ export function initializeSchema(db: Database): void {
element_name TEXT NOT NULL,
original_name TEXT NOT NULL,
element_description TEXT,
element_meta TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (location) REFERENCES book_location(loc_id) ON DELETE CASCADE
);
@@ -427,7 +409,6 @@ export function initializeSchema(db: Database): void {
sub_elem_name TEXT NOT NULL,
original_name TEXT NOT NULL,
sub_elem_description TEXT,
sub_elem_meta TEXT NOT NULL,
synced INTEGER DEFAULT 0,
FOREIGN KEY (element_id) REFERENCES location_element(element_id) ON DELETE CASCADE
);
@@ -523,3 +504,90 @@ export function dropAllTables(db: Database): void {
db.exec('PRAGMA foreign_keys = ON');
}
/**
* Get current schema version from database
*/
function getDbSchemaVersion(db: Database): number {
try {
const result = db.get('SELECT version FROM _schema_version LIMIT 1') as { version: number } | undefined;
return result?.version ?? 0;
} catch {
return 0;
}
}
/**
* Set schema version in database
*/
function setDbSchemaVersion(db: Database, version: number): void {
db.exec('CREATE TABLE IF NOT EXISTS _schema_version (version INTEGER PRIMARY KEY)');
db.run('DELETE FROM _schema_version');
db.run('INSERT INTO _schema_version (version) VALUES (?)', [version]);
}
/**
* Check if a column exists in a table
*/
function columnExists(db: Database, tableName: string, columnName: string): boolean {
const columns = db.all(`PRAGMA table_info(${tableName})`) as { name: string }[];
return columns.some(col => col.name === columnName);
}
/**
* Safely drop a column if it exists
*/
function dropColumnIfExists(db: Database, tableName: string, columnName: string): void {
if (columnExists(db, tableName, columnName)) {
try {
db.exec(`ALTER TABLE ${tableName} DROP COLUMN ${columnName}`);
console.log(`[Migration] Dropped column ${columnName} from ${tableName}`);
} catch (e) {
console.error(`[Migration] Failed to drop column ${columnName} from ${tableName}:`, e);
}
}
}
/**
* Run migrations to update schema from one version to another
*/
export function runMigrations(db: Database): void {
const currentVersion = getDbSchemaVersion(db);
if (currentVersion >= SCHEMA_VERSION) {
return;
}
console.log(`[Migration] Upgrading schema from version ${currentVersion} to ${SCHEMA_VERSION}`);
// Migration 1 -> 2: Remove all meta_* columns
if (currentVersion < 2) {
console.log('[Migration] Running migration v2: Removing meta 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');
console.log('[Migration] Migration v2 completed');
}
// Update schema version
setDbSchemaVersion(db, SCHEMA_VERSION);
console.log(`[Migration] Schema updated to version ${SCHEMA_VERSION}`);
}