/** * TypeScript interfaces (copied from lib/models for type safety) */ export interface Attribute { id?: string; name: string; description: string; } export interface CharacterProps { id: string | null; name: string; lastName: string; category: string; title: string; image: string; physical?: Attribute[]; psychological?: Attribute[]; relations?: Attribute[]; skills?: Attribute[]; weaknesses?: Attribute[]; strengths?: Attribute[]; goals?: Attribute[]; motivations?: Attribute[]; role: string; biography?: string; history?: string; } /** * Database row types (snake_case from SQLite) */ export interface DBCharacter { character_id: string; book_id: string; user_id: string; first_name: string; last_name?: string; category: string; title?: string; image?: string; role?: string; biography?: string; history?: string; char_meta: string; synced?: number; } export interface DBCharacterAttribute { attr_id: string; character_id: string; user_id: string; attribute_name: string; // Format: "section:attributeName" (e.g., "physical:Height") attribute_value: string; // JSON stringified Attribute attr_meta: string; synced?: number; } /** * MAPPERS: DB → TypeScript Interfaces */ export function dbToCharacter(dbChar: DBCharacter, attributes: DBCharacterAttribute[] = []): CharacterProps { // Group attributes by section const physical: Attribute[] = []; const psychological: Attribute[] = []; const relations: Attribute[] = []; const skills: Attribute[] = []; const weaknesses: Attribute[] = []; const strengths: Attribute[] = []; const goals: Attribute[] = []; const motivations: Attribute[] = []; for (const attr of attributes) { try { const parsedValue: Attribute = JSON.parse(attr.attribute_value); const section = attr.attribute_name.split(':')[0]; switch (section) { case 'physical': physical.push(parsedValue); break; case 'psychological': psychological.push(parsedValue); break; case 'relations': relations.push(parsedValue); break; case 'skills': skills.push(parsedValue); break; case 'weaknesses': weaknesses.push(parsedValue); break; case 'strengths': strengths.push(parsedValue); break; case 'goals': goals.push(parsedValue); break; case 'motivations': motivations.push(parsedValue); break; } } catch (error) { console.error('Failed to parse character attribute:', error); } } return { id: dbChar.character_id, name: dbChar.first_name, lastName: dbChar.last_name || '', category: dbChar.category as any, title: dbChar.title || '', image: dbChar.image || '', physical, psychological, relations, skills, weaknesses, strengths, goals, motivations, role: dbChar.role || '', biography: dbChar.biography, history: dbChar.history }; } /** * MAPPERS: TypeScript Interfaces → DB */ export function characterToDb(character: CharacterProps, bookId: string, userId: string, synced: number = 0): DBCharacter { return { character_id: character.id || crypto.randomUUID(), book_id: bookId, user_id: userId, first_name: character.name, last_name: character.lastName, category: character.category, title: character.title, image: character.image, role: character.role, biography: character.biography, history: character.history, char_meta: '', synced }; } export function characterAttributesToDb( character: CharacterProps, userId: string, synced: number = 0 ): DBCharacterAttribute[] { const attributes: DBCharacterAttribute[] = []; const addAttributes = (section: string, attrs: Attribute[]) => { for (const attr of attrs) { attributes.push({ attr_id: attr.id || crypto.randomUUID(), character_id: character.id || '', user_id: userId, attribute_name: `${section}:${attr.name}`, attribute_value: JSON.stringify(attr), attr_meta: '', synced }); } }; addAttributes('physical', character.physical || []); addAttributes('psychological', character.psychological || []); addAttributes('relations', character.relations || []); addAttributes('skills', character.skills || []); addAttributes('weaknesses', character.weaknesses || []); addAttributes('strengths', character.strengths || []); addAttributes('goals', character.goals || []); addAttributes('motivations', character.motivations || []); return attributes; }