import type { RowDataPacket } from 'mysql2' import { db, DB } from './db' // Armería: búsqueda de personajes/ítems/hermandades y ficha de personaje con equipo. // Datos de personaje/equipo en acore_characters; datos de ítem (nombre/calidad/ // display_id) en django_wow.item_data (importado de los db2; item_template no existe // en 3.4.3). Se resuelve en dos pasos para no depender de joins entre esquemas. export interface CharacterResult { guid: number name: string race: number gender: number class: number level: number } export interface ItemResult { entry: number name: string quality: number itemLevel: number inventoryType: number } export interface GuildResult { guildid: number name: string members: number } export interface EquipItem { slot: number entry: number name: string quality: number itemLevel: number inventoryType: number displayId: number | null transmogEntry: number | null transmogDisplayId: number | null } const LIMIT = 25 export async function searchCharacters(q: string, limit = LIMIT): Promise { try { const [rows] = await db(DB.characters).query( 'SELECT guid, name, race, gender, class, level FROM characters WHERE name LIKE ? ORDER BY level DESC, name LIMIT ?', [`%${q}%`, limit], ) return rows.map((r) => ({ guid: r.guid, name: r.name, race: r.race, gender: r.gender, class: r.class, level: r.level, })) } catch { return [] } } export async function searchGuilds(q: string, limit = LIMIT): Promise { try { const [rows] = await db(DB.characters).query( `SELECT g.guildid, g.name, (SELECT COUNT(*) FROM guild_member gm WHERE gm.guildid = g.guildid) AS members FROM guild g WHERE g.name LIKE ? ORDER BY members DESC LIMIT ?`, [`%${q}%`, limit], ) return rows.map((r) => ({ guildid: r.guildid, name: r.name, members: Number(r.members ?? 0) })) } catch { return [] } } export async function searchItems(q: string, locale: string, limit = LIMIT): Promise { const col = locale === 'en' ? 'name_en' : 'name_es' try { const [rows] = await db(DB.default).query( `SELECT entry, COALESCE(${col}, name_en) AS name, quality, item_level, inventory_type FROM item_data WHERE ${col} LIKE ? OR name_en LIKE ? ORDER BY item_level DESC LIMIT ?`, [`%${q}%`, `%${q}%`, limit], ) return rows.map((r) => ({ entry: r.entry, name: r.name, quality: r.quality, itemLevel: r.item_level, inventoryType: r.inventory_type, })) } catch { return [] } } export async function getCharacter(guid: number): Promise< (CharacterResult & { guildName: string | null; guildId: number | null; online: boolean }) | null > { try { const [rows] = await db(DB.characters).query( 'SELECT guid, name, race, gender, class, level, online FROM characters WHERE guid = ?', [guid], ) const c = rows[0] if (!c) return null let guildName: string | null = null let guildId: number | null = null try { const [g] = await db(DB.characters).query( `SELECT gu.guildid, gu.name FROM guild_member gm JOIN guild gu ON gu.guildid = gm.guildid WHERE gm.guid = ?`, [guid], ) if (g[0]) { guildId = g[0].guildid guildName = g[0].name } } catch { /* sin hermandad */ } return { guid: c.guid, name: c.name, race: c.race, gender: c.gender, class: c.class, level: c.level, online: c.online === 1, guildName, guildId, } } catch { return null } } /** Ítems equipados (slots 0-18) del personaje, resueltos con item_data. */ export async function getCharacterEquipment(guid: number, locale: string): Promise { const col = locale === 'en' ? 'name_en' : 'name_es' try { const [inv] = await db(DB.characters).query( `SELECT ci.slot, ii.itemEntry, ii.transmogrification FROM character_inventory ci JOIN item_instance ii ON ii.guid = ci.item WHERE ci.guid = ? AND ci.bag = 0 AND ci.slot <= 18 ORDER BY ci.slot`, [guid], ) if (inv.length === 0) return [] // Resolver todos los entries (equipados + transmog) en una consulta a item_data. const entries = [ ...new Set(inv.flatMap((r) => [Number(r.itemEntry), Number(r.transmogrification)]).filter((n) => n > 0)), ] const meta = new Map() if (entries.length) { const [items] = await db(DB.default).query( `SELECT entry, COALESCE(${col}, name_en) AS name, quality, item_level, inventory_type, display_id FROM item_data WHERE entry IN (${entries.map(() => '?').join(',')})`, entries, ) for (const it of items) meta.set(Number(it.entry), it) } return inv.map((r) => { const entry = Number(r.itemEntry) const tmog = Number(r.transmogrification) || null const m = meta.get(entry) const tm = tmog ? meta.get(tmog) : undefined return { slot: r.slot, entry, name: m?.name ?? `#${entry}`, quality: m ? Number(m.quality) : 0, itemLevel: m ? Number(m.item_level) : 0, inventoryType: m ? Number(m.inventory_type) : 0, displayId: m && m.display_id != null ? Number(m.display_id) : null, transmogEntry: tmog, transmogDisplayId: tm && tm.display_id != null ? Number(tm.display_id) : null, } }) } catch { return [] } } export interface GuildMember { guid: number name: string race: number class: number level: number rank: number } export async function getGuild( guildid: number, ): Promise<{ guildid: number; name: string; members: GuildMember[]; leaderName: string | null } | null> { try { const [g] = await db(DB.characters).query( 'SELECT guildid, name, leaderguid FROM guild WHERE guildid = ?', [guildid], ) if (!g[0]) return null const [members] = await db(DB.characters).query( `SELECT c.guid, c.name, c.race, c.class, c.level, gm.rank FROM guild_member gm JOIN characters c ON c.guid = gm.guid WHERE gm.guildid = ? ORDER BY gm.rank, c.level DESC`, [guildid], ) const list = members.map((m) => ({ guid: m.guid, name: m.name, race: m.race, class: m.class, level: m.level, rank: m.rank, })) const leader = list.find((m) => m.guid === g[0].leaderguid) return { guildid: g[0].guildid, name: g[0].name, members: list, leaderName: leader?.name ?? null } } catch { return null } }