- 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.
169 lines
9.0 KiB
TypeScript
169 lines
9.0 KiB
TypeScript
import {Database, RunResult, SQLiteValue} from 'node-sqlite3-wasm';
|
|
import System from "../System.js";
|
|
|
|
export interface CharacterResult extends Record<string, SQLiteValue> {
|
|
character_id: string;
|
|
first_name: string;
|
|
last_name: string;
|
|
title: string;
|
|
category: string;
|
|
image: string;
|
|
role: string;
|
|
biography: string;
|
|
history: string;
|
|
}
|
|
|
|
export interface AttributeResult extends Record<string, SQLiteValue> {
|
|
attr_id: string;
|
|
attribute_name: string;
|
|
attribute_value: string;
|
|
}
|
|
|
|
export interface CompleteCharacterResult extends Record<string, SQLiteValue> {
|
|
character_id: string;
|
|
first_name: string;
|
|
last_name: string;
|
|
category: string;
|
|
title: string;
|
|
role: string;
|
|
biography: string;
|
|
history: string;
|
|
attribute_name: string;
|
|
attribute_value: string;
|
|
}
|
|
|
|
export default class CharacterRepo {
|
|
public static fetchCharacters(userId: string, bookId: string, lang: 'fr' | 'en' = 'fr'): CharacterResult[] {
|
|
let result: CharacterResult[];
|
|
try {
|
|
const db: Database = System.getDb();
|
|
result = db.all('SELECT character_id, first_name, last_name, title, category, image, role, biography, history FROM book_characters WHERE book_id=? AND user_id=?', [bookId, userId]) as CharacterResult[];
|
|
} catch (e: unknown) {
|
|
if (e instanceof Error) {
|
|
console.error(`DB Error: ${e.message}`);
|
|
throw new Error(lang === 'fr' ? `Impossible de récupérer les personnages.` : `Unable to retrieve characters.`);
|
|
} else {
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static addNewCharacter(userId: string, characterId: string, encryptedName: string, encryptedLastName: string, encryptedTitle: string, encryptedCategory: string, encryptedImage: string, encryptedRole: string, encryptedBiography: string, encryptedHistory: string, bookId: string, lang: 'fr' | 'en' = 'fr'): string {
|
|
let result: RunResult;
|
|
try {
|
|
const db: Database = System.getDb();
|
|
result = db.run('INSERT INTO `book_characters` (character_id, book_id, user_id, first_name, last_name, category, title, image, role, biography, history, last_update) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)', [characterId, bookId, userId, encryptedName, encryptedLastName, encryptedCategory, encryptedTitle, encryptedImage, encryptedRole, encryptedBiography, encryptedHistory, System.timeStampInSeconds()]);
|
|
} catch (e: unknown) {
|
|
if (e instanceof Error) {
|
|
console.error(`DB Error: ${e.message}`);
|
|
throw new Error(lang === 'fr' ? `Impossible d'ajouter le personnage.` : `Unable to add character.`);
|
|
} else {
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
if (!result || result.changes === 0) {
|
|
throw new Error(lang === 'fr' ? `Une erreur s'est produite lors de l'ajout du personnage.` : `Error adding character.`);
|
|
}
|
|
return characterId;
|
|
}
|
|
|
|
static insertAttribute(attributeId: string, characterId: string, userId: string, type: string, name: string, lang: 'fr' | 'en' = 'fr'): string {
|
|
let result: RunResult;
|
|
try {
|
|
const db: Database = System.getDb();
|
|
result = db.run('INSERT INTO `book_characters_attributes` (attr_id, character_id, user_id, attribute_name, attribute_value, last_update) VALUES (?,?,?,?,?,?)', [attributeId, characterId, userId, type, name, System.timeStampInSeconds()]);
|
|
} catch (e: unknown) {
|
|
if (e instanceof Error) {
|
|
console.error(`DB Error: ${e.message}`);
|
|
throw new Error(lang === 'fr' ? `Impossible d'ajouter l'attribut.` : `Unable to add attribute.`);
|
|
} else {
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
if (!result || result.changes === 0) {
|
|
throw new Error(lang === 'fr' ? `Une erreur s'est produite lors de l'ajout de l'attribut.` : `Error adding attribute.`);
|
|
}
|
|
return attributeId;
|
|
}
|
|
|
|
static updateCharacter(userId: string, id: number | null, encryptedName: string, encryptedLastName: string, encryptedTitle: string, encryptedCategory: string, encryptedImage: string, encryptedRole: string, encryptedBiography: string, encryptedHistory: string, lang: 'fr' | 'en' = 'fr'): boolean {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const result: RunResult = db.run('UPDATE `book_characters` SET `first_name`=?,`last_name`=?,`title`=?,`category`=?,`image`=?,`role`=?,`biography`=?,`history`=?,`last_update`=? WHERE `character_id`=? AND `user_id`=?', [encryptedName, encryptedLastName, encryptedTitle, encryptedCategory, encryptedImage, encryptedRole, encryptedBiography, encryptedHistory, System.timeStampInSeconds(), id, userId]);
|
|
return result.changes > 0;
|
|
} catch (e: unknown) {
|
|
if (e instanceof Error) {
|
|
console.error(`DB Error: ${e.message}`);
|
|
throw new Error(lang === 'fr' ? `Impossible de mettre à jour le personnage.` : `Unable to update character.`);
|
|
} else {
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
}
|
|
|
|
static deleteAttribute(userId: string, attributeId: string, lang: 'fr' | 'en' = 'fr'): boolean {
|
|
try {
|
|
const db: Database = System.getDb();
|
|
const result: RunResult = db.run('DELETE FROM `book_characters_attributes` WHERE `attr_id`=? AND `user_id`=?', [attributeId, userId]);
|
|
return result.changes > 0;
|
|
} catch (e: unknown) {
|
|
if (e instanceof Error) {
|
|
console.error(`DB Error: ${e.message}`);
|
|
throw new Error(lang === 'fr' ? `Impossible de supprimer l'attribut.` : `Unable to delete attribute.`);
|
|
} else {
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
}
|
|
|
|
static fetchAttributes(characterId: string, userId: string, lang: 'fr' | 'en' = 'fr'): AttributeResult[] {
|
|
let result: AttributeResult[];
|
|
try {
|
|
const db: Database = System.getDb();
|
|
result = db.all('SELECT attr_id, attribute_name, attribute_value FROM book_characters_attributes WHERE character_id=? AND user_id=?', [characterId, userId]) as AttributeResult[];
|
|
} catch (e: unknown) {
|
|
if (e instanceof Error) {
|
|
console.error(`DB Error: ${e.message}`);
|
|
throw new Error(lang === 'fr' ? `Impossible de récupérer les attributs.` : `Unable to retrieve attributes.`);
|
|
} else {
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static fetchCompleteCharacters(userId: string, bookId: string, tags: string[], lang: 'fr' | 'en' = 'fr'): CompleteCharacterResult[] {
|
|
let result: CompleteCharacterResult[];
|
|
try {
|
|
const db: Database = System.getDb();
|
|
let query: string = 'SELECT charac.character_id, first_name, last_name, category, title, role, biography, history, attribute_name, attribute_value FROM book_characters AS charac LEFT JOIN book_characters_attributes AS attr ON charac.character_id=attr.character_id WHERE charac.user_id=? AND charac.book_id=?';
|
|
let values: any[] = [userId, bookId];
|
|
if (tags && tags.length > 0) {
|
|
const placeholders: string = tags.map((): string => '?').join(',');
|
|
query += ` AND charac.character_id IN (${placeholders})`;
|
|
values.push(...tags);
|
|
}
|
|
result = db.all(query, values) as CompleteCharacterResult[];
|
|
} catch (e: unknown) {
|
|
if (e instanceof Error) {
|
|
console.error(`DB Error: ${e.message}`);
|
|
throw new Error(lang === 'fr' ? `Impossible de récupérer les personnages complets.` : `Unable to retrieve complete characters.`);
|
|
} else {
|
|
console.error("An unknown error occurred.");
|
|
throw new Error(lang === 'fr' ? "Une erreur inconnue s'est produite." : "An unknown error occurred.");
|
|
}
|
|
}
|
|
if (result.length === 0) {
|
|
throw new Error(lang === 'fr' ? `Aucun personnage complet trouvé.` : `No complete characters found.`);
|
|
}
|
|
return result;
|
|
}
|
|
}
|