import 'dotenv/config' import { Pool } from 'pg' async function main() { const pool = new Pool({ connectionString: process.env.DATABASE_URL }) const schema = (process.env.VECTOR_SCHEMA || 'ai_bible').replace(/[^a-zA-Z0-9_]/g, '') const source = `${schema}.bv_ro_fidela` const target = `${schema}.bv_ro_cornilescu` const client = await pool.connect() try { console.log('Cloning vector table from', source, 'to', target) await client.query('BEGIN') await client.query(`CREATE EXTENSION IF NOT EXISTS vector;`) await client.query(`CREATE SCHEMA IF NOT EXISTS "${schema}";`) // Create target table if not exists with same structure await client.query(` DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = '${schema}' AND table_name = 'bv_ro_cornilescu') THEN EXECUTE format('CREATE TABLE %I.%I (LIKE %I.%I INCLUDING ALL)', '${schema}', 'bv_ro_cornilescu', '${schema}', 'bv_ro_fidela'); END IF; END$$;`) // Insert rows if target empty const cnt = await client.query(`SELECT count(*)::int AS c FROM ${target}`) if ((cnt.rows?.[0]?.c ?? 0) === 0) { console.log('Copying rows...') await client.query(` INSERT INTO ${target} (testament, book, chapter, verse, text_raw, text_norm, tsv, embedding, created_at, updated_at) SELECT testament, book, chapter, verse, text_raw, text_norm, tsv, embedding, created_at, updated_at FROM ${source} ON CONFLICT DO NOTHING `) } else { console.log('Target already has rows, skipping copy') } // Create indexes if not exist await client.query(` CREATE UNIQUE INDEX IF NOT EXISTS ux_ref_bv_ro_cornilescu ON ${target} (book, chapter, verse); CREATE INDEX IF NOT EXISTS idx_tsv_bv_ro_cornilescu ON ${target} USING GIN (tsv); CREATE INDEX IF NOT EXISTS idx_book_ch_bv_ro_cornilescu ON ${target} (book, chapter); CREATE INDEX IF NOT EXISTS idx_testament_bv_ro_cornilescu ON ${target} (testament); `) await client.query('COMMIT') console.log('Rows copied and indexes created. Running post-copy maintenance...') // Run maintenance commands outside of transaction await client.query(`VACUUM ANALYZE ${target};`) try { await client.query(` CREATE INDEX IF NOT EXISTS idx_vec_ivfflat_bv_ro_cornilescu ON ${target} USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100); `) } catch (e) { console.warn('IVFFLAT index creation hit memory limits; skipping for now. You can create it later with higher maintenance_work_mem.') } console.log('Clone completed.') } catch (e) { await client.query('ROLLBACK') console.error('Clone error:', e) process.exit(1) } finally { client.release() await pool.end() } } main()