/** * Script para popular a tabela items unificada a partir do SQLite * * Este script: * 1. Lê todos os itens de todas as tabelas do SQLite * 2. Insere na tabela items do PostgreSQL com IDs únicos * 3. Mapeia os dados para o formato unificado */ import { config } from "dotenv"; import { resolve } from "path"; import path from "node:path"; // Carregar variáveis de ambiente config({ path: resolve(process.cwd(), ".env.local") }); config({ path: resolve(process.cwd(), ".env") }); import { getPool, query } from "../lib/db/index"; import { enToPtCategoryMap } from "../lib/item-images"; // Mapeamento de tabelas PT para categorias EN const ptToEnCategoryMap: Record = { espadas: "weapon", armaduras: "armor", capacetes: "helmet", calcas: "legs", botas: "boots", escudos: "shield", amuletos: "amulet", aneis: "ring", runas: "rune", ferramentas: "tool", municao: "ammunition", }; function getDatabase() { let Database: any; try { Database = require("better-sqlite3"); } catch (err) { console.error("better-sqlite3 não está instalado"); return null; } const dbPath = path.join(process.cwd(), "data", "tibiawiki.db"); const db = new Database(dbPath, { readonly: true, fileMustExist: true }); return db; } interface ItemRow { id: number; nome: string; image_url?: string; image_local_path?: string; rarity?: string; lvl?: number; peso?: number; peso_em_oz?: number; slots?: number; skill_para_usar?: string; [key: string]: any; } async function populateItemsTable() { console.log("🚀 Iniciando população da tabela items...\n"); const db = getDatabase(); if (!db) { console.error("❌ Não foi possível conectar ao SQLite"); process.exit(1); } try { // Obter todas as tabelas const tables = db .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'") .all() as { name: string }[]; console.log(`📋 Encontradas ${tables.length} tabelas\n`); let totalInserted = 0; let totalSkipped = 0; for (const table of tables) { const tableName = table.name; const categoryEn = ptToEnCategoryMap[tableName] || "other"; console.log(`📦 Processando tabela: ${tableName} (categoria: ${categoryEn})...`); try { // Verificar se a tabela tem as colunas necessárias const columns = db .prepare(`PRAGMA table_info(${tableName})`) .all() as { name: string; type: string }[]; const colNames = new Set(columns.map((c) => c.name.toLowerCase())); if (!colNames.has("id") || !colNames.has("nome")) { console.log(` ⚠️ Tabela ${tableName} não tem colunas id/nome, pulando...`); continue; } // Buscar todos os itens da tabela const items = db.prepare(`SELECT * FROM ${tableName}`).all() as ItemRow[]; console.log(` 📊 Encontrados ${items.length} itens`); for (const item of items) { try { // Verificar se já existe (baseado em source_table_name + source_table_id) const existing = await query<{ item_id: number }>( `SELECT item_id FROM items WHERE source_table_name = $1 AND source_table_id = $2`, [tableName, item.id] ); if (existing.rows.length > 0) { totalSkipped++; continue; } // Preparar dados do item const itemName = item.nome || ""; const imageUrl = item.image_url || null; const imageLocalPath = item.image_local_path || null; const rarity = item.rarity || null; const level = item.lvl || null; // Peso (pode ser em peso ou peso_em_oz) const weight = item.peso || item.peso_em_oz || null; const slots = item.slots || null; const skill = item.skill_para_usar || null; // Metadata com campos extras const metadata: Record = {}; // Adicionar campos extras ao metadata const extraFields = [ "voc", "volume", "bonus_de_skill", "protecao", "dropa_de", ]; for (const field of extraFields) { if (colNames.has(field) && item[field] !== undefined && item[field] !== null) { metadata[field] = item[field]; } } // Inserir na tabela items await query( `INSERT INTO items ( source_table_id, source_table_name, item_name, category, image_local_path, image_url, rarity, level, weight, slots, skill, metadata ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`, [ item.id, tableName, itemName, categoryEn, imageLocalPath, imageUrl, rarity, level, weight, slots, skill, JSON.stringify(metadata), ] ); totalInserted++; } catch (error: any) { if (error.code === "23505") { // Unique constraint violation - já existe totalSkipped++; } else { console.error(` ❌ Erro ao inserir item ${item.nome}:`, error.message); } } } console.log(` ✅ Tabela ${tableName} processada\n`); } catch (error: any) { console.error(` ❌ Erro ao processar tabela ${tableName}:`, error.message); } } console.log("\n📊 Resumo:"); console.log(` ✅ Itens inseridos: ${totalInserted}`); console.log(` ⏭️ Itens ignorados (já existentes): ${totalSkipped}`); console.log(` 📦 Total processado: ${totalInserted + totalSkipped}\n`); console.log("✨ População concluída com sucesso!"); } finally { db.close(); const pool = getPool(); await pool.end(); } } // Executar populateItemsTable().catch((error) => { console.error("❌ Erro fatal:", error); process.exit(1); });