feat: add PostgreSQL database adapter support

This commit is contained in:
2026-03-29 20:08:53 -07:00
parent 54fd6abb5e
commit 803f936e2f
8 changed files with 393 additions and 6 deletions
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env node
/**
* Database seed script for EuchreCamp
* Creates sample data for testing and development
*/
const { PrismaClient } = require('@prisma/client');
const bcrypt = require('bcrypt');
const prisma = new PrismaClient();
async function main() {
console.log('🌱 Seeding database...\n');
// Create admin user if it doesn't exist
const adminEmail = 'david@dhg.lol';
const existingAdmin = await prisma.user.findUnique({
where: { email: adminEmail },
});
if (!existingAdmin) {
console.log('Creating admin user...');
const passwordHash = await bcrypt.hash('adminadmin', 12);
const adminUser = await prisma.user.create({
data: {
email: adminEmail,
emailVerified: true,
name: 'David Admin',
role: 'club_admin',
accounts: {
create: {
id: `admin_${Date.now()}`,
accountId: `admin_${Date.now()}`,
providerId: 'credential',
password: passwordHash,
},
},
},
});
console.log(`✅ Created admin user: ${adminUser.email}`);
} else {
console.log('✅ Admin user already exists');
}
// Create sample players if none exist
const playerCount = await prisma.player.count();
if (playerCount === 0) {
console.log('\nCreating sample players...');
const samplePlayers = [
'John Smith',
'Jane Doe',
'Mike Johnson',
'Sarah Brown',
'Charlie Wilson',
'Diana Davis',
'Robert Taylor',
'Emily Anderson',
'David Martinez',
'Lisa Thompson',
];
for (const name of samplePlayers) {
await prisma.player.create({
data: {
name,
currentElo: 1000 + Math.floor(Math.random() * 200) - 100,
gamesPlayed: Math.floor(Math.random() * 50),
wins: Math.floor(Math.random() * 30),
losses: Math.floor(Math.random() * 30),
},
});
}
console.log(`✅ Created ${samplePlayers.length} sample players`);
} else {
console.log(`${playerCount} players already exist`);
}
// Create sample tournament
const tournamentCount = await prisma.event.count({
where: { eventType: 'tournament' },
});
if (tournamentCount === 0) {
console.log('\nCreating sample tournament...');
const tournament = await prisma.event.create({
data: {
name: 'Sample Tournament',
eventType: 'tournament',
format: 'round_robin',
eventDate: new Date(),
status: 'planned',
ownerId: existingAdmin?.id,
},
});
console.log(`✅ Created sample tournament: ${tournament.name}`);
} else {
console.log('✅ Tournaments already exist');
}
console.log('\n🌱 Seeding completed successfully!');
}
main()
.catch((e) => {
console.error('❌ Seeding failed:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env node
/**
* Script to set up PostgreSQL database for EuchreCamp
* This script creates the database and runs migrations
*/
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
function checkPostgresConnection() {
try {
const dbUrl = process.env.DATABASE_URL;
if (!dbUrl || !dbUrl.startsWith('postgresql://')) {
console.error('❌ DATABASE_URL is not set for PostgreSQL');
console.error('Please update your .env file with:');
console.error('DATABASE_PROVIDER=postgresql');
console.error('DATABASE_URL="postgresql://username:password@localhost:5432/euchre_camp"');
return false;
}
// Try to connect using psql
execSync(`psql "${dbUrl}" -c "SELECT 1"`, { stdio: 'pipe' });
console.log('✅ PostgreSQL connection successful');
return true;
} catch (error) {
console.error('❌ PostgreSQL connection failed:', error.message);
return false;
}
}
function createDatabase() {
try {
const dbUrl = process.env.DATABASE_URL;
const dbName = dbUrl.split('/').pop();
// Create database if it doesn't exist
execSync(`psql "${dbUrl}" -c "CREATE DATABASE ${dbName};" 2>/dev/null || true`, { stdio: 'pipe' });
console.log(`✅ Database "${dbName}" ready`);
return true;
} catch (error) {
console.error('❌ Failed to create database:', error.message);
return false;
}
}
function runMigrations() {
try {
console.log('🔄 Running migrations...');
execSync('npx prisma migrate deploy', { stdio: 'inherit' });
console.log('✅ Migrations completed successfully');
return true;
} catch (error) {
console.error('❌ Migration failed:', error.message);
return false;
}
}
function generatePrismaClient() {
try {
console.log('🔄 Generating Prisma client...');
execSync('npx prisma generate', { stdio: 'inherit' });
console.log('✅ Prisma client generated successfully');
return true;
} catch (error) {
console.error('❌ Prisma client generation failed:', error.message);
return false;
}
}
function main() {
console.log('=== PostgreSQL Setup for EuchreCamp ===\n');
// Check if DATABASE_URL is set
if (!process.env.DATABASE_URL) {
console.error('❌ DATABASE_URL environment variable is not set');
console.error('Please add it to your .env file');
process.exit(1);
}
// Check PostgreSQL connection
if (!checkPostgresConnection()) {
process.exit(1);
}
// Create database
if (!createDatabase()) {
process.exit(1);
}
// Generate Prisma client
if (!generatePrismaClient()) {
process.exit(1);
}
// Run migrations
if (!runMigrations()) {
process.exit(1);
}
console.log('\n✅ PostgreSQL setup completed successfully!');
console.log('\nNext steps:');
console.log('1. Start your development server: npm run dev');
console.log('2. Test the connection by visiting http://localhost:3000');
}
// Run if called directly
if (require.main === module) {
main();
}
module.exports = { checkPostgresConnection, createDatabase, runMigrations, generatePrismaClient };
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env node
/**
* Script to switch between SQLite and PostgreSQL databases
* Usage: node scripts/switch-database.js [sqlite|postgres]
*/
const fs = require('fs');
const path = require('path');
const envFile = '.env';
const envExampleFile = '.env.example';
function updateEnvFile(provider) {
const envPath = path.join(process.cwd(), envFile);
// Read current .env file or create from example
let envContent = '';
if (fs.existsSync(envPath)) {
envContent = fs.readFileSync(envPath, 'utf8');
} else if (fs.existsSync(envExampleFile)) {
envContent = fs.readFileSync(envExampleFile, 'utf8');
}
// Update DATABASE_PROVIDER
const providerRegex = /^DATABASE_PROVIDER=.*$/m;
if (providerRegex.test(envContent)) {
envContent = envContent.replace(providerRegex, `DATABASE_PROVIDER=${provider}`);
} else {
envContent += `\nDATABASE_PROVIDER=${provider}\n`;
}
// Update DATABASE_URL based on provider
if (provider === 'sqlite') {
const sqliteUrl = 'DATABASE_URL="file:./prisma/dev.db"';
const urlRegex = /^DATABASE_URL=.*$/m;
if (urlRegex.test(envContent)) {
envContent = envContent.replace(urlRegex, sqliteUrl);
} else {
envContent += `${sqliteUrl}\n`;
}
} else if (provider === 'postgresql') {
const pgUrl = 'DATABASE_URL="postgresql://username:password@localhost:5432/euchre_camp"';
const urlRegex = /^DATABASE_URL=.*$/m;
if (urlRegex.test(envContent)) {
envContent = envContent.replace(urlRegex, pgUrl);
} else {
envContent += `${pgUrl}\n`;
}
}
// Write updated content
fs.writeFileSync(envPath, envContent);
console.log(`✅ Updated ${envFile} to use ${provider} database`);
}
function main() {
const args = process.argv.slice(2);
const provider = args[0];
if (!provider) {
console.error('❌ Usage: node scripts/switch-database.js [sqlite|postgres]');
process.exit(1);
}
if (!['sqlite', 'postgres', 'postgresql'].includes(provider)) {
console.error(`❌ Invalid provider: ${provider}. Must be 'sqlite' or 'postgres'`);
process.exit(1);
}
const normalizedProvider = provider === 'postgres' ? 'postgresql' : provider;
updateEnvFile(normalizedProvider);
console.log('\nNext steps:');
console.log('1. Run: npx prisma generate');
console.log('2. Run: npx prisma migrate deploy');
console.log('3. Restart your development server');
}
main();