deckhearth/pages/api/cards/index.js

163 lines
No EOL
4.2 KiB
JavaScript

import { sql } from '@vercel/postgres';
import { verifyToken } from '../auth-utils.js';
// GET /api/cards - Search cards from database
export default async function handler(req, res) {
// Set CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// Handle preflight requests
if (req.method === 'OPTIONS') {
res.status(200).end();
return;
}
if (req.method !== 'GET' && req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const { q, search, game, page = '1', limit = '20' } = req.query;
const query = q || search || '';
const pageNum = parseInt(page);
const limitNum = parseInt(limit);
const offset = (pageNum - 1) * limitNum;
console.log(`🔍 Searching cards: "${query}" game: "${game}" page: ${pageNum}`);
// 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(limitNum, 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);
// Format the response
const cards = result.rows.map(card => ({
id: card.id,
name: card.name,
setName: card.set_name,
setCode: card.set_code,
cardNumber: card.card_number,
rarity: card.rarity,
game: card.game,
manaCost: card.mana_cost,
cmc: card.cmc,
cardType: card.card_type,
colors: card.colors ? JSON.parse(card.colors) : [],
oracleText: card.oracle_text,
power: card.power,
toughness: card.toughness,
imageUrl: card.image_url,
stockImageUrl: card.stock_image_url,
currentPrice: card.current_price,
marketPrice: card.market_price,
verified: card.verified,
createdAt: card.created_at,
updatedAt: card.updated_at
}));
return res.status(200).json({
success: true,
cards,
pagination: {
page: pageNum,
limit: limitNum,
total,
pages: Math.ceil(total / limitNum)
}
});
} catch (error) {
console.error('❌ Error in cards API:', error);
return res.status(500).json({
error: 'Failed to search cards',
details: error.message
});
}
}