import {Database, QueryResult, RunResult, SQLiteValue} from 'node-sqlite3-wasm'; import System from "../System.js"; export interface ChapterQueryResult extends Record { chapter_id: string; title: string; chapter_order: number; } export interface ActChapterQuery extends Record { chapter_info_id: number; chapter_id: string; title: string; chapter_order: number; act_id: number; incident_id: string | null; plot_point_id: string | null; summary: string; goal: string; } export interface ChapterStoryQueryResult extends Record { chapter_info_id: number; act_id: number; summary: string; chapter_summary: string; chapter_goal: string; incident_id: number; incident_title: string; incident_summary: string; plot_point_id: number; plot_title: string; plot_summary: string; } export interface LastChapterResult extends Record { chapter_id: string; version: number; } export interface BookChaptersTable extends Record { chapter_id: string; book_id: string; author_id: string; title: string; hashed_title: string; words_count: number | null; chapter_order: number; last_update: number; } export interface BookChapterInfosTable extends Record { chapter_info_id: string; chapter_id: string; act_id: number; incident_id: string | null; plot_point_id: string | null; book_id: string; author_id: string; summary: string | null; goal: string | null; last_update: number; } export interface SyncedChapterResult extends Record { chapter_id: string; book_id: string; title: string; last_update: number; } export interface SyncedChapterInfoResult extends Record { chapter_info_id: string; chapter_id: string | null; book_id: string; last_update: number; } export interface ChapterBookResult extends Record { title: string; chapter_order: number; content: string | null; } export default class ChapterRepo { /** * Checks if a chapter name already exists for a book. * @param userId - The user identifier * @param bookId - The book identifier * @param hashedTitle - The hashed chapter title * @param lang - The language for error messages * @returns true if a chapter with this name exists */ public static checkNameDuplication(userId: string, bookId: string, hashedTitle: string, lang: 'fr' | 'en' = 'fr'): boolean { try { const db: Database = System.getDb(); const query: string = 'SELECT chapter_id FROM book_chapters WHERE author_id=? AND book_id=? AND hashed_title=?'; const params: SQLiteValue[] = [userId, bookId, hashedTitle]; const chapter: QueryResult | null = db.get(query, params); return chapter !== null; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de vérifier la duplication du nom.' : 'Unable to verify name duplication.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Inserts a new chapter into the database. * @param chapterId - The chapter identifier * @param userId - The user identifier * @param bookId - The book identifier * @param title - The encrypted chapter title * @param hashedTitle - The hashed chapter title * @param wordsCount - The word count * @param chapterOrder - The chapter order position * @param lang - The language for error messages * @returns The created chapter identifier */ public static insertChapter(chapterId: string, userId: string, bookId: string, title: string, hashedTitle: string, wordsCount: number, chapterOrder: number, lang: 'fr' | 'en' = 'fr'): string { let insertResult: RunResult; try { const db: Database = System.getDb(); const query: string = 'INSERT INTO book_chapters (chapter_id, author_id, book_id, title, hashed_title, words_count, chapter_order, last_update) VALUES (?,?,?,?,?,?,?,?)'; const params: SQLiteValue[] = [chapterId, userId, bookId, title, hashedTitle, wordsCount, chapterOrder, System.timeStampInSeconds()]; insertResult = db.run(query, params); } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? "Impossible d'ajouter le chapitre." : 'Unable to add chapter.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } if (!insertResult || insertResult.changes === 0) { throw new Error(lang === 'fr' ? "Une erreur s'est passé lors de l'ajout du chapitre." : 'Error adding chapter.'); } return chapterId; } /** * Retrieves all chapters with their act information for a book. * @param userId - The user identifier * @param bookId - The book identifier * @param lang - The language for error messages * @returns List of chapters with act information */ public static fetchAllChapterForActs(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): ActChapterQuery[] { try { const db: Database = System.getDb(); const query: string = 'SELECT ci.chapter_info_id AS chapter_info_id, ci.chapter_id AS chapter_id, chapter.title, chapter.chapter_order, ci.act_id, ci.incident_id AS incident_id, ci.plot_point_id AS plot_point_id, ci.summary, ci.goal FROM book_chapter_infos AS ci INNER JOIN book_chapters AS chapter ON chapter.chapter_id = ci.chapter_id WHERE ci.book_id = ? AND ci.author_id = ?'; const params: SQLiteValue[] = [bookId, userId]; return db.all(query, params) as ActChapterQuery[]; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de récupérer les chapitres pour les actes.' : 'Unable to retrieve chapters for acts.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Retrieves all chapters from a book ordered by chapter order. * @param userId - The user identifier * @param bookId - The book identifier * @param lang - The language for error messages * @returns List of chapters */ public static fetchAllChapterFromABook(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): ChapterQueryResult[] { try { const db: Database = System.getDb(); const query: string = 'SELECT chapter_id, title, chapter_order FROM book_chapters WHERE book_id=? AND author_id=? ORDER BY chapter_order'; const params: SQLiteValue[] = [bookId, userId]; return db.all(query, params) as ChapterQueryResult[]; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de récupérer les chapitres.' : 'Unable to retrieve chapters.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Deletes a chapter from the database. * @param userId - The user identifier * @param chapterId - The chapter identifier to delete * @param lang - The language for error messages * @returns true if the deletion was successful */ public static deleteChapter(userId: string, chapterId: string, lang: 'fr' | 'en' = 'fr'): boolean { try { const db: Database = System.getDb(); const query: string = 'DELETE FROM book_chapters WHERE author_id=? AND chapter_id=?'; const params: SQLiteValue[] = [userId, chapterId]; const deleteResult: RunResult = db.run(query, params); return deleteResult.changes > 0; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de supprimer le chapitre.' : 'Unable to delete chapter.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Inserts chapter information linking a chapter to an act. * @param chapterInfoId - The chapter info identifier * @param userId - The user identifier * @param chapterId - The chapter identifier * @param actId - The act identifier * @param bookId - The book identifier * @param plotId - The plot point identifier (optional) * @param incidentId - The incident identifier (optional) * @param lang - The language for error messages * @returns The created chapter info identifier */ static insertChapterInformation(chapterInfoId: string, userId: string, chapterId: string, actId: number, bookId: string, plotId: string | null, incidentId: string | null, lang: 'fr' | 'en' = 'fr'): string { let existingChapter: QueryResult | null; let insertResult: RunResult; try { const db: Database = System.getDb(); const checkQuery: string = 'SELECT chapter_info_id FROM book_chapter_infos WHERE chapter_id=? AND act_id=? AND book_id=? AND plot_point_id=? AND incident_id=? AND author_id=?'; const checkParams: SQLiteValue[] = [chapterId, actId, bookId, plotId, incidentId, userId]; existingChapter = db.get(checkQuery, checkParams); } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? "Impossible de vérifier l'existence de l'information du chapitre." : 'Unable to verify chapter information existence.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } if (existingChapter !== null) { throw new Error(lang === 'fr' ? 'Le chapitre est déjà lié.' : 'Chapter is already linked.'); } try { const db: Database = System.getDb(); const query: string = 'INSERT INTO book_chapter_infos (chapter_info_id, chapter_id, act_id, book_id, author_id, incident_id, plot_point_id, summary, goal, last_update) VALUES (?,?,?,?,?,?,?,?,?,?)'; const params: SQLiteValue[] = [chapterInfoId, chapterId, actId, bookId, userId, incidentId, plotId, '', '', System.timeStampInSeconds()]; insertResult = db.run(query, params); } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? "Impossible d'ajouter l'information du chapitre." : 'Unable to add chapter information.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } if (!insertResult || insertResult.changes === 0) { throw new Error(lang === 'fr' ? "Une erreur s'est produite pendant la liaison du chapitre." : 'Error linking chapter.'); } return chapterInfoId; } /** * Updates a chapter's basic information. * @param userId - The user identifier * @param chapterId - The chapter identifier * @param encryptedTitle - The encrypted title * @param hashTitle - The hashed title * @param chapterOrder - The chapter order position * @param lastUpdate - The last update timestamp * @param lang - The language for error messages * @returns true if the update was successful */ public static updateChapter(userId: string, chapterId: string, encryptedTitle: string, hashTitle: string, chapterOrder: number, lastUpdate: number, lang: 'fr' | 'en' = 'fr'): boolean { try { const db: Database = System.getDb(); const query: string = 'UPDATE book_chapters SET title=?, hashed_title=?, chapter_order=?, last_update=? WHERE author_id=? AND chapter_id=?'; const params: SQLiteValue[] = [encryptedTitle, hashTitle, chapterOrder, lastUpdate, userId, chapterId]; const updateResult: RunResult = db.run(query, params); return updateResult.changes > 0; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de mettre à jour le chapitre.' : 'Unable to update chapter.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Updates chapter information (summary and goal). * @param userId - The user identifier * @param chapterId - The chapter identifier * @param actId - The act identifier * @param bookId - The book identifier * @param incidentId - The incident identifier (optional) * @param plotId - The plot point identifier (optional) * @param summary - The chapter summary * @param goal - The chapter goal * @param lastUpdate - The last update timestamp * @param lang - The language for error messages * @returns true if the update was successful */ public static updateChapterInfos(userId: string, chapterId: string, actId: number, bookId: string, incidentId: string | null, plotId: string | null, summary: string, goal: string | null, lastUpdate: number, lang: 'fr' | 'en' = 'fr'): boolean { try { const db: Database = System.getDb(); let query: string = 'UPDATE book_chapter_infos SET summary=?,goal=?,last_update=? WHERE chapter_id = ? AND act_id = ? AND book_id = ?'; const params: SQLiteValue[] = [summary, goal, lastUpdate, chapterId, actId, bookId]; if (incidentId) { query += ' AND incident_id=?'; params.push(incidentId); } else { query += ' AND incident_id IS NULL'; } if (plotId) { query += ' AND plot_point_id=?'; params.push(plotId); } else { query += ' AND plot_point_id IS NULL'; } query += ' AND author_id=?'; params.push(userId); const updateResult: RunResult = db.run(query, params); return updateResult.changes > 0; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de mettre à jour les informations du chapitre.' : 'Unable to update chapter information.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Retrieves the last opened chapter for a book. * @param userId - The user identifier * @param bookId - The book identifier * @param lang - The language for error messages * @returns The last chapter information or null */ public static fetchLastChapter(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): LastChapterResult | null { try { const db: Database = System.getDb(); const query: string = 'SELECT chapter_id as chapter_id,version FROM user_last_chapter WHERE user_id=? AND book_id=?'; const params: SQLiteValue[] = [userId, bookId]; return db.get(query, params) as LastChapterResult | null; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de récupérer le dernier chapitre ouvert.' : 'Unable to retrieve last opened chapter.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Updates or inserts the last chapter record for a user. * @param userId - The user identifier * @param bookId - The book identifier * @param chapterId - The chapter identifier * @param version - The chapter version * @param lang - The language for error messages * @returns true if the operation was successful */ public static updateLastChapterRecord(userId: string, bookId: string, chapterId: string, version: number, lang: 'fr' | 'en' = 'fr'): boolean { try { const db: Database = System.getDb(); const updateQuery: string = 'UPDATE user_last_chapter SET chapter_id=?, version=? WHERE user_id=? AND book_id=?'; const updateParams: SQLiteValue[] = [chapterId, version, userId, bookId]; const updateResult: RunResult = db.run(updateQuery, updateParams); if (updateResult.changes > 0) { return true; } const insertQuery: string = 'INSERT INTO user_last_chapter (user_id, book_id, chapter_id, version) VALUES (?,?,?,?)'; const insertParams: SQLiteValue[] = [userId, bookId, chapterId, version]; const insertResult: RunResult = db.run(insertQuery, insertParams); return insertResult.changes > 0; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? "Impossible d'enregistrer le dernier chapitre." : 'Unable to save last chapter.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Retrieves chapter story information including act, incident, and plot point data. * @param userId - The user identifier * @param chapterId - The chapter identifier * @param lang - The language for error messages * @returns List of chapter story information */ public static fetchChapterStory(userId: string, chapterId: string, lang: 'fr' | 'en' = 'fr'): ChapterStoryQueryResult[] { try { const db: Database = System.getDb(); const query: string = 'SELECT chapter_info_id, chapter.act_id, act_sum.summary, chapter.summary AS chapter_summary, chapter.goal AS chapter_goal, chapter.incident_id, incident.title AS incident_title, incident.summary AS incident_summary, chapter.plot_point_id, plot.title AS plot_title, plot.summary AS plot_summary FROM book_chapter_infos AS chapter LEFT JOIN book_incidents AS incident ON chapter.incident_id=incident.incident_id LEFT JOIN book_plot_points AS plot ON chapter.plot_point_id=plot.plot_point_id LEFT JOIN book_act_summaries AS act_sum ON chapter.act_id=act_sum.act_sum_id AND chapter.book_id=act_sum.book_id WHERE chapter.chapter_id=? AND chapter.author_id=?'; const params: SQLiteValue[] = [chapterId, userId]; return db.all(query, params) as ChapterStoryQueryResult[]; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? "Impossible de récupérer l'histoire du chapitre." : 'Unable to retrieve chapter story.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Deletes chapter information by its identifier. * @param userId - The user identifier * @param chapterInfoId - The chapter info identifier to delete * @param lang - The language for error messages * @returns true if the deletion was successful */ static deleteChapterInformation(userId: string, chapterInfoId: string, lang: 'fr' | 'en' = 'fr'): boolean { try { const db: Database = System.getDb(); const query: string = 'DELETE FROM book_chapter_infos WHERE chapter_info_id=? AND author_id=?'; const params: SQLiteValue[] = [chapterInfoId, userId]; const deleteResult: RunResult = db.run(query, params); return deleteResult.changes > 0; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de supprimer les informations du chapitre.' : 'Unable to delete chapter information.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Checks if a chapter exists. * @param userId - The user identifier * @param chapterId - The chapter identifier * @param lang - The language for error messages * @returns true if the chapter exists */ static isChapterExist(userId: string, chapterId: string, lang: 'fr' | 'en'): boolean { try { const db: Database = System.getDb(); const query: string = 'SELECT 1 FROM book_chapters WHERE chapter_id=? AND author_id=?'; const params: SQLiteValue[] = [chapterId, userId]; const chapter: QueryResult | null = db.get(query, params) || null; return chapter !== null; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? "Impossible de vérifier l'existence du chapitre." : 'Unable to check chapter existence.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Checks if chapter info exists. * @param userId - The user identifier * @param chapterId - The chapter identifier * @param lang - The language for error messages * @returns true if the chapter info exists */ static isChapterInfoExist(userId: string, chapterId: string, lang: 'fr' | 'en'): boolean { try { const db: Database = System.getDb(); const query: string = 'SELECT 1 FROM book_chapter_infos WHERE chapter_id=? AND author_id=?'; const params: SQLiteValue[] = [chapterId, userId]; const chapterInfo: QueryResult | null = db.get(query, params) || null; return chapterInfo !== null; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? "Impossible de vérifier l'existence des informations du chapitre." : 'Unable to check chapter info existence.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Retrieves complete book chapters with their content. * @param bookId - The book identifier * @param lang - The language for error messages * @returns List of chapters with content */ static fetchCompleteBookChapters(bookId: string, lang: 'fr' | 'en'): ChapterBookResult[] { let chapters: ChapterBookResult[]; try { const db: Database = System.getDb(); const query: string = 'SELECT title, chapter_order, content.content FROM book_chapters AS chapter LEFT JOIN book_chapter_content AS content ON chapter.chapter_id = content.chapter_id AND content.version = (SELECT MAX(version) FROM book_chapter_content WHERE chapter_id = chapter.chapter_id AND version > 1) WHERE chapter.book_id = ? ORDER BY chapter.chapter_order'; const params: SQLiteValue[] = [bookId]; chapters = db.all(query, params) as ChapterBookResult[]; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de récupérer les chapitres.' : 'Unable to retrieve chapters.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } if (chapters.length === 0) { throw new Error(lang === 'fr' ? 'Aucun chapitre trouvé.' : 'No chapters found.'); } return chapters; } /** * Retrieves all chapters for a book. * @param userId - The user identifier * @param bookId - The book identifier * @param lang - The language for error messages * @returns List of book chapters */ static async fetchBookChapters(userId: string, bookId: string, lang: 'fr' | 'en'): Promise { try { const db: Database = System.getDb(); const query: string = 'SELECT chapter_id, book_id, author_id, title, hashed_title, words_count, chapter_order, last_update FROM book_chapters WHERE author_id=? AND book_id=?'; const params: SQLiteValue[] = [userId, bookId]; return db.all(query, params) as BookChaptersTable[]; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de récupérer les chapitres.' : 'Unable to retrieve chapters.'); } throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Retrieves chapter information for a specific chapter. * @param userId - The user identifier * @param chapterId - The chapter identifier * @param lang - The language for error messages * @returns List of chapter info records */ static async fetchBookChapterInfos(userId: string, chapterId: string, lang: 'fr' | 'en'): Promise { try { const db: Database = System.getDb(); const query: string = 'SELECT chapter_info_id, chapter_id, act_id, incident_id, plot_point_id, book_id, author_id, summary, goal, last_update FROM book_chapter_infos WHERE author_id=? AND chapter_id=?'; const params: SQLiteValue[] = [userId, chapterId]; return db.all(query, params) as BookChapterInfosTable[]; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de récupérer les infos des chapitres.' : 'Unable to retrieve chapter infos.'); } throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Retrieves synced chapters for a user. * @param userId - The user identifier * @param lang - The language for error messages * @returns List of synced chapters */ static fetchSyncedChapters(userId: string, lang: 'fr' | 'en'): SyncedChapterResult[] { try { const db: Database = System.getDb(); const query: string = 'SELECT chapter_id, book_id, title, last_update FROM book_chapters WHERE author_id = ?'; const params: SQLiteValue[] = [userId]; return db.all(query, params) as SyncedChapterResult[]; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de récupérer les chapitres synchronisés.' : 'Unable to retrieve synced chapters.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Retrieves synced chapter infos for a user. * @param userId - The user identifier * @param lang - The language for error messages * @returns List of synced chapter infos */ static fetchSyncedChapterInfos(userId: string, lang: 'fr' | 'en'): SyncedChapterInfoResult[] { try { const db: Database = System.getDb(); const query: string = 'SELECT chapter_info_id, chapter_id, book_id, last_update FROM book_chapter_infos WHERE author_id = ?'; const params: SQLiteValue[] = [userId]; return db.all(query, params) as SyncedChapterInfoResult[]; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? 'Impossible de récupérer les infos des chapitres synchronisés.' : 'Unable to retrieve synced chapter infos.'); } console.error("An unknown error occurred."); throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Inserts a synced chapter from the server. * @param chapterId - The chapter identifier * @param bookId - The book identifier * @param authorId - The author identifier * @param title - The encrypted title * @param hashedTitle - The hashed title * @param wordsCount - The word count * @param chapterOrder - The chapter order * @param lastUpdate - The last update timestamp * @param lang - The language for error messages * @returns true if the insertion was successful */ static insertSyncChapter(chapterId: string, bookId: string, authorId: string, title: string, hashedTitle: string | null, wordsCount: number | null, chapterOrder: number | null, lastUpdate: number, lang: 'fr' | 'en'): boolean { try { const db: Database = System.getDb(); const query: string = 'INSERT INTO book_chapters (chapter_id, book_id, author_id, title, hashed_title, words_count, chapter_order, last_update) VALUES (?, ?, ?, ?, ?, ?, ?, ?)'; const params: SQLiteValue[] = [chapterId, bookId, authorId, title, hashedTitle, wordsCount, chapterOrder, lastUpdate]; const insertResult: RunResult = db.run(query, params); return insertResult.changes > 0; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? "Impossible d'insérer le chapitre." : 'Unable to insert chapter.'); } throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Inserts synced chapter info from the server. * @param chapterInfoId - The chapter info identifier * @param chapterId - The chapter identifier * @param actId - The act identifier * @param incidentId - The incident identifier * @param plotPointId - The plot point identifier * @param bookId - The book identifier * @param authorId - The author identifier * @param summary - The chapter summary * @param goal - The chapter goal * @param lastUpdate - The last update timestamp * @param lang - The language for error messages * @returns true if the insertion was successful */ static insertSyncChapterInfo(chapterInfoId: string, chapterId: string, actId: number | null, incidentId: string | null, plotPointId: string | null, bookId: string, authorId: string, summary: string | null, goal: string | null, lastUpdate: number, lang: 'fr' | 'en'): boolean { try { const db: Database = System.getDb(); const query: string = 'INSERT INTO book_chapter_infos (chapter_info_id, chapter_id, act_id, incident_id, plot_point_id, book_id, author_id, summary, goal, last_update) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; const params: SQLiteValue[] = [chapterInfoId, chapterId, actId, incidentId, plotPointId, bookId, authorId, summary, goal, lastUpdate]; const insertResult: RunResult = db.run(query, params); return insertResult.changes > 0; } catch (error: unknown) { if (error instanceof Error) { console.error(`DB Error: ${error.message}`); throw new Error(lang === 'fr' ? "Impossible d'insérer les infos du chapitre." : 'Unable to insert chapter info.'); } throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Retrieves a complete chapter by its identifier. * @param chapterId - The chapter identifier * @param lang - The language for error messages * @returns The complete chapter data */ static async fetchCompleteChapterById(chapterId: string, lang: 'fr' | 'en'): Promise { try { const db: Database = System.getDb(); const query: string = 'SELECT chapter_id, book_id, author_id, title, hashed_title, words_count, chapter_order, last_update FROM book_chapters WHERE chapter_id = ?'; const params: SQLiteValue[] = [chapterId]; return db.all(query, params) as BookChaptersTable[]; } catch (error: unknown) { if (error instanceof Error) { throw new Error(lang === 'fr' ? 'Impossible de récupérer le chapitre complet.' : 'Unable to retrieve complete chapter.'); } throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } /** * Retrieves complete chapter info by its identifier. * @param chapterInfoId - The chapter info identifier * @param lang - The language for error messages * @returns The complete chapter info data */ static async fetchCompleteChapterInfoById(chapterInfoId: string, lang: 'fr' | 'en'): Promise { try { const db: Database = System.getDb(); const query: string = 'SELECT chapter_info_id, chapter_id, act_id, incident_id, plot_point_id, book_id, author_id, summary, goal, last_update FROM book_chapter_infos WHERE chapter_info_id = ?'; const params: SQLiteValue[] = [chapterInfoId]; return db.all(query, params) as BookChapterInfosTable[]; } catch (error: unknown) { if (error instanceof Error) { throw new Error(lang === 'fr' ? 'Impossible de récupérer les informations de chapitre complètes.' : 'Unable to retrieve complete chapter info.'); } throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred."); } } }