feat: implement market page with QueryProvider and dynamic listings
- 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)
This commit is contained in:
1 parent
55eebde0ba
commit
ab37b477df
106 files changed
+15261
-301
No files matched your search
@@ -0,0 +1,189 @@
|
||||
-- Migration 012: Telemetria e Expansão de Anúncios
|
||||
-- Criado em: 2025-01-27
|
||||
|
||||
-- ============================================
|
||||
-- 1. Tabela de Eventos de Telemetria
|
||||
-- ============================================
|
||||
CREATE TABLE IF NOT EXISTS telemetry_events (
|
||||
event_id SERIAL PRIMARY KEY,
|
||||
event_type VARCHAR(50) NOT NULL,
|
||||
ad_id INTEGER REFERENCES listings(listing_id) ON DELETE CASCADE,
|
||||
user_id INTEGER REFERENCES users(user_id) ON DELETE SET NULL,
|
||||
session_id VARCHAR(255),
|
||||
metadata JSONB DEFAULT '{}'::jsonb,
|
||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Índices para performance
|
||||
CREATE INDEX IF NOT EXISTS idx_telemetry_ad_id ON telemetry_events(ad_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_telemetry_user_id ON telemetry_events(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_telemetry_timestamp ON telemetry_events(timestamp DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_telemetry_event_type ON telemetry_events(event_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_telemetry_session_id ON telemetry_events(session_id);
|
||||
|
||||
-- Índice composto para queries de analytics
|
||||
CREATE INDEX IF NOT EXISTS idx_telemetry_ad_type_time ON telemetry_events(ad_id, event_type, timestamp DESC);
|
||||
|
||||
-- ============================================
|
||||
-- 2. Expansão da Tabela listings
|
||||
-- ============================================
|
||||
ALTER TABLE listings
|
||||
ADD COLUMN IF NOT EXISTS is_featured BOOLEAN DEFAULT FALSE,
|
||||
ADD COLUMN IF NOT EXISTS favorites_count INTEGER DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS inquiries_count INTEGER DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS price_history JSONB DEFAULT '[]'::jsonb,
|
||||
ADD COLUMN IF NOT EXISTS expires_at TIMESTAMP;
|
||||
|
||||
-- Índices para novos campos
|
||||
CREATE INDEX IF NOT EXISTS idx_listings_is_featured ON listings(is_featured) WHERE is_featured = TRUE;
|
||||
CREATE INDEX IF NOT EXISTS idx_listings_expires_at ON listings(expires_at) WHERE expires_at IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_listings_favorites_count ON listings(favorites_count DESC);
|
||||
|
||||
-- ============================================
|
||||
-- 3. Tabela de Analytics Agregados
|
||||
-- ============================================
|
||||
CREATE TABLE IF NOT EXISTS ad_analytics (
|
||||
ad_id INTEGER PRIMARY KEY REFERENCES listings(listing_id) ON DELETE CASCADE,
|
||||
impressions INTEGER DEFAULT 0,
|
||||
clicks INTEGER DEFAULT 0,
|
||||
ctr DECIMAL(5, 2) DEFAULT 0.00, -- Click-through rate em porcentagem
|
||||
avg_view_duration DECIMAL(10, 2) DEFAULT 0.00, -- em segundos
|
||||
bounce_rate DECIMAL(5, 2) DEFAULT 0.00, -- em porcentagem
|
||||
inquiries INTEGER DEFAULT 0,
|
||||
favorites INTEGER DEFAULT 0,
|
||||
conversion_rate DECIMAL(5, 2) DEFAULT 0.00, -- em porcentagem
|
||||
time_to_sell INTEGER DEFAULT NULL, -- em horas
|
||||
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Trigger para atualizar last_updated automaticamente
|
||||
CREATE OR REPLACE FUNCTION update_ad_analytics_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.last_updated = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trigger_update_ad_analytics_updated_at
|
||||
BEFORE UPDATE ON ad_analytics
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_ad_analytics_updated_at();
|
||||
|
||||
-- ============================================
|
||||
-- 4. Tabela de Inventário do Usuário
|
||||
-- ============================================
|
||||
CREATE TABLE IF NOT EXISTS user_inventory (
|
||||
inventory_id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
|
||||
item_id INTEGER NOT NULL,
|
||||
item_name VARCHAR(255) NOT NULL,
|
||||
quantity INTEGER DEFAULT 1 CHECK (quantity > 0),
|
||||
acquired_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(user_id, item_id)
|
||||
);
|
||||
|
||||
-- Índices
|
||||
CREATE INDEX IF NOT EXISTS idx_user_inventory_user_id ON user_inventory(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_inventory_item_id ON user_inventory(item_id);
|
||||
|
||||
-- ============================================
|
||||
-- 5. Tabela de Favoritos
|
||||
-- ============================================
|
||||
CREATE TABLE IF NOT EXISTS user_favorites (
|
||||
user_id INTEGER NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
|
||||
ad_id INTEGER NOT NULL REFERENCES listings(listing_id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (user_id, ad_id)
|
||||
);
|
||||
|
||||
-- Índices
|
||||
CREATE INDEX IF NOT EXISTS idx_user_favorites_user_id ON user_favorites(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_favorites_ad_id ON user_favorites(ad_id);
|
||||
|
||||
-- ============================================
|
||||
-- 6. Trigger para Atualizar favorites_count
|
||||
-- ============================================
|
||||
CREATE OR REPLACE FUNCTION update_listing_favorites_count()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
UPDATE listings
|
||||
SET favorites_count = favorites_count + 1
|
||||
WHERE listing_id = NEW.ad_id;
|
||||
RETURN NEW;
|
||||
ELSIF TG_OP = 'DELETE' THEN
|
||||
UPDATE listings
|
||||
SET favorites_count = GREATEST(0, favorites_count - 1)
|
||||
WHERE listing_id = OLD.ad_id;
|
||||
RETURN OLD;
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trigger_update_listing_favorites_count
|
||||
AFTER INSERT OR DELETE ON user_favorites
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_listing_favorites_count();
|
||||
|
||||
-- ============================================
|
||||
-- 7. Função para Inicializar Analytics ao Criar Anúncio
|
||||
-- ============================================
|
||||
CREATE OR REPLACE FUNCTION initialize_ad_analytics()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
INSERT INTO ad_analytics (ad_id)
|
||||
VALUES (NEW.listing_id)
|
||||
ON CONFLICT (ad_id) DO NOTHING;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trigger_initialize_ad_analytics
|
||||
AFTER INSERT ON listings
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION initialize_ad_analytics();
|
||||
|
||||
-- ============================================
|
||||
-- 8. Função para Atualizar Price History
|
||||
-- ============================================
|
||||
CREATE OR REPLACE FUNCTION update_price_history()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
new_price_entry JSONB;
|
||||
current_history JSONB;
|
||||
BEGIN
|
||||
-- Verifica se algum preço mudou
|
||||
IF (OLD.price_pix IS DISTINCT FROM NEW.price_pix) OR
|
||||
(OLD.price_tibia_coins IS DISTINCT FROM NEW.price_tibia_coins) OR
|
||||
(OLD.price_gold_coins IS DISTINCT FROM NEW.price_gold_coins) THEN
|
||||
|
||||
-- Cria entrada de histórico
|
||||
new_price_entry := jsonb_build_object(
|
||||
'timestamp', CURRENT_TIMESTAMP,
|
||||
'price_pix', NEW.price_pix,
|
||||
'price_tibia_coins', NEW.price_tibia_coins,
|
||||
'price_gold_coins', NEW.price_gold_coins
|
||||
);
|
||||
|
||||
-- Obtém histórico atual
|
||||
current_history := COALESCE(NEW.price_history, '[]'::jsonb);
|
||||
|
||||
-- Adiciona nova entrada no início do array
|
||||
NEW.price_history := jsonb_insert(
|
||||
current_history,
|
||||
'{0}',
|
||||
new_price_entry
|
||||
);
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trigger_update_price_history
|
||||
BEFORE UPDATE ON listings
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_price_history();
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
-- Migration 013: Suporte a troca por item em anúncios
|
||||
-- Criado em: 2025-01-29
|
||||
|
||||
-- Adicionar colunas para troca por item
|
||||
ALTER TABLE listings
|
||||
ADD COLUMN IF NOT EXISTS trade_item_id INTEGER,
|
||||
ADD COLUMN IF NOT EXISTS trade_item_name VARCHAR(255),
|
||||
ADD COLUMN IF NOT EXISTS trade_item_quantity INTEGER DEFAULT 1 CHECK (trade_item_quantity > 0);
|
||||
|
||||
-- Comentários para documentação
|
||||
COMMENT ON COLUMN listings.trade_item_id IS 'ID do item aceito em troca (referência ao banco de itens do TibiaWiki)';
|
||||
COMMENT ON COLUMN listings.trade_item_name IS 'Nome do item aceito em troca';
|
||||
COMMENT ON COLUMN listings.trade_item_quantity IS 'Quantidade do item aceito em troca';
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
-- Migration 014: Adicionar campos de incremento mínimo e preços iniciais para leilões
|
||||
-- Criado em: 2025-01-29
|
||||
|
||||
-- Adicionar colunas para incremento mínimo de lance
|
||||
ALTER TABLE listings
|
||||
ADD COLUMN IF NOT EXISTS min_bid_increment DECIMAL(10, 2);
|
||||
|
||||
-- Adicionar colunas para armazenar preços iniciais (para leilões)
|
||||
ALTER TABLE listings
|
||||
ADD COLUMN IF NOT EXISTS initial_price_pix DECIMAL(10, 2),
|
||||
ADD COLUMN IF NOT EXISTS initial_price_tibia_coins INTEGER,
|
||||
ADD COLUMN IF NOT EXISTS initial_price_gold_coins BIGINT;
|
||||
|
||||
-- Comentários para documentação
|
||||
COMMENT ON COLUMN listings.min_bid_increment IS 'Incremento mínimo para novos lances (padrão: 5% do preço inicial ou valor fixo)';
|
||||
COMMENT ON COLUMN listings.initial_price_pix IS 'Preço inicial em PIX (para leilões)';
|
||||
COMMENT ON COLUMN listings.initial_price_tibia_coins IS 'Preço inicial em Tibia Coins (para leilões)';
|
||||
COMMENT ON COLUMN listings.initial_price_gold_coins IS 'Preço inicial em Gold Coins (para leilões)';
|
||||
|
||||
-- Atualizar preços iniciais para leilões existentes (copiar dos preços atuais)
|
||||
UPDATE listings
|
||||
SET
|
||||
initial_price_pix = price_pix,
|
||||
initial_price_tibia_coins = price_tibia_coins,
|
||||
initial_price_gold_coins = price_gold_coins
|
||||
WHERE is_auction = TRUE
|
||||
AND (initial_price_pix IS NULL OR initial_price_tibia_coins IS NULL OR initial_price_gold_coins IS NULL);
|
||||
|
||||
-- Calcular incremento mínimo para leilões existentes (5% do preço inicial ou mínimo de R$ 10,00)
|
||||
UPDATE listings
|
||||
SET min_bid_increment = GREATEST(
|
||||
COALESCE(initial_price_pix * 0.05, 0),
|
||||
10.00
|
||||
)
|
||||
WHERE is_auction = TRUE
|
||||
AND min_bid_increment IS NULL
|
||||
AND initial_price_pix IS NOT NULL;
|
||||
|
||||
-- Para leilões com preço em TC ou GP, usar incremento fixo de 5% ou mínimo
|
||||
UPDATE listings
|
||||
SET min_bid_increment = COALESCE(
|
||||
min_bid_increment,
|
||||
GREATEST(
|
||||
CASE
|
||||
WHEN initial_price_tibia_coins IS NOT NULL THEN initial_price_tibia_coins * 0.05
|
||||
WHEN initial_price_gold_coins IS NOT NULL THEN initial_price_gold_coins * 0.05
|
||||
ELSE 10.00
|
||||
END,
|
||||
10.00
|
||||
)
|
||||
)
|
||||
WHERE is_auction = TRUE
|
||||
AND min_bid_increment IS NULL;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
-- Migration 015: Sistema de Intenções de Compra
|
||||
-- Criado em: 2025-01-29
|
||||
|
||||
CREATE TABLE IF NOT EXISTS purchase_intentions (
|
||||
intention_id SERIAL PRIMARY KEY,
|
||||
listing_id INTEGER NOT NULL REFERENCES listings(listing_id) ON DELETE CASCADE,
|
||||
buyer_id INTEGER NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
|
||||
payment_method VARCHAR(20) NOT NULL CHECK (payment_method IN ('pix', 'tibia_coins', 'gold_coins', 'trade')),
|
||||
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'rejected', 'expired', 'completed')),
|
||||
buyer_message TEXT,
|
||||
seller_response TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP,
|
||||
accepted_at TIMESTAMP,
|
||||
rejected_at TIMESTAMP
|
||||
);
|
||||
|
||||
-- Índices para performance
|
||||
CREATE INDEX IF NOT EXISTS idx_purchase_intentions_listing_id ON purchase_intentions(listing_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_purchase_intentions_buyer_id ON purchase_intentions(buyer_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_purchase_intentions_status ON purchase_intentions(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_purchase_intentions_created_at ON purchase_intentions(created_at DESC);
|
||||
|
||||
-- Constraint: apenas uma intenção pendente por listing+buyer
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_purchase_intentions_unique_pending
|
||||
ON purchase_intentions(listing_id, buyer_id)
|
||||
WHERE status = 'pending';
|
||||
|
||||
-- Trigger para atualizar updated_at
|
||||
CREATE OR REPLACE FUNCTION update_purchase_intentions_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trigger_update_purchase_intentions_updated_at
|
||||
BEFORE UPDATE ON purchase_intentions
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_purchase_intentions_updated_at();
|
||||
|
||||
-- Comentários para documentação
|
||||
COMMENT ON TABLE purchase_intentions IS 'Intenções de compra de anúncios - permite múltiplos compradores interessados';
|
||||
COMMENT ON COLUMN purchase_intentions.status IS 'pending: aguardando resposta do vendedor, accepted: aceita, rejected: rejeitada, expired: expirada, completed: concluída';
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
-- Migration 016: Tabela Unificada de Itens
|
||||
-- Criado em: 2025-01-29
|
||||
-- Objetivo: Unificar todos os itens de todas as categorias do SQLite em uma única tabela
|
||||
-- com IDs únicos e consistentes, permitindo JOINs confiáveis
|
||||
|
||||
CREATE TABLE IF NOT EXISTS items (
|
||||
item_id SERIAL PRIMARY KEY,
|
||||
-- ID original da tabela de origem (para referência)
|
||||
source_table_id INTEGER NOT NULL,
|
||||
-- Nome da tabela de origem (espadas, armaduras, etc)
|
||||
source_table_name VARCHAR(50) NOT NULL,
|
||||
-- Nome do item (normalizado)
|
||||
item_name VARCHAR(255) NOT NULL,
|
||||
-- Categoria (normalizada para inglês)
|
||||
category VARCHAR(50) NOT NULL,
|
||||
-- Caminho da imagem local (se houver)
|
||||
image_local_path TEXT,
|
||||
-- URL da imagem externa (se houver)
|
||||
image_url TEXT,
|
||||
-- Raridade
|
||||
rarity VARCHAR(20),
|
||||
-- NÃvel (se aplicável)
|
||||
level INTEGER,
|
||||
-- Peso (se aplicável)
|
||||
weight DECIMAL(10, 2),
|
||||
-- Slots (se aplicável)
|
||||
slots INTEGER,
|
||||
-- Skill para usar (se aplicável)
|
||||
skill VARCHAR(50),
|
||||
-- Dados adicionais em JSON (para campos extras que variam por categoria)
|
||||
metadata JSONB DEFAULT '{}',
|
||||
-- Timestamps
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- Ãndices para performance
|
||||
CONSTRAINT unique_source_item UNIQUE (source_table_name, source_table_id)
|
||||
);
|
||||
|
||||
-- Ãndices para busca rápida
|
||||
CREATE INDEX IF NOT EXISTS idx_items_name ON items(item_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_items_category ON items(category);
|
||||
CREATE INDEX IF NOT EXISTS idx_items_rarity ON items(rarity);
|
||||
CREATE INDEX IF NOT EXISTS idx_items_name_lower ON items(LOWER(item_name));
|
||||
CREATE INDEX IF NOT EXISTS idx_items_category_name ON items(category, item_name);
|
||||
|
||||
-- Ãndice GIN para busca em JSONB
|
||||
CREATE INDEX IF NOT EXISTS idx_items_metadata ON items USING GIN (metadata);
|
||||
|
||||
-- Trigger para atualizar updated_at
|
||||
CREATE OR REPLACE FUNCTION update_items_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trigger_update_items_updated_at
|
||||
BEFORE UPDATE ON items
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_items_updated_at();
|
||||
|
||||
-- Comentários para documentação
|
||||
COMMENT ON TABLE items IS 'Tabela unificada de itens - todos os itens de todas as categorias com IDs únicos';
|
||||
COMMENT ON COLUMN items.source_table_id IS 'ID original do item na tabela de origem (SQLite)';
|
||||
COMMENT ON COLUMN items.source_table_name IS 'Nome da tabela de origem (espadas, armaduras, etc)';
|
||||
COMMENT ON COLUMN items.category IS 'Categoria normalizada (weapon, armor, helmet, etc)';
|
||||
COMMENT ON COLUMN items.metadata IS 'Campos extras que variam por categoria (proteção, bonus, etc)';
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
-- Migration 017: Adicionar Foreign Key e Atualizar Listings
|
||||
-- Criado em: 2025-01-29
|
||||
-- Objetivo: Adicionar foreign key de listings para items e garantir integridade
|
||||
|
||||
-- Primeiro, adicionar coluna item_id_unified se não existir (para migração gradual)
|
||||
-- Depois, podemos fazer migration dos dados existentes
|
||||
|
||||
-- Por enquanto, vamos manter item_id como está e adicionar uma coluna de referência
|
||||
-- que será populada gradualmente
|
||||
|
||||
-- Adicionar foreign key para items (opcional, permite NULL para itens antigos durante migração)
|
||||
ALTER TABLE listings
|
||||
ADD COLUMN IF NOT EXISTS item_id_unified INTEGER REFERENCES items(item_id) ON DELETE SET NULL;
|
||||
|
||||
-- Ãndice para performance
|
||||
CREATE INDEX IF NOT EXISTS idx_listings_item_id_unified ON listings(item_id_unified);
|
||||
|
||||
-- Comentário
|
||||
COMMENT ON COLUMN listings.item_id_unified IS 'Referência ao item na tabela unificada items (substitui item_id no futuro)';
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
-- Migration 018: Atualizar Listings para usar item_id_unified como padrão
|
||||
-- Criado em: 2025-01-29
|
||||
-- Objetivo: Migrar dados existentes de item_id para item_id_unified baseado em correspondência
|
||||
|
||||
-- Primeiro, vamos popular item_id_unified baseado em correspondência de nome
|
||||
-- Isso é uma migração gradual - mantemos item_id para compatibilidade
|
||||
|
||||
UPDATE listings l
|
||||
SET item_id_unified = (
|
||||
SELECT i.item_id
|
||||
FROM items i
|
||||
WHERE LOWER(i.item_name) = LOWER(l.item_name)
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE l.item_id_unified IS NULL;
|
||||
|
||||
-- Comentário
|
||||
COMMENT ON COLUMN listings.item_id IS 'ID legado do SQLite - será substituÃdo por item_id_unified';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Script de execução de migrations
|
||||
/**
|
||||
* Script de execução de migrations
|
||||
* Executa todas as migrations SQL em ordem
|
||||
*/
|
||||
|
||||
// Carregar variáveis de ambiente
|
||||
// Carregar variáveis de ambiente
|
||||
import { config } from "dotenv";
|
||||
import { resolve } from "path";
|
||||
|
||||
@@ -18,8 +18,7 @@ import { getPool, query, healthCheck } from "../index";
|
||||
const MIGRATIONS_DIR = join(__dirname, ".");
|
||||
|
||||
// Lista de migrations em ordem
|
||||
const MIGRATIONS = [
|
||||
"001_users.sql",
|
||||
const MIGRATIONS = [ "001_users.sql",
|
||||
"002_servers.sql",
|
||||
"003_fix_servers_location.sql",
|
||||
"004_listings.sql",
|
||||
@@ -30,21 +29,27 @@ const MIGRATIONS = [
|
||||
"009_item_price_history.sql",
|
||||
"010_notifications.sql",
|
||||
"011_donations.sql",
|
||||
];
|
||||
"012_telemetry_and_ads_enhancement.sql",
|
||||
"013_add_trade_item_support.sql",
|
||||
"014_add_bid_increment.sql",
|
||||
"015_add_purchase_intentions.sql",
|
||||
"016_create_unified_items_table.sql",
|
||||
"017_add_items_foreign_key.sql",
|
||||
"018_migrate_listings_to_unified_items.sql",];
|
||||
|
||||
async function runMigrations() {
|
||||
console.log("🚀 Iniciando execução de migrations...\n");
|
||||
console.log("🚀 Iniciando execução de migrations...\n");
|
||||
|
||||
// Verificar conexão com banco
|
||||
console.log("🔍 Verificando conexão com PostgreSQL...");
|
||||
// Verificar conexão com banco
|
||||
console.log("🔠Verificando conexão com PostgreSQL...");
|
||||
const isHealthy = await healthCheck();
|
||||
|
||||
if (!isHealthy) {
|
||||
console.error("❌ Falha na conexão com PostgreSQL. Verifique a variável PG_DB.");
|
||||
console.error("⌠Falha na conexão com PostgreSQL. Verifique a variável PG_DB.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("✅ Conexão estabelecida com sucesso\n");
|
||||
console.log("✅ Conexão estabelecida com sucesso\n");
|
||||
|
||||
// Verificar tabela de controle de migrations (opcional)
|
||||
try {
|
||||
@@ -55,7 +60,7 @@ async function runMigrations() {
|
||||
)
|
||||
`);
|
||||
} catch (error) {
|
||||
console.error("❌ Erro ao criar tabela de controle:", error);
|
||||
console.error("⌠Erro ao criar tabela de controle:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -65,18 +70,18 @@ async function runMigrations() {
|
||||
const version = migrationFile.replace(".sql", "");
|
||||
|
||||
try {
|
||||
// Verificar se já foi executada
|
||||
// Verificar se já foi executada
|
||||
const checkResult = await query<{ version: string }>(
|
||||
"SELECT version FROM schema_migrations WHERE version = $1",
|
||||
[version]
|
||||
);
|
||||
|
||||
if (checkResult.rows.length > 0) {
|
||||
console.log(`⏭️ Migration ${version} já executada, pulando...`);
|
||||
console.log(`âï¸ Migration ${version} já executada, pulando...`);
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`📝 Executando migration: ${migrationFile}...`);
|
||||
console.log(`📠Executando migration: ${migrationFile}...`);
|
||||
|
||||
// Ler arquivo SQL
|
||||
const sql = readFileSync(migrationPath, "utf-8");
|
||||
@@ -90,14 +95,14 @@ async function runMigrations() {
|
||||
[version]
|
||||
);
|
||||
|
||||
console.log(`✅ Migration ${version} executada com sucesso\n`);
|
||||
console.log(`✅ Migration ${version} executada com sucesso\n`);
|
||||
} catch (error) {
|
||||
console.error(`❌ Erro ao executar migration ${version}:`, error);
|
||||
console.error(`⌠Erro ao executar migration ${version}:`, error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("🎉 Todas as migrations foram executadas com sucesso!");
|
||||
console.log("🎉 Todas as migrations foram executadas com sucesso!");
|
||||
|
||||
// Fechar pool
|
||||
const pool = getPool();
|
||||
@@ -107,7 +112,8 @@ async function runMigrations() {
|
||||
|
||||
// Executar
|
||||
runMigrations().catch((error) => {
|
||||
console.error("❌ Erro fatal:", error);
|
||||
console.error("⌠Erro fatal:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user