/** * Queries de personagens * CRUD completo para a tabela user_characters */ import { query } from "../index"; export interface Character { character_id: number; user_id: number; character_name: string; server_name: string; is_main: boolean; verified: boolean; created_at: Date; } export interface CreateCharacterData { character_name: string; server_name: string; is_main?: boolean; } export interface UpdateCharacterData { character_name?: string; server_name?: string; is_main?: boolean; } /** * Cria um novo personagem * Se isMain=true, desmarca outros personagens como main */ export async function createCharacter( userId: number, data: CreateCharacterData, ): Promise { // Usar transação para garantir atomicidade const { getPool } = await import("../index"); const pool = getPool(); const client = await pool.connect(); try { await client.query("BEGIN"); // Se este personagem será main, desmarcar outros if (data.is_main) { await client.query( ` UPDATE user_characters SET is_main = FALSE WHERE user_id = $1 `, [userId], ); } // Inserir novo personagem const result = await client.query( ` INSERT INTO user_characters (user_id, character_name, server_name, is_main) VALUES ($1, $2, $3, $4) RETURNING * `, [userId, data.character_name, data.server_name, data.is_main || false], ); await client.query("COMMIT"); return result.rows[0]; } catch (error) { await client.query("ROLLBACK"); throw error; } finally { client.release(); } } /** * Lista todos os personagens de um usuário */ export async function getUserCharacters(userId: number): Promise { const result = await query( ` SELECT * FROM user_characters WHERE user_id = $1 ORDER BY is_main DESC, created_at ASC `, [userId], ); return result.rows; } /** * Busca personagem principal de um usuário em um servidor específico * Retorna o personagem principal (is_main = true) ou o primeiro personagem do servidor */ export async function getMainCharacterByUserId( userId: number, serverName: string, ): Promise { const result = await query( ` SELECT * FROM user_characters WHERE user_id = $1 AND server_name = $2 ORDER BY is_main DESC, created_at ASC LIMIT 1 `, [userId, serverName], ); return result.rows[0] || null; } /** * Busca personagem por ID */ export async function getCharacterById( characterId: number, ): Promise { const result = await query( ` SELECT * FROM user_characters WHERE character_id = $1 `, [characterId], ); return result.rows[0] || null; } /** * Atualiza personagem * Verifica ownership e se isMain=true, desmarca outros */ export async function updateCharacter( characterId: number, userId: number, data: UpdateCharacterData, ): Promise { // Verificar ownership primeiro const existing = await getCharacterById(characterId); if (!existing) { throw new Error("Personagem não encontrado"); } if (existing.user_id !== userId) { throw new Error("Você não tem permissão para atualizar este personagem"); } // Usar transação para garantir atomicidade const { getPool } = await import("../index"); const pool = getPool(); const client = await pool.connect(); try { await client.query("BEGIN"); // Se este personagem será main, desmarcar outros if (data.is_main) { await client.query( ` UPDATE user_characters SET is_main = FALSE WHERE user_id = $1 AND character_id != $2 `, [userId, characterId], ); } // Construir query de update const updates: string[] = []; const values: any[] = []; let paramIndex = 1; if (data.character_name !== undefined) { updates.push(`character_name = $${paramIndex++}`); values.push(data.character_name); } if (data.server_name !== undefined) { updates.push(`server_name = $${paramIndex++}`); values.push(data.server_name); } if (data.is_main !== undefined) { updates.push(`is_main = $${paramIndex++}`); values.push(data.is_main); } if (updates.length === 0) { // Se não há updates, retorna personagem atual await client.query("COMMIT"); return existing; } values.push(characterId); const result = await client.query( ` UPDATE user_characters SET ${updates.join(", ")} WHERE character_id = $${paramIndex} RETURNING * `, values, ); await client.query("COMMIT"); return result.rows[0]; } catch (error) { await client.query("ROLLBACK"); throw error; } finally { client.release(); } } /** * Remove personagem * Verifica ownership antes de remover */ export async function deleteCharacter( characterId: number, userId: number, ): Promise { // Verificar ownership const existing = await getCharacterById(characterId); if (!existing) { throw new Error("Personagem não encontrado"); } if (existing.user_id !== userId) { throw new Error("Você não tem permissão para remover este personagem"); } await query( ` DELETE FROM user_characters WHERE character_id = $1 `, [characterId], ); }