- wrap root layout with QueryProvider for React Query - replace market UnderConstruction placeholder with MarketClient and real data fetching - implement search, pagination, and sort via search params using getActiveListings - add necessary client components and queries - update dependencies (e.g., prisma, pkg-types)
221 lines
6.4 KiB
TypeScript
221 lines
6.4 KiB
TypeScript
/**
|
|
* 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<string, string> = {
|
|
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<string, any> = {};
|
|
|
|
// 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);
|
|
});
|
|
|