/** * Migration 026: Fuzzy search with trigram similarity (pg_trgm) * * - Enables pg_trgm extension for Levenshtein-like fuzzy matching * - Creates GIN indexes on product name/description for fast trigram similarity * - Adds similarity index on brands and categories for term suggestions * * Run: node migrations/026_fuzzy_search.js */ const { Pool } = require('pg'); const pool = new Pool({ connectionString: process.env.DATABASE_URL || 'postgres://mdv:mdv_dev_only@localhost:5432/mercadodevida', }); async function migrate() { const client = await pool.connect(); try { await client.query('BEGIN'); // 1. Enable pg_trgm extension await client.query(` CREATE EXTENSION IF NOT EXISTS pg_trgm; `); console.log('✓ pg_trgm extension enabled'); // 2. GIN index on product name for trigram similarity await client.query(` CREATE INDEX IF NOT EXISTS catalog_products_name_trgm_idx ON catalog_products USING GIN (name gin_trgm_ops); `); console.log('✓ catalog_products name trigram index'); // 3. GIN index on product description await client.query(` CREATE INDEX IF NOT EXISTS catalog_products_description_trgm_idx ON catalog_products USING GIN (description gin_trgm_ops); `); console.log('✓ catalog_products description trigram index'); // 4. GIN index on brand names (for suggestions) await client.query(` CREATE INDEX IF NOT EXISTS brands_brands_name_trgm_idx ON brands_brands USING GIN (name gin_trgm_ops); `); console.log('✓ brands_brands name trigram index'); // 5. GIN index on category names (for suggestions) await client.query(` CREATE INDEX IF NOT EXISTS categories_categories_name_trgm_idx ON categories_categories USING GIN (name gin_trgm_ops); `); console.log('✓ categories_categories name trigram index'); // 6. Record migration await client.query(` INSERT INTO pgmigrations (name, run_on) VALUES ('026_fuzzy_search', NOW()) ON CONFLICT (name) DO NOTHING; `); console.log('✓ Migration recorded'); await client.query('COMMIT'); console.log('\n✅ Migration 026 complete: fuzzy search indexes created'); } catch (err) { await client.query('ROLLBACK'); throw err; } finally { client.release(); await pool.end(); } } migrate().catch((err) => { console.error('❌ Migration failed:', err.message); process.exit(1); });