Refactor BookRepo methods and improve error handling
- 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.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import {Database, QueryResult, RunResult, SQLiteValue} from "node-sqlite3-wasm";
|
||||
import { Database, QueryResult, RunResult, SQLiteValue } from "node-sqlite3-wasm";
|
||||
import System from "@/electron/database/System";
|
||||
|
||||
export interface BookIssuesTable extends Record<string, SQLiteValue> {
|
||||
@@ -23,13 +23,23 @@ export interface IssueQuery extends Record<string, SQLiteValue> {
|
||||
}
|
||||
|
||||
export default class IssueRepository {
|
||||
public static fetchIssuesFromBook(userId:string,bookId:string, lang: 'fr' | 'en'):IssueQuery[]{
|
||||
/**
|
||||
* Fetches all issues associated with a specific book.
|
||||
* @param userId - The unique identifier of the user/author.
|
||||
* @param bookId - The unique identifier of the book.
|
||||
* @param lang - The language for error messages ('fr' or 'en').
|
||||
* @returns An array of issues with their IDs and names.
|
||||
*/
|
||||
public static fetchIssuesFromBook(userId: string, bookId: string, lang: 'fr' | 'en'): IssueQuery[] {
|
||||
try {
|
||||
const db: Database = System.getDb();
|
||||
return db.all('SELECT issue_id, name FROM book_issues WHERE author_id=? AND book_id=?', [userId, bookId]) as IssueQuery[];
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.error(`DB Error: ${e.message}`);
|
||||
const query: string = 'SELECT issue_id, name FROM book_issues WHERE author_id=? AND book_id=?';
|
||||
const params: SQLiteValue[] = [userId, bookId];
|
||||
const issues: IssueQuery[] = db.all(query, params) as IssueQuery[];
|
||||
return issues;
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`DB Error: ${error.message}`);
|
||||
throw new Error(lang === 'fr' ? `Impossible de récupérer les problématiques.` : `Unable to retrieve issues.`);
|
||||
} else {
|
||||
console.error("An unknown error occurred.");
|
||||
@@ -37,30 +47,45 @@ export default class IssueRepository {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new issue into the database after verifying it doesn't already exist.
|
||||
* @param issueId - The unique identifier for the new issue.
|
||||
* @param userId - The unique identifier of the user/author.
|
||||
* @param bookId - The unique identifier of the book.
|
||||
* @param encryptedName - The encrypted name of the issue.
|
||||
* @param hashedName - The hashed name of the issue for duplicate checking.
|
||||
* @param lang - The language for error messages ('fr' or 'en').
|
||||
* @returns The issue ID if successfully inserted.
|
||||
*/
|
||||
public static insertNewIssue(issueId: string, userId: string, bookId: string, encryptedName: string, hashedName: string, lang: 'fr' | 'en'): string {
|
||||
let existingResult: QueryResult | null;
|
||||
let existingIssue: QueryResult | null;
|
||||
let insertResult: RunResult;
|
||||
try {
|
||||
const db: Database = System.getDb();
|
||||
existingResult = db.get('SELECT issue_id FROM book_issues WHERE hashed_issue_name=? AND book_id=? AND author_id=?', [hashedName, bookId, userId]);
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.error(`DB Error: ${e.message}`);
|
||||
const checkQuery: string = 'SELECT issue_id FROM book_issues WHERE hashed_issue_name=? AND book_id=? AND author_id=?';
|
||||
const checkParams: SQLiteValue[] = [hashedName, bookId, userId];
|
||||
existingIssue = 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 la problématique.` : `Unable to verify issue existence.`);
|
||||
} else {
|
||||
console.error("An unknown error occurred.");
|
||||
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
||||
}
|
||||
}
|
||||
if (existingResult !== null) {
|
||||
if (existingIssue !== null) {
|
||||
throw new Error(lang === 'fr' ? `La problématique existe déjà.` : `This issue already exists.`);
|
||||
}
|
||||
try {
|
||||
const db: Database = System.getDb();
|
||||
insertResult = db.run('INSERT INTO book_issues (issue_id,author_id, book_id, name, hashed_issue_name, last_update) VALUES (?,?,?,?,?,?)', [issueId, userId, bookId, encryptedName, hashedName, System.timeStampInSeconds()]);
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.error(`DB Error: ${e.message}`);
|
||||
const insertQuery: string = 'INSERT INTO book_issues (issue_id, author_id, book_id, name, hashed_issue_name, last_update) VALUES (?, ?, ?, ?, ?, ?)';
|
||||
const insertParams: SQLiteValue[] = [issueId, userId, bookId, encryptedName, hashedName, System.timeStampInSeconds()];
|
||||
insertResult = db.run(insertQuery, insertParams);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`DB Error: ${error.message}`);
|
||||
throw new Error(lang === 'fr' ? `Impossible d'ajouter la problématique.` : `Unable to add issue.`);
|
||||
} else {
|
||||
console.error("An unknown error occurred.");
|
||||
@@ -72,15 +97,24 @@ export default class IssueRepository {
|
||||
}
|
||||
return issueId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes an issue from the database.
|
||||
* @param userId - The unique identifier of the user/author.
|
||||
* @param issueId - The unique identifier of the issue to delete.
|
||||
* @param lang - The language for error messages ('fr' or 'en').
|
||||
* @returns True if the issue was successfully deleted, false otherwise.
|
||||
*/
|
||||
public static deleteIssue(userId: string, issueId: string, lang: 'fr' | 'en'): boolean {
|
||||
try {
|
||||
const db: Database = System.getDb();
|
||||
const result: RunResult = db.run('DELETE FROM book_issues WHERE author_id=? AND issue_id=?', [userId, issueId]);
|
||||
return result.changes > 0;
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.error(`DB Error: ${e.message}`);
|
||||
const query: string = 'DELETE FROM book_issues WHERE author_id=? AND issue_id=?';
|
||||
const params: SQLiteValue[] = [userId, issueId];
|
||||
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 la problématique.` : `Unable to delete issue.`);
|
||||
} else {
|
||||
console.error("An unknown error occurred.");
|
||||
@@ -88,26 +122,47 @@ export default class IssueRepository {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all complete issue records for a specific book.
|
||||
* @param userId - The unique identifier of the user/author.
|
||||
* @param bookId - The unique identifier of the book.
|
||||
* @param lang - The language for error messages ('fr' or 'en').
|
||||
* @returns A promise resolving to an array of complete issue records.
|
||||
*/
|
||||
static async fetchBookIssues(userId: string, bookId: string, lang: 'fr' | 'en'): Promise<BookIssuesTable[]> {
|
||||
try {
|
||||
const db: Database = System.getDb();
|
||||
return db.all('SELECT issue_id, author_id, book_id, name, hashed_issue_name, last_update FROM book_issues WHERE author_id=? AND book_id=?', [userId, bookId]) as BookIssuesTable[];
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.error(`DB Error: ${e.message}`);
|
||||
const query: string = 'SELECT issue_id, author_id, book_id, name, hashed_issue_name, last_update FROM book_issues WHERE author_id=? AND book_id=?';
|
||||
const params: SQLiteValue[] = [userId, bookId];
|
||||
const issues: BookIssuesTable[] = db.all(query, params) as BookIssuesTable[];
|
||||
return issues;
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`DB Error: ${error.message}`);
|
||||
throw new Error(lang === 'fr' ? `Impossible de récupérer les problématiques.` : `Unable to retrieve issues.`);
|
||||
} else {
|
||||
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all synced issues for a specific user.
|
||||
* @param userId - The unique identifier of the user/author.
|
||||
* @param lang - The language for error messages ('fr' or 'en').
|
||||
* @returns An array of synced issue records.
|
||||
*/
|
||||
static fetchSyncedIssues(userId: string, lang: 'fr' | 'en'): SyncedIssueResult[] {
|
||||
try {
|
||||
const db: Database = System.getDb();
|
||||
return db.all('SELECT issue_id, book_id, name, last_update FROM book_issues WHERE author_id = ?', [userId]) as SyncedIssueResult[];
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.error(`DB Error: ${e.message}`);
|
||||
const query: string = 'SELECT issue_id, book_id, name, last_update FROM book_issues WHERE author_id = ?';
|
||||
const params: SQLiteValue[] = [userId];
|
||||
const syncedIssues: SyncedIssueResult[] = db.all(query, params) as SyncedIssueResult[];
|
||||
return syncedIssues;
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`DB Error: ${error.message}`);
|
||||
throw new Error(lang === 'fr' ? `Impossible de récupérer les problématiques synchronisées.` : `Unable to retrieve synced issues.`);
|
||||
} else {
|
||||
console.error("An unknown error occurred.");
|
||||
@@ -115,52 +170,78 @@ export default class IssueRepository {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inserts a synced issue from remote into the local database.
|
||||
* @param issueId - The unique identifier of the issue.
|
||||
* @param authorId - The unique identifier of the author.
|
||||
* @param bookId - The unique identifier of the book.
|
||||
* @param name - The encrypted name of the issue.
|
||||
* @param hashedIssueName - The hashed name of the issue.
|
||||
* @param lastUpdate - The timestamp of the last update.
|
||||
* @param lang - The language for error messages ('fr' or 'en').
|
||||
* @returns True if the issue was successfully inserted, false otherwise.
|
||||
*/
|
||||
static insertSyncIssue(issueId: string, authorId: string, bookId: string, name: string, hashedIssueName: string, lastUpdate: number, lang: 'fr' | 'en'): boolean {
|
||||
try {
|
||||
const db: Database = System.getDb();
|
||||
const result: RunResult = db.run(
|
||||
`INSERT INTO book_issues (issue_id, author_id, book_id, name, hashed_issue_name, last_update)
|
||||
VALUES (?, ?, ?, ?, ?, ?)`,
|
||||
[issueId, authorId, bookId, name, hashedIssueName, lastUpdate]
|
||||
);
|
||||
return result.changes > 0;
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.error(`DB Error: ${e.message}`);
|
||||
const query: string = `INSERT INTO book_issues (issue_id, author_id, book_id, name, hashed_issue_name, last_update) VALUES (?, ?, ?, ?, ?, ?)`;
|
||||
const params: SQLiteValue[] = [issueId, authorId, bookId, name, hashedIssueName, 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 la problématique.` : `Unable to insert issue.`);
|
||||
} else {
|
||||
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
||||
}
|
||||
}
|
||||
}
|
||||
static async fetchCompleteIssueById(id: string, lang: "fr" | "en"):Promise<BookIssuesTable[]> {
|
||||
|
||||
/**
|
||||
* Fetches a complete issue record by its ID.
|
||||
* @param id - The unique identifier of the issue.
|
||||
* @param lang - The language for error messages ('fr' or 'en').
|
||||
* @returns A promise resolving to an array of complete issue records.
|
||||
*/
|
||||
static async fetchCompleteIssueById(id: string, lang: "fr" | "en"): Promise<BookIssuesTable[]> {
|
||||
try {
|
||||
const db: Database = System.getDb();
|
||||
return db.all(
|
||||
`SELECT issue_id, author_id, book_id, name, hashed_issue_name, last_update
|
||||
FROM book_issues
|
||||
WHERE issue_id = ?`,
|
||||
[id]
|
||||
) as BookIssuesTable[];
|
||||
} catch (e:unknown){
|
||||
if (e instanceof Error) {
|
||||
const query: string = `SELECT issue_id, author_id, book_id, name, hashed_issue_name, last_update FROM book_issues WHERE issue_id = ?`;
|
||||
const params: SQLiteValue[] = [id];
|
||||
const issues: BookIssuesTable[] = db.all(query, params) as BookIssuesTable[];
|
||||
return issues;
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(lang === 'fr' ? `Impossible de récupérer le problème complet.` : `Unable to retrieve complete issue.`);
|
||||
} else {
|
||||
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
||||
}
|
||||
}
|
||||
}
|
||||
static updateIssue(userId: string, bookId: string, issueId: string, name: string, hashedName: string, lastUpdate: number, lang: "fr" | "en"):boolean {
|
||||
|
||||
/**
|
||||
* Updates an existing issue in the database.
|
||||
* @param userId - The unique identifier of the user/author.
|
||||
* @param bookId - The unique identifier of the book.
|
||||
* @param issueId - The unique identifier of the issue to update.
|
||||
* @param name - The new encrypted name of the issue.
|
||||
* @param hashedName - The new hashed name of the issue.
|
||||
* @param lastUpdate - The timestamp of the update.
|
||||
* @param lang - The language for error messages ('fr' or 'en').
|
||||
* @returns True if the issue was successfully updated, false otherwise.
|
||||
*/
|
||||
static updateIssue(userId: string, bookId: string, issueId: string, name: string, hashedName: string, lastUpdate: number, lang: "fr" | "en"): boolean {
|
||||
try {
|
||||
const db: Database = System.getDb();
|
||||
const query:string = `UPDATE book_issues SET name = ?, hashed_issue_name = ?, last_update = FROM_UNIXTIME(?) WHERE issue_id = UUID_TO_BIN(?) AND author_id = UUID_TO_BIN(?) AND book_id = UUID_TO_BIN(?)`;
|
||||
const params:(string|number)[] = [name, hashedName, lastUpdate, issueId, userId, bookId];
|
||||
const result:RunResult = db.run(query, params);
|
||||
return result.changes > 0;
|
||||
} catch (e:unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.error(`DB Error: ${e.message}`);
|
||||
const query: string = `UPDATE book_issues SET name = ?, hashed_issue_name = ?, last_update = ? WHERE issue_id = ? AND author_id = ? AND book_id = ?`;
|
||||
const params: SQLiteValue[] = [name, hashedName, lastUpdate, issueId, 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 la problématique.` : `Unable to update issue.`);
|
||||
} else {
|
||||
console.error("An unknown error occurred.");
|
||||
@@ -168,18 +249,29 @@ export default class IssueRepository {
|
||||
}
|
||||
}
|
||||
}
|
||||
static issueExist(userId: string, bookId: string, issue_id: string,lang: "fr" | "en"): boolean {
|
||||
|
||||
/**
|
||||
* Checks if an issue exists in the database.
|
||||
* @param userId - The unique identifier of the user/author.
|
||||
* @param bookId - The unique identifier of the book.
|
||||
* @param issueId - The unique identifier of the issue to check.
|
||||
* @param lang - The language for error messages ('fr' or 'en').
|
||||
* @returns True if the issue exists, false otherwise.
|
||||
*/
|
||||
static issueExist(userId: string, bookId: string, issueId: string, lang: "fr" | "en"): boolean {
|
||||
try {
|
||||
const db: Database = System.getDb();
|
||||
const result: QueryResult | null = db.get('SELECT 1 FROM `book_issues` WHERE `issue_id`=? AND `author_id`=? AND `book_id`=?', [issue_id, userId, bookId]) || null;
|
||||
return result !== null;
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof Error) {
|
||||
console.error(`DB Error: ${e.message}`);
|
||||
const query: string = 'SELECT 1 FROM book_issues WHERE issue_id=? AND author_id=? AND book_id=?';
|
||||
const params: SQLiteValue[] = [issueId, userId, bookId];
|
||||
const existingIssue: QueryResult | null = db.get(query, params) || null;
|
||||
return existingIssue !== 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 problème.` : `Unable to check issue existence.`);
|
||||
} else {
|
||||
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user