Files
2025-11-11 03:08:36 -03:00

245 lines
5.4 KiB
TypeScript

/**
* 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<Character> {
// 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<Character>(
`
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<Character[]> {
const result = await query<Character>(
`
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<Character | null> {
const result = await query<Character>(
`
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<Character | null> {
const result = await query<Character>(
`
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<Character> {
// 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<Character>(
`
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<void> {
// 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],
);
}