135 lines
4.7 KiB
TypeScript
135 lines
4.7 KiB
TypeScript
|
|
import { config } from 'dotenv';
|
||
|
|
import { PrismaClient } from '@prisma/client';
|
||
|
|
import { Pool } from 'pg';
|
||
|
|
import { PrismaPg } from '@prisma/adapter-pg';
|
||
|
|
|
||
|
|
// Load .env.local first, then .env
|
||
|
|
config({ path: '.env.local' });
|
||
|
|
config({ path: '.env' });
|
||
|
|
|
||
|
|
const connectionString = process.env.DATABASE_URL;
|
||
|
|
|
||
|
|
if (!connectionString) {
|
||
|
|
throw new Error('DATABASE_URL environment variable is not set');
|
||
|
|
}
|
||
|
|
|
||
|
|
const pool = new Pool({ connectionString });
|
||
|
|
const adapter = new PrismaPg(pool);
|
||
|
|
const prisma = new PrismaClient({ adapter });
|
||
|
|
|
||
|
|
async function listChurchWebsites() {
|
||
|
|
try {
|
||
|
|
console.log('Fetching churches from database...\n');
|
||
|
|
|
||
|
|
const churches = await prisma.church.findMany({
|
||
|
|
select: {
|
||
|
|
id: true,
|
||
|
|
name: true,
|
||
|
|
city: true,
|
||
|
|
state: true,
|
||
|
|
country: true,
|
||
|
|
website: true,
|
||
|
|
googlePlaceId: true,
|
||
|
|
},
|
||
|
|
orderBy: [
|
||
|
|
{ country: 'asc' },
|
||
|
|
{ state: 'asc' },
|
||
|
|
{ city: 'asc' },
|
||
|
|
],
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log(`Total churches: ${churches.length}`);
|
||
|
|
|
||
|
|
const withWebsite = churches.filter(c => c.website);
|
||
|
|
const withGoogle = churches.filter(c => c.googlePlaceId);
|
||
|
|
const withoutWebsite = churches.filter(c => !c.website);
|
||
|
|
|
||
|
|
console.log(`Churches with website: ${withWebsite.length}`);
|
||
|
|
console.log(`Churches with Google Place ID: ${withGoogle.length}`);
|
||
|
|
console.log(`Churches without website: ${withoutWebsite.length}\n`);
|
||
|
|
|
||
|
|
// Group by country
|
||
|
|
const byCountry = churches.reduce((acc, church) => {
|
||
|
|
const country = church.country || 'Unknown';
|
||
|
|
if (!acc[country]) {
|
||
|
|
acc[country] = [];
|
||
|
|
}
|
||
|
|
acc[country].push(church);
|
||
|
|
return acc;
|
||
|
|
}, {} as Record<string, typeof churches>);
|
||
|
|
|
||
|
|
// Write to file
|
||
|
|
let output = '# Church Websites\n\n';
|
||
|
|
output += `Generated: ${new Date().toISOString()}\n\n`;
|
||
|
|
output += `## Summary\n`;
|
||
|
|
output += `- Total churches: ${churches.length}\n`;
|
||
|
|
output += `- With website: ${withWebsite.length} (${((withWebsite.length / churches.length) * 100).toFixed(1)}%)\n`;
|
||
|
|
output += `- With Google Place ID: ${withGoogle.length} (${((withGoogle.length / churches.length) * 100).toFixed(1)}%)\n`;
|
||
|
|
output += `- Without website: ${withoutWebsite.length} (${((withoutWebsite.length / churches.length) * 100).toFixed(1)}%)\n\n`;
|
||
|
|
|
||
|
|
// Add country breakdown
|
||
|
|
output += `## By Country\n\n`;
|
||
|
|
Object.entries(byCountry)
|
||
|
|
.sort(([, a], [, b]) => b.length - a.length)
|
||
|
|
.forEach(([country, countryChurches]) => {
|
||
|
|
const withSite = countryChurches.filter(c => c.website).length;
|
||
|
|
const withGoogle = countryChurches.filter(c => c.googlePlaceId).length;
|
||
|
|
output += `### ${country} (${countryChurches.length} churches)\n`;
|
||
|
|
output += `- With website: ${withSite} (${((withSite / countryChurches.length) * 100).toFixed(1)}%)\n`;
|
||
|
|
output += `- With Google Place ID: ${withGoogle} (${((withGoogle / countryChurches.length) * 100).toFixed(1)}%)\n\n`;
|
||
|
|
});
|
||
|
|
|
||
|
|
// List all websites
|
||
|
|
output += `## All Websites\n\n`;
|
||
|
|
Object.entries(byCountry)
|
||
|
|
.sort(([a], [b]) => a.localeCompare(b))
|
||
|
|
.forEach(([country, countryChurches]) => {
|
||
|
|
output += `### ${country}\n\n`;
|
||
|
|
countryChurches.forEach(church => {
|
||
|
|
const location = [church.city, church.state, church.country].filter(Boolean).join(', ');
|
||
|
|
if (church.website) {
|
||
|
|
output += `- **${church.name}** (${location})\n`;
|
||
|
|
output += ` - Website: ${church.website}\n`;
|
||
|
|
if (church.googlePlaceId) {
|
||
|
|
output += ` - Google Place ID: ${church.googlePlaceId}\n`;
|
||
|
|
}
|
||
|
|
output += ` - DB ID: ${church.id}\n\n`;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// List churches without websites
|
||
|
|
output += `## Churches Without Websites\n\n`;
|
||
|
|
Object.entries(byCountry)
|
||
|
|
.sort(([a], [b]) => a.localeCompare(b))
|
||
|
|
.forEach(([country, countryChurches]) => {
|
||
|
|
const without = countryChurches.filter(c => !c.website);
|
||
|
|
if (without.length > 0) {
|
||
|
|
output += `### ${country}\n\n`;
|
||
|
|
without.forEach(church => {
|
||
|
|
const location = [church.city, church.state, church.country].filter(Boolean).join(', ');
|
||
|
|
output += `- **${church.name}** (${location})\n`;
|
||
|
|
if (church.googlePlaceId) {
|
||
|
|
output += ` - Google Place ID: ${church.googlePlaceId}\n`;
|
||
|
|
}
|
||
|
|
output += ` - DB ID: ${church.id}\n\n`;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// Write to file
|
||
|
|
const fs = await import('fs/promises');
|
||
|
|
await fs.writeFile('church-websites.md', output);
|
||
|
|
console.log('✓ Written to church-websites.md');
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Error:', error);
|
||
|
|
process.exit(1);
|
||
|
|
} finally {
|
||
|
|
await prisma.$disconnect();
|
||
|
|
await pool.end();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
listChurchWebsites();
|