Add database reset script and update package.json for db commands; refactor middleware for CORS support and error handling in parks page

This commit is contained in:
pacnpal
2025-02-23 18:09:27 -05:00
parent 04acef4766
commit 41c747ab03
6 changed files with 255 additions and 279 deletions

View File

@@ -1,110 +1,88 @@
import { NextResponse } from 'next/server';
import { Prisma } from '@prisma/client';
import prisma from '@/lib/prisma';
import type { ParkStatus } from '@/types/api';
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const search = searchParams.get('search')?.trim();
const status = searchParams.get('status') as ParkStatus;
const ownerId = searchParams.get('ownerId');
const hasOwner = searchParams.get('hasOwner');
const minRides = parseInt(searchParams.get('minRides') || '');
const minCoasters = parseInt(searchParams.get('minCoasters') || '');
const minSize = parseInt(searchParams.get('minSize') || '');
const openingDateStart = searchParams.get('openingDateStart');
const openingDateEnd = searchParams.get('openingDateEnd');
const where = {
AND: [] as any[]
};
// Search filter
if (search) {
where.AND.push({
OR: [
{ name: { contains: search, mode: 'insensitive' } },
{ description: { contains: search, mode: 'insensitive' } },
{ owner: { name: { contains: search, mode: 'insensitive' } } }
]
});
// Test raw query first
try {
console.log('Testing database connection...');
const rawResult = await prisma.$queryRaw`SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = 'public'`;
console.log('Available tables:', rawResult);
} catch (connectionError) {
console.error('Raw query test failed:', connectionError);
throw new Error('Database connection test failed');
}
// Status filter
if (status) {
where.AND.push({ status });
}
// Basic query with explicit types
try {
const queryResult = await prisma.$transaction(async (tx) => {
// Count total parks
const totalCount = await tx.park.count();
console.log('Total parks count:', totalCount);
// Owner filters
if (ownerId) {
where.AND.push({ ownerId });
}
if (hasOwner !== null) {
where.AND.push({ owner: hasOwner === 'true' ? { not: null } : null });
}
// Numeric filters
if (!isNaN(minRides)) {
where.AND.push({ ride_count: { gte: minRides } });
}
if (!isNaN(minCoasters)) {
where.AND.push({ coaster_count: { gte: minCoasters } });
}
if (!isNaN(minSize)) {
where.AND.push({ size_acres: { gte: minSize } });
}
// Date range filter
if (openingDateStart || openingDateEnd) {
const dateFilter: any = {};
if (openingDateStart) {
dateFilter.gte = new Date(openingDateStart);
}
if (openingDateEnd) {
dateFilter.lte = new Date(openingDateEnd);
}
where.AND.push({ opening_date: dateFilter });
}
const parks = await prisma.park.findMany({
where: where.AND.length > 0 ? where : undefined,
include: {
owner: {
// Fetch parks with minimal fields
const parks = await tx.park.findMany({
take: 10,
select: {
id: true,
name: true,
slug: true
}
},
location: true,
_count: {
select: {
rides: true
slug: true,
status: true,
owner: {
select: {
id: true,
name: true
}
}
},
orderBy: {
name: 'asc'
}
} satisfies Prisma.ParkFindManyArgs);
return { totalCount, parks };
});
return NextResponse.json({
success: true,
data: queryResult.parks,
meta: {
total: queryResult.totalCount
}
},
orderBy: [
{ status: 'asc' },
{ name: 'asc' }
]
});
});
const formattedParks = parks.map(park => ({
...park,
ride_count: park._count.rides,
_count: undefined
}));
return NextResponse.json({
success: true,
data: formattedParks
});
} catch (queryError) {
if (queryError instanceof Prisma.PrismaClientKnownRequestError) {
console.error('Known Prisma error:', {
code: queryError.code,
meta: queryError.meta,
message: queryError.message
});
throw new Error(`Database query failed: ${queryError.code}`);
}
throw queryError;
}
} catch (error) {
console.error('Error in /api/parks:', error);
return NextResponse.json({
success: false,
error: 'Failed to fetch parks'
}, { status: 500 });
console.error('Error in /api/parks:', {
name: error instanceof Error ? error.name : 'Unknown',
message: error instanceof Error ? error.message : 'Unknown error',
stack: error instanceof Error ? error.stack : undefined
});
return NextResponse.json(
{
success: false,
error: error instanceof Error ? error.message : 'Failed to fetch parks'
},
{
status: 500,
headers: {
'Cache-Control': 'no-store, must-revalidate',
'Content-Type': 'application/json'
}
}
);
}
}