- Add JSDoc comments for better maintainability and code clarity in `BookRepo` methods. - Streamline query definitions using variables to improve readability. - Consolidate error handling logic across all methods. - Ensure multilingual support in error messages for consistent user feedback. - Remove redundant error branches and simplify unknown error processing.
364 lines
18 KiB
TypeScript
364 lines
18 KiB
TypeScript
import {Database, QueryResult, RunResult, SQLiteValue} from 'node-sqlite3-wasm';
|
|
import System from "../System.js";
|
|
|
|
export interface BookQuery extends Record<string, SQLiteValue> {
|
|
book_id: string;
|
|
type: string;
|
|
author_id: string;
|
|
title: string;
|
|
hashed_title: string;
|
|
sub_title: string | null;
|
|
hashed_sub_title: string | null;
|
|
summary: string | null;
|
|
serie_id: number | null;
|
|
desired_release_date: string | null;
|
|
desired_word_count: number | null;
|
|
words_count: number | null;
|
|
cover_image: string | null;
|
|
}
|
|
|
|
export interface EritBooksTable extends Record<string, SQLiteValue> {
|
|
book_id: string;
|
|
type: string;
|
|
author_id: string;
|
|
title: string;
|
|
hashed_title: string;
|
|
sub_title: string | null;
|
|
hashed_sub_title: string | null;
|
|
summary: string | null;
|
|
serie_id: number | null;
|
|
desired_release_date: string | null;
|
|
desired_word_count: number | null;
|
|
words_count: number | null;
|
|
last_update: number;
|
|
cover_image: string | null;
|
|
}
|
|
|
|
export interface SyncedBookResult extends Record<string, SQLiteValue> {
|
|
book_id: string;
|
|
type: string;
|
|
title: string;
|
|
sub_title: string | null;
|
|
last_update: number;
|
|
}
|
|
|
|
export interface BookCoverQuery extends Record<string, SQLiteValue> {
|
|
cover_image: string;
|
|
}
|
|
|
|
export default class BookRepo {
|
|
/**
|
|
* Retrieves all books for a user.
|
|
* @param userId - The user identifier
|
|
* @param lang - The language for error messages
|
|
* @returns List of user's books
|
|
*/
|
|
public static fetchBooks(userId: string, lang: 'fr' | 'en'): BookQuery[] {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'SELECT book_id, type, author_id, title, sub_title, summary, serie_id, desired_release_date, desired_word_count, words_count, cover_image FROM erit_books WHERE author_id = ? ORDER BY book_id DESC';
|
|
const params: SQLiteValue[] = [userId];
|
|
return db.all(query, params) as BookQuery[];
|
|
} catch (error: unknown) {
|
|
if (error instanceof Error) {
|
|
console.error(error.message);
|
|
throw new Error(lang === 'fr' ? 'Impossible de récupérer la liste des livres.' : 'Unable to retrieve book list.');
|
|
}
|
|
console.error(error);
|
|
throw new Error(lang === 'fr' ? 'Une erreur inconnue est survenue.' : 'An unknown error occurred.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates a book's cover image.
|
|
* @param bookId - The book identifier
|
|
* @param coverImageName - The cover image file name
|
|
* @param userId - The user identifier
|
|
* @param lang - The language for error messages
|
|
* @returns true if the update was successful
|
|
*/
|
|
public static updateBookCover(bookId: string, coverImageName: string, userId: string, lang: 'fr' | 'en'): boolean {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'UPDATE erit_books SET cover_image=?, last_update=? WHERE book_id=? AND author_id=?';
|
|
const params: SQLiteValue[] = [coverImageName, System.timeStampInSeconds(), bookId, 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 la couverture du livre.' : 'Unable to update book cover.');
|
|
}
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves a book by its identifier.
|
|
* @param bookId - The book identifier
|
|
* @param userId - The user identifier
|
|
* @param lang - The language for error messages
|
|
* @returns The book information
|
|
*/
|
|
public static fetchBook(bookId: string, userId: string, lang: 'fr' | 'en'): BookQuery {
|
|
let book: BookQuery;
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'SELECT book_id, author_id, title, summary, sub_title, cover_image, desired_release_date, desired_word_count, words_count FROM erit_books WHERE book_id=? AND author_id=?';
|
|
const params: SQLiteValue[] = [bookId, userId];
|
|
book = db.get(query, params) as BookQuery;
|
|
} catch (error: unknown) {
|
|
if (error instanceof Error) {
|
|
console.error(`DB Error: ${error.message}`);
|
|
throw new Error(lang === 'fr' ? 'Impossible de récupérer les informations du livre.' : 'Unable to retrieve book information.');
|
|
}
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
if (!book) {
|
|
throw new Error(lang === 'fr' ? 'Livre non trouvé.' : 'Book not found.');
|
|
}
|
|
return book;
|
|
}
|
|
|
|
/**
|
|
* Verifies if a book already exists for a user.
|
|
* @param hashedTitle - The hashed book title
|
|
* @param hashedSubTitle - The hashed book subtitle
|
|
* @param userId - The user identifier
|
|
* @param lang - The language for error messages
|
|
* @returns true if the book exists
|
|
*/
|
|
public static verifyBookExist(hashedTitle: string, hashedSubTitle: string, userId: string, lang: 'fr' | 'en'): boolean {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'SELECT book_id FROM erit_books WHERE hashed_title=? AND author_id=? AND hashed_sub_title=?';
|
|
const params: SQLiteValue[] = [hashedTitle, userId, hashedSubTitle];
|
|
const book: QueryResult | null = db.get(query, params);
|
|
return book !== 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 livre." : 'Unable to verify book existence.');
|
|
}
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Inserts a new book into the database.
|
|
* @param bookId - The book identifier
|
|
* @param userId - The user identifier
|
|
* @param encryptedTitle - The encrypted title
|
|
* @param hashedTitle - The hashed title
|
|
* @param encryptedSubTitle - The encrypted subtitle
|
|
* @param hashedSubTitle - The hashed subtitle
|
|
* @param encryptedSummary - The encrypted summary
|
|
* @param type - The book type
|
|
* @param serie - The series identifier
|
|
* @param publicationDate - The desired publication date
|
|
* @param desiredWordCount - The desired word count
|
|
* @param lang - The language for error messages
|
|
* @returns The created book identifier
|
|
*/
|
|
public static insertBook(bookId: string, userId: string, encryptedTitle: string, hashedTitle: string, encryptedSubTitle: string, hashedSubTitle: string, encryptedSummary: string, type: string, serie: number, publicationDate: string, desiredWordCount: number, lang: 'fr' | 'en'): string {
|
|
let insertResult: RunResult;
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'INSERT INTO erit_books (book_id, type, author_id, title, hashed_title, sub_title, hashed_sub_title, summary, serie_id, desired_release_date, desired_word_count, last_update) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)';
|
|
const params: SQLiteValue[] = [bookId, type, userId, encryptedTitle, hashedTitle, encryptedSubTitle, hashedSubTitle, encryptedSummary, serie, publicationDate ? publicationDate : null, desiredWordCount, 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 livre." : 'Unable to add book.');
|
|
}
|
|
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' ? "Erreur lors de l'ajout du livre." : 'Error adding book.');
|
|
}
|
|
return bookId;
|
|
}
|
|
|
|
/**
|
|
* Retrieves a book's cover image.
|
|
* @param userId - The user identifier
|
|
* @param bookId - The book identifier
|
|
* @param lang - The language for error messages
|
|
* @returns The cover information
|
|
*/
|
|
public static fetchBookCover(userId: string, bookId: string, lang: 'fr' | 'en'): BookCoverQuery {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'SELECT cover_image FROM erit_books WHERE author_id=? AND book_id=?';
|
|
const params: SQLiteValue[] = [userId, bookId];
|
|
return db.get(query, params) as BookCoverQuery;
|
|
} catch (error: unknown) {
|
|
if (error instanceof Error) {
|
|
console.error(`DB Error: ${error.message}`);
|
|
throw new Error(lang === 'fr' ? 'Impossible de récupérer la couverture du livre.' : 'Unable to retrieve book cover.');
|
|
}
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates a book's basic information.
|
|
* @param userId - The user identifier
|
|
* @param title - The new title
|
|
* @param hashedTitle - The hashed title
|
|
* @param subTitle - The new subtitle
|
|
* @param hashedSubTitle - The hashed subtitle
|
|
* @param summary - The new summary
|
|
* @param publicationDate - The new publication date
|
|
* @param wordCount - The new desired word count
|
|
* @param bookId - The book identifier
|
|
* @param lang - The language for error messages
|
|
* @returns true if the update was successful
|
|
*/
|
|
static updateBookBasicInformation(userId: string, title: string, hashedTitle: string, subTitle: string, hashedSubTitle: string, summary: string, publicationDate: string, wordCount: number, bookId: string, lang: 'fr' | 'en'): boolean {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'UPDATE erit_books SET title=?, hashed_title=?, sub_title=?, hashed_sub_title=?, summary=?, serie_id=?, desired_release_date=?, desired_word_count=?, last_update=? WHERE author_id=? AND book_id=?';
|
|
const params: SQLiteValue[] = [title, hashedTitle, subTitle, hashedSubTitle, summary, 0, publicationDate ? System.dateToMySqlDate(publicationDate) : null, wordCount, System.timeStampInSeconds(), userId, bookId];
|
|
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 livre.' : 'Unable to update book information.');
|
|
}
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes a book from the database.
|
|
* @param userId - The user identifier
|
|
* @param bookId - The book identifier to delete
|
|
* @param lang - The language for error messages
|
|
* @returns true if the deletion was successful
|
|
*/
|
|
public static deleteBook(userId: string, bookId: string, lang: 'fr' | 'en'): boolean {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'DELETE FROM erit_books WHERE author_id=? AND book_id=?';
|
|
const params: SQLiteValue[] = [userId, bookId];
|
|
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 livre.' : 'Unable to delete book.');
|
|
}
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves all columns from erit_books table for a book.
|
|
* @param userId - The user identifier
|
|
* @param bookId - The book identifier
|
|
* @param lang - The language for error messages
|
|
* @returns The complete book data
|
|
*/
|
|
static async fetchEritBooksTable(userId: string, bookId: string, lang: 'fr' | 'en'): Promise<EritBooksTable[]> {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'SELECT 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 FROM erit_books WHERE book_id=? AND author_id=?';
|
|
const params: SQLiteValue[] = [bookId, userId];
|
|
return db.all(query, params) as EritBooksTable[];
|
|
} catch (error: unknown) {
|
|
if (error instanceof Error) {
|
|
console.error(`DB Error: ${error.message}`);
|
|
throw new Error(lang === 'fr' ? 'Impossible de récupérer les informations du livre.' : 'Unable to retrieve book information.');
|
|
}
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves synced books for a user.
|
|
* @param userId - The user identifier
|
|
* @param lang - The language for error messages
|
|
* @returns List of books with sync information
|
|
*/
|
|
static fetchSyncedBooks(userId: string, lang: 'fr' | 'en'): SyncedBookResult[] {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'SELECT book_id, type, title, sub_title, last_update FROM erit_books WHERE author_id = ?';
|
|
const params: SQLiteValue[] = [userId];
|
|
return db.all(query, params) as SyncedBookResult[];
|
|
} catch (error: unknown) {
|
|
if (error instanceof Error) {
|
|
console.error(`DB Error: ${error.message}`);
|
|
throw new Error(lang === 'fr' ? 'Impossible de récupérer les livres synchronisés.' : 'Unable to retrieve synced books.');
|
|
}
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Inserts a synced book from the server.
|
|
* @param bookId - The book identifier
|
|
* @param userId - The user identifier
|
|
* @param type - The book type
|
|
* @param title - The encrypted title
|
|
* @param hashedTitle - The hashed title
|
|
* @param subTitle - The encrypted subtitle
|
|
* @param hashedSubTitle - The hashed subtitle
|
|
* @param summary - The encrypted summary
|
|
* @param serieId - The series identifier
|
|
* @param desiredReleaseDate - The desired release date
|
|
* @param desiredWordCount - The desired word count
|
|
* @param wordsCount - The current word count
|
|
* @param coverImage - The cover image file name
|
|
* @param lastUpdate - The last update timestamp
|
|
* @param lang - The language for error messages
|
|
* @returns true if the insertion was successful
|
|
*/
|
|
static insertSyncBook(bookId: string, userId: string, type: string, title: string, hashedTitle: string, subTitle: string | null, hashedSubTitle: string | null, summary: string | null, serieId: number | null, desiredReleaseDate: string | null, desiredWordCount: number | null, wordsCount: number | null, coverImage: string | null, lastUpdate: number, lang: 'fr' | 'en'): boolean {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'INSERT INTO erit_books (book_id, author_id, type, title, hashed_title, sub_title, hashed_sub_title, summary, serie_id, desired_release_date, desired_word_count, words_count, cover_image, last_update) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
|
const params: SQLiteValue[] = [bookId, userId, type, title, hashedTitle, subTitle, hashedSubTitle, summary, serieId, desiredReleaseDate, desiredWordCount, wordsCount, coverImage, 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 livre synchronisé." : 'Unable to insert synced book.');
|
|
}
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves a complete book by its identifier (without author verification).
|
|
* @param bookId - The book identifier
|
|
* @param lang - The language for error messages
|
|
* @returns The complete book data
|
|
*/
|
|
static async fetchCompleteBookById(bookId: string, lang: 'fr' | 'en'): Promise<EritBooksTable[]> {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const query: string = 'SELECT * FROM erit_books WHERE book_id = ?';
|
|
const params: SQLiteValue[] = [bookId];
|
|
return db.all(query, params) as EritBooksTable[];
|
|
} catch (error: unknown) {
|
|
if (error instanceof Error) {
|
|
throw new Error(lang === 'fr' ? 'Impossible de récupérer le livre complet.' : 'Unable to retrieve complete book.');
|
|
}
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
} |