157 lines
4.6 KiB
JavaScript
157 lines
4.6 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Sync production data to development database
|
|
*
|
|
* This script copies real data from production to development, filtering out
|
|
* test records to keep the dev database clean for testing.
|
|
*/
|
|
|
|
const { execSync } = require('child_process');
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
|
|
const PROD_DB_URL = process.env.PROD_DATABASE_URL;
|
|
const DEV_DB_URL = process.env.DEV_DATABASE_URL;
|
|
|
|
if (!PROD_DB_URL || !DEV_DB_URL) {
|
|
console.error('❌ Missing environment variables');
|
|
console.error('Please set PROD_DATABASE_URL and DEV_DATABASE_URL');
|
|
console.error('');
|
|
console.error('Example:');
|
|
console.error(' PROD_DATABASE_URL="postgresql://user:pass@host:5432/euchre_camp" \\');
|
|
console.error(' DEV_DATABASE_URL="postgresql://user:pass@host:5432/euchre_camp_dev" \\');
|
|
console.error(' node scripts/sync-prod-to-dev.js');
|
|
process.exit(1);
|
|
}
|
|
|
|
if (PROD_DB_URL.includes('_dev') || PROD_DB_URL.includes('_ci')) {
|
|
console.error('❌ PROD_DATABASE_URL appears to be a non-production database!');
|
|
console.error(' This script should only be used with the production database.');
|
|
process.exit(1);
|
|
}
|
|
|
|
const TEST_PATTERNS = {
|
|
players: [
|
|
'%Test%',
|
|
'%Setup%',
|
|
'%Home Test%',
|
|
'%Home Match Player%',
|
|
'%Admin User%',
|
|
'%NinePart%',
|
|
'%Nine Part%',
|
|
'%Test Player%',
|
|
'%TestUser%',
|
|
'%Cucumber%',
|
|
'%Config Admin%',
|
|
],
|
|
events: [
|
|
'%Test%',
|
|
'%Setup%',
|
|
'%Recent%',
|
|
'%Test Tournament%',
|
|
'%Cucumber%',
|
|
],
|
|
users: [
|
|
'%test%',
|
|
'%setup%',
|
|
'%cucumber%',
|
|
'%TestUser%',
|
|
]
|
|
};
|
|
|
|
function buildLikeClause(patterns) {
|
|
return patterns.map(p => `name LIKE '${p}'`).join(' OR ');
|
|
}
|
|
|
|
function buildEmailLikeClause(patterns) {
|
|
return patterns.map(p => `email LIKE '${p}'`).join(' OR ');
|
|
}
|
|
|
|
async function main() {
|
|
console.log('🔄 Syncing production data to development database');
|
|
console.log('====================================================\n');
|
|
|
|
const readline = require('readline');
|
|
const rl = readline.createInterface({
|
|
input: process.stdin,
|
|
output: process.stdout
|
|
});
|
|
|
|
console.log('⚠️ WARNING: This will OVERWRITE the development database!');
|
|
console.log(' Production data will be copied, with test records excluded.');
|
|
console.log('');
|
|
console.log('Source:', PROD_DB_URL.replace(/:[^:@]+@/, ':***@'));
|
|
console.log('Target:', DEV_DB_URL.replace(/:[^:@]+@/, ':***@'));
|
|
console.log('');
|
|
|
|
rl.question('Type "sync" to confirm: ', async (answer) => {
|
|
if (answer !== 'sync') {
|
|
console.log('❌ Cancelled');
|
|
rl.close();
|
|
process.exit(0);
|
|
}
|
|
|
|
rl.close();
|
|
|
|
try {
|
|
console.log('\n📦 Dumping production data...');
|
|
|
|
const dumpFile = path.join(os.tmpdir(), `prod_dump_${Date.now()}.sql`);
|
|
|
|
execSync(`pg_dump "${PROD_DB_URL}" -f "${dumpFile}" --no-owner --no-acl`, {
|
|
stdio: 'inherit'
|
|
});
|
|
console.log('✅ Dump created');
|
|
|
|
console.log('\n🗑️ Clearing development database...');
|
|
execSync(`psql "${DEV_DB_URL}" -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"`, {
|
|
stdio: 'inherit'
|
|
});
|
|
console.log('✅ Development database cleared');
|
|
|
|
console.log('\n📥 Restoring to development database...');
|
|
execSync(`psql "${DEV_DB_URL}" -f "${dumpFile}"`, {
|
|
stdio: 'inherit'
|
|
});
|
|
console.log('✅ Data restored');
|
|
|
|
console.log('\n🧹 Cleaning up test records in dev database...');
|
|
|
|
const playerWhere = buildLikeClause(TEST_PATTERNS.players);
|
|
const eventWhere = buildLikeClause(TEST_PATTERNS.events);
|
|
const userWhere = buildEmailLikeClause(TEST_PATTERNS.users);
|
|
|
|
execSync(`psql "${DEV_DB_URL}" -c "DELETE FROM events WHERE (${eventWhere});"`, {
|
|
stdio: 'inherit'
|
|
});
|
|
console.log(' Deleted test events');
|
|
|
|
execSync(`psql "${DEV_DB_URL}" -c "DELETE FROM players WHERE (${playerWhere});"`, {
|
|
stdio: 'inherit'
|
|
});
|
|
console.log(' Deleted test players');
|
|
|
|
execSync(`psql "${DEV_DB_URL}" -c "DELETE FROM users WHERE (${userWhere}) AND \"playerId\" IS NULL;"`, {
|
|
stdio: 'inherit'
|
|
});
|
|
console.log(' Deleted test users');
|
|
|
|
fs.unlinkSync(dumpFile);
|
|
console.log('\n🧹 Cleaned up temporary dump file');
|
|
|
|
console.log('\n✅ Sync complete!');
|
|
console.log('\n📊 Summary:');
|
|
console.log(' - Production data copied to development');
|
|
console.log(' - Test records filtered out');
|
|
console.log(' - Development database is now a mirror of production (minus test data)');
|
|
|
|
} catch (error) {
|
|
console.error('\n❌ Sync failed:', error.message);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
}
|
|
|
|
main(); |