import pg from 'pg'; const { Pool } = pg; const liaraPool = new Pool({ connectionString: 'postgresql://root:hePGFWh8f5TAEWCBK0V8XtQh@el-capitan.liara.cloud:32727/postgres', ssl: false, }); const vpsPool = new Pool({ connectionString: 'postgresql://user:d1ph12poyhd1o2pDASd2jp2dnbcba@94.101.186.198:5433/steelforesight', ssl: false, }); async function migrateFast() { console.log('Starting fast batch migration...'); const tablesRes = await liaraPool.query(` SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE' ORDER BY table_name; `); const tables = tablesRes.rows.map(r => r.table_name); for (const table of tables) { console.log(`\nTable: ${table}`); // Check if table exists on VPS const checkTable = await vpsPool.query(` SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = $1 `, [table]); if (checkTable.rows.length === 0) { const colsRes = await liaraPool.query(` SELECT column_name, data_type, udt_name, is_nullable, column_default FROM information_schema.columns WHERE table_schema = 'public' AND table_name = $1 ORDER BY ordinal_position; `, [table]); const colDefs = colsRes.rows.map(col => { let type = col.data_type; if (col.data_type === 'USER-DEFINED') type = col.udt_name; if (col.column_name === 'id' && (col.data_type === 'integer' || col.data_type === 'bigint') && col.column_default?.includes('nextval')) { return `"${col.column_name}" SERIAL PRIMARY KEY`; } let def = `"${col.column_name}" ${type}`; if (col.is_nullable === 'NO') def += ' NOT NULL'; if (col.column_name === 'id' && col.data_type === 'text') def += ' PRIMARY KEY'; return def; }).join(',\n '); const createSql = `CREATE TABLE IF NOT EXISTS "${table}" (\n ${colDefs}\n);`; await vpsPool.query(createSql); console.log(`Created table ${table}`); } const rowsRes = await liaraPool.query(`SELECT * FROM "${table}"`); console.log(`Copying ${rowsRes.rows.length} rows...`); if (rowsRes.rows.length > 0) { await vpsPool.query(`TRUNCATE TABLE "${table}" CASCADE;`); // Batch insert in chunks of 100 rows const chunkSize = 100; for (let i = 0; i < rowsRes.rows.length; i += chunkSize) { const chunk = rowsRes.rows.slice(i, i + chunkSize); const keys = Object.keys(chunk[0]); const colNames = keys.map(k => `"${k}"`).join(', '); const values = []; const valuePlaceholders = []; let paramIdx = 1; for (const row of chunk) { const rowPlaceholders = []; for (const key of keys) { values.push(row[key]); rowPlaceholders.push(`$${paramIdx++}`); } valuePlaceholders.push(`(${rowPlaceholders.join(', ')})`); } const batchSql = `INSERT INTO "${table}" (${colNames}) VALUES ${valuePlaceholders.join(', ')} ON CONFLICT DO NOTHING;`; await vpsPool.query(batchSql, values); } console.log(`✓ Completed table ${table}`); } } // Update sequences const seqRes = await vpsPool.query(` SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema = 'public'; `); for (const seq of seqRes.rows) { const seqName = seq.sequence_name; const tabName = seqName.replace(/_id_seq$/, ''); try { await vpsPool.query(`SELECT setval('${seqName}', COALESCE((SELECT MAX(id) FROM "${tabName}"), 1), true);`); console.log(`Updated sequence: ${seqName}`); } catch (e) { // ignore } } console.log('\nAll PostgreSQL tables & data migrated successfully!'); await liaraPool.end(); await vpsPool.end(); } migrateFast().catch(err => { console.error('Migration error:', err); process.exit(1); });