Files
vyndr/scripts/apply-migration.js
T
builtbykev 3da1b4242c feat: Feature 1.2 (NBA stats FastAPI service) + Feature 1.4 (database schema)
Feature 1.2: Python FastAPI microservice wrapping nba_api
- GET /stats/season-avg, /stats/last-n, /stats/splits, /players/search
- Redis caching (24hr/1hr/6hr/7day), 0.6s rate limiting, PRA derived stat
- 27 Python tests passing

Feature 1.4: Complete Supabase database schema
- 6 tables: users, picks, scan_sessions, bets, outcomes, performance
- RLS enabled on all tables with auth.uid() policies
- 3 triggers: auto-create user, updated_at, scan count reset
- 37 schema validation tests passing
- Migration SQL ready, pending manual apply (WSL2 DNS blocker)

Total: 92 tests (65 Node.js + 27 Python), all passing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 10:58:58 -04:00

137 lines
3.6 KiB
JavaScript

require('dotenv').config();
const fs = require('fs');
const postgres = require('postgres');
const DB_PASSWORD = process.env.SUPABASE_DB_PASSWORD;
const PROJECT_REF = process.env.SUPABASE_URL.match(/https:\/\/(.+?)\.supabase/)[1];
// Use session mode (port 5432) for DDL statements
const sql = postgres({
host: `aws-0-us-east-1.pooler.supabase.com`,
port: 5432,
database: 'postgres',
username: `postgres.${PROJECT_REF}`,
password: DB_PASSWORD,
ssl: { rejectUnauthorized: false },
connection: { application_name: 'betonblk-migration' },
prepare: false,
});
async function applyMigration() {
// Test connection first
try {
const result = await sql`SELECT current_database(), current_user`;
console.log('Connected:', result[0]);
} catch (err) {
console.error('Connection failed:', err.message);
// Try transaction mode as fallback
console.log('Trying transaction mode on port 6543...');
const sql2 = postgres({
host: `aws-0-us-east-1.pooler.supabase.com`,
port: 6543,
database: 'postgres',
username: `postgres.${PROJECT_REF}`,
password: DB_PASSWORD,
ssl: { rejectUnauthorized: false },
prepare: false,
});
try {
const result2 = await sql2`SELECT current_database(), current_user`;
console.log('Connected via transaction mode:', result2[0]);
await runMigration(sql2);
await sql2.end();
return;
} catch (err2) {
console.error('Transaction mode also failed:', err2.message);
// Try direct connection
console.log('Trying direct connection...');
const sql3 = postgres({
host: `db.${PROJECT_REF}.supabase.co`,
port: 5432,
database: 'postgres',
username: 'postgres',
password: DB_PASSWORD,
ssl: { rejectUnauthorized: false },
prepare: false,
});
try {
const result3 = await sql3`SELECT current_database(), current_user`;
console.log('Connected directly:', result3[0]);
await runMigration(sql3);
await sql3.end();
return;
} catch (err3) {
console.error('Direct connection failed:', err3.message);
process.exit(1);
}
}
}
await runMigration(sql);
await sql.end();
}
async function runMigration(db) {
const migration = fs.readFileSync('supabase/migrations/001_initial_schema.sql', 'utf8');
const statements = splitStatements(migration);
console.log(`Applying ${statements.length} statements...`);
let ok = 0;
let errors = 0;
for (let i = 0; i < statements.length; i++) {
const stmt = statements[i].trim();
if (!stmt || stmt.startsWith('--')) continue;
try {
await db.unsafe(stmt);
ok++;
console.log(`[${i + 1}/${statements.length}] OK`);
} catch (err) {
errors++;
console.error(`[${i + 1}/${statements.length}] ERROR: ${err.message}`);
console.error(`Statement: ${stmt.substring(0, 120)}...`);
}
}
console.log(`Migration complete. ${ok} succeeded, ${errors} failed.`);
}
function splitStatements(sqlText) {
const results = [];
let current = '';
let inDollarQuote = false;
const lines = sqlText.split('\n');
for (const line of lines) {
const trimmed = line.trim();
if (trimmed.startsWith('--')) {
current += line + '\n';
continue;
}
const dollarCount = (line.match(/\$\$/g) || []).length;
if (dollarCount % 2 !== 0) {
inDollarQuote = !inDollarQuote;
}
current += line + '\n';
if (!inDollarQuote && trimmed.endsWith(';')) {
results.push(current);
current = '';
}
}
if (current.trim()) {
results.push(current);
}
return results;
}
applyMigration().catch(console.error);