Introduce series management functionality and repository updates
- Added `series-world.repo.ts` to handle database operations related to series worlds and their elements. - Implemented `series-sync.repo.ts` for managing synchronization between books and series. - Expanded `spell.ipc.ts` data models to include `seriesSpellId` for spell synchronization. - Refactored `insertSpellTag` method in `spelltag.repo.ts` for improved error handling and logic clarity.
This commit is contained in:
199
electron/database/models/SeriesSync.ts
Normal file
199
electron/database/models/SeriesSync.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
import { getUserEncryptionKey } from "../keyManager.js";
|
||||
import System from "../System.js";
|
||||
import SeriesSyncRepo, { SyncElementType } from "../repositories/series-sync.repo.js";
|
||||
|
||||
export interface SeriesSyncUploadPayload {
|
||||
type: SyncElementType;
|
||||
bookElementId: string;
|
||||
field: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface SeriesSyncResult {
|
||||
success: boolean;
|
||||
updatedCount: number;
|
||||
}
|
||||
|
||||
export default class SeriesSync {
|
||||
/**
|
||||
* Uploads a field value from a book element to its linked series element,
|
||||
* and propagates the change to all other book elements linked to the same series element.
|
||||
* @param userId - The unique identifier of the user
|
||||
* @param payload - The upload payload containing type, bookElementId, field, and value
|
||||
* @param lang - The language for error messages ('fr' or 'en')
|
||||
* @returns The upload response
|
||||
*/
|
||||
public static uploadFieldToSeries(userId: string, payload: SeriesSyncUploadPayload, lang: 'fr' | 'en' = 'fr'): SeriesSyncResult {
|
||||
const { type, bookElementId, field, value } = payload;
|
||||
|
||||
const seriesElementId: string | null = this.getSeriesLink(userId, type, bookElementId, lang);
|
||||
if (!seriesElementId) {
|
||||
throw new Error(lang === 'fr' ? `Cet élément n'est pas lié à une série.` : `This element is not linked to a series.`);
|
||||
}
|
||||
|
||||
const userKey: string = getUserEncryptionKey(userId);
|
||||
const encryptedValue: string = value ? System.encryptDataWithUserKey(value, userKey) : '';
|
||||
|
||||
const dbField: string = this.mapFieldToDbColumn(type, field);
|
||||
|
||||
this.updateSeriesElement(userId, type, seriesElementId, dbField, encryptedValue, lang);
|
||||
const updatedCount: number = this.updateLinkedBookElements(userId, type, seriesElementId, dbField, encryptedValue, lang);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
updatedCount: updatedCount + 1
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the series element ID linked to a book element.
|
||||
* @param userId - The unique identifier of the user
|
||||
* @param type - The type of element (character, world, location, spell)
|
||||
* @param bookElementId - The unique identifier of the book element
|
||||
* @param lang - The language for error messages ('fr' or 'en')
|
||||
* @returns The series element ID or null if not linked
|
||||
*/
|
||||
private static getSeriesLink(userId: string, type: SyncElementType, bookElementId: string, lang: 'fr' | 'en'): string | null {
|
||||
switch (type) {
|
||||
case 'character':
|
||||
return SeriesSyncRepo.getCharacterSeriesLink(userId, bookElementId, lang);
|
||||
case 'world':
|
||||
return SeriesSyncRepo.getWorldSeriesLink(userId, bookElementId, lang);
|
||||
case 'location':
|
||||
return SeriesSyncRepo.getLocationSeriesLink(userId, bookElementId, lang);
|
||||
case 'spell':
|
||||
return SeriesSyncRepo.getSpellSeriesLink(userId, bookElementId, lang);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps frontend field names to database column names.
|
||||
* @param type - The type of element (character, world, location, spell)
|
||||
* @param field - The frontend field name to map
|
||||
* @returns The corresponding database column name
|
||||
*/
|
||||
private static mapFieldToDbColumn(type: SyncElementType, field: string): string {
|
||||
const characterFieldMap: Record<string, string> = {
|
||||
'name': 'first_name',
|
||||
'firstName': 'first_name',
|
||||
'lastName': 'last_name',
|
||||
'nickname': 'nickname',
|
||||
'age': 'age',
|
||||
'gender': 'gender',
|
||||
'species': 'species',
|
||||
'nationality': 'nationality',
|
||||
'status': 'status',
|
||||
'title': 'title',
|
||||
'category': 'category',
|
||||
'role': 'role',
|
||||
'biography': 'biography',
|
||||
'history': 'history',
|
||||
'speechPattern': 'speech_pattern',
|
||||
'catchphrase': 'catchphrase',
|
||||
'residence': 'residence',
|
||||
'notes': 'notes',
|
||||
'color': 'color'
|
||||
};
|
||||
|
||||
const worldFieldMap: Record<string, string> = {
|
||||
'name': 'name',
|
||||
'history': 'history',
|
||||
'politics': 'politics',
|
||||
'economy': 'economy',
|
||||
'religion': 'religion',
|
||||
'languages': 'languages'
|
||||
};
|
||||
|
||||
const locationFieldMap: Record<string, string> = {
|
||||
'name': 'name',
|
||||
'loc_name': 'loc_name'
|
||||
};
|
||||
|
||||
const spellFieldMap: Record<string, string> = {
|
||||
'name': 'name',
|
||||
'description': 'description',
|
||||
'type': 'type',
|
||||
'level': 'level',
|
||||
'range': 'range',
|
||||
'duration': 'duration',
|
||||
'cost': 'cost',
|
||||
'effect': 'effect',
|
||||
'components': 'components',
|
||||
'notes': 'notes'
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
case 'character':
|
||||
return characterFieldMap[field] || field;
|
||||
case 'world':
|
||||
return worldFieldMap[field] || field;
|
||||
case 'location':
|
||||
return locationFieldMap[field] || field;
|
||||
case 'spell':
|
||||
return spellFieldMap[field] || field;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the series element field.
|
||||
* @param userId - The unique identifier of the user
|
||||
* @param type - The type of element (character, world, location, spell)
|
||||
* @param seriesElementId - The unique identifier of the series element
|
||||
* @param field - The database column name to update
|
||||
* @param encryptedValue - The encrypted value to set
|
||||
* @param lang - The language for error messages ('fr' or 'en')
|
||||
* @returns True if updated successfully
|
||||
*/
|
||||
private static updateSeriesElement(userId: string, type: SyncElementType, seriesElementId: string, field: string, encryptedValue: string, lang: 'fr' | 'en'): boolean {
|
||||
switch (type) {
|
||||
case 'character':
|
||||
return SeriesSyncRepo.updateSeriesCharacterField(userId, seriesElementId, field, encryptedValue, lang);
|
||||
case 'world':
|
||||
return SeriesSyncRepo.updateSeriesWorldField(userId, seriesElementId, field, encryptedValue, lang);
|
||||
case 'location':
|
||||
return SeriesSyncRepo.updateSeriesLocationField(userId, seriesElementId, field, encryptedValue, lang);
|
||||
case 'spell':
|
||||
return SeriesSyncRepo.updateSeriesSpellField(userId, seriesElementId, field, encryptedValue, lang);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all book elements linked to the series element.
|
||||
* @param userId - The unique identifier of the user
|
||||
* @param type - The type of element (character, world, location, spell)
|
||||
* @param seriesElementId - The unique identifier of the series element
|
||||
* @param field - The database column name to update
|
||||
* @param encryptedValue - The encrypted value to set
|
||||
* @param lang - The language for error messages ('fr' or 'en')
|
||||
* @returns The number of book elements updated
|
||||
*/
|
||||
private static updateLinkedBookElements(userId: string, type: SyncElementType, seriesElementId: string, field: string, encryptedValue: string, lang: 'fr' | 'en'): number {
|
||||
const bookField: string = this.mapSeriesFieldToBookField(type, field);
|
||||
|
||||
switch (type) {
|
||||
case 'character':
|
||||
return SeriesSyncRepo.updateLinkedBookCharactersField(userId, seriesElementId, bookField, encryptedValue, lang);
|
||||
case 'world':
|
||||
return SeriesSyncRepo.updateLinkedBookWorldsField(userId, seriesElementId, bookField, encryptedValue, lang);
|
||||
case 'location':
|
||||
return SeriesSyncRepo.updateLinkedBookLocationsField(userId, seriesElementId, bookField, encryptedValue, lang);
|
||||
case 'spell':
|
||||
return SeriesSyncRepo.updateLinkedBookSpellsField(userId, seriesElementId, bookField, encryptedValue, lang);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps series table field names to book table field names (if different).
|
||||
* @param type - The type of element (character, world, location, spell)
|
||||
* @param seriesField - The series table field name
|
||||
* @returns The corresponding book table field name
|
||||
*/
|
||||
private static mapSeriesFieldToBookField(type: SyncElementType, seriesField: string): string {
|
||||
if (type === 'location') {
|
||||
if (seriesField === 'name') {
|
||||
return 'loc_name';
|
||||
}
|
||||
}
|
||||
return seriesField;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user