158 lines
No EOL
4 KiB
JavaScript
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 }
|
|
);
|
|
}
|
|
}
|