deckhearth/api/cards/search.js

158 lines
No EOL
4 KiB
JavaScript

import { NextResponse } from 'next/server';
import { sql } from '@vercel/postgres';
// GET /api/cards/search - Search cards from database
export async function GET(request) {
try {
const { searchParams } = new URL(request.url);
const query = searchParams.get('q') || searchParams.get('search') || '';
const game = searchParams.get('game');
const page = parseInt(searchParams.get('page') || '1');
const limit = parseInt(searchParams.get('limit') || '20');
const offset = (page - 1) * limit;
console.log(`🔍 Searching cards: "${query}" game: "${game}" page: ${page}`);
// Build the SQL query
let sqlQuery = `
SELECT
id,
name,
set_name,
set_code,
card_number,
rarity,
game,
mana_cost,
cmc,
card_type,
colors,
oracle_text,
power,
toughness,
image_url,
stock_image_url,
current_price,
market_price,
verified,
created_at,
updated_at
FROM cards
WHERE 1=1
`;
const params = [];
let paramIndex = 1;
// Add search filter
if (query.trim()) {
sqlQuery += ` AND (
name ILIKE $${paramIndex} OR
oracle_text ILIKE $${paramIndex} OR
card_type ILIKE $${paramIndex} OR
set_name ILIKE $${paramIndex}
)`;
params.push(`%${query}%`);
paramIndex++;
}
// Add game filter
if (game && game !== 'ALL') {
sqlQuery += ` AND game = $${paramIndex}`;
params.push(game);
paramIndex++;
}
// Add ordering and pagination
sqlQuery += ` ORDER BY name ASC LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`;
params.push(limit, offset);
console.log(`📝 SQL Query: ${sqlQuery}`);
console.log(`📝 Parameters:`, params);
// Execute the query
const result = await sql.query(sqlQuery, params);
// Get total count for pagination
let countQuery = `
SELECT COUNT(*) as total
FROM cards
WHERE 1=1
`;
const countParams = [];
let countParamIndex = 1;
if (query.trim()) {
countQuery += ` AND (
name ILIKE $${countParamIndex} OR
oracle_text ILIKE $${countParamIndex} OR
card_type ILIKE $${countParamIndex} OR
set_name ILIKE $${countParamIndex}
)`;
countParams.push(`%${query}%`);
countParamIndex++;
}
if (game && game !== 'ALL') {
countQuery += ` AND game = $${countParamIndex}`;
countParams.push(game);
countParamIndex++;
}
const countResult = await sql.query(countQuery, countParams);
const total = parseInt(countResult.rows[0].total);
// Transform the results
const cards = result.rows.map(row => ({
id: row.id,
name: row.name,
set_name: row.set_name,
set_code: row.set_code,
card_number: row.card_number,
rarity: row.rarity,
game: row.game,
mana_cost: row.mana_cost,
cmc: row.cmc,
card_type: row.card_type,
colors: row.colors ? JSON.parse(row.colors) : [],
oracle_text: row.oracle_text,
power: row.power,
toughness: row.toughness,
image_url: row.image_url,
stock_image_url: row.stock_image_url,
current_price: row.current_price,
market_price: row.market_price,
verified: row.verified,
createdAt: row.created_at,
updatedAt: row.updated_at,
}));
console.log(`✅ Found ${cards.length} cards (total: ${total})`);
return NextResponse.json({
success: true,
data: cards,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit),
hasNext: page * limit < total,
hasPrev: page > 1
},
search: {
query,
game,
results: cards.length
}
});
} catch (error) {
console.error('❌ Error searching cards:', error);
return NextResponse.json(
{ error: 'Failed to search cards', details: error.message },
{ status: 500 }
);
}
}