#!/usr/bin/env node import dotenv from 'dotenv'; import { neon } from '@neondatabase/serverless'; dotenv.config({ path: '.env.local' }); async function fixUserCardsConstraints() { const sql = neon(process.env.POSTGRES_URL); try { console.log('šŸ”§ Fixing user_cards table constraints...'); // First, check if there are any duplicate entries that would prevent adding the constraint console.log('šŸ” Checking for duplicate entries...'); const duplicates = await sql` SELECT user_id, card_id, COUNT(*) as count FROM user_cards GROUP BY user_id, card_id HAVING COUNT(*) > 1 `; if (duplicates.length > 0) { console.log(`āš ļø Found ${duplicates.length} duplicate entries. Cleaning up...`); // Remove duplicates by keeping the latest entry for each user/card combination for (const dup of duplicates) { console.log(`Cleaning duplicates for user ${dup.user_id}, card ${dup.card_id}...`); // Keep only the most recent entry await sql` DELETE FROM user_cards WHERE user_id = ${dup.user_id} AND card_id = ${dup.card_id} AND id NOT IN ( SELECT id FROM user_cards WHERE user_id = ${dup.user_id} AND card_id = ${dup.card_id} ORDER BY updated_at DESC, id DESC LIMIT 1 ) `; } console.log('āœ… Cleaned up duplicate entries'); } else { console.log('āœ… No duplicate entries found'); } // Add the unique constraint to user_cards console.log('šŸ”’ Adding unique constraint on user_cards (user_id, card_id)...'); try { await sql` ALTER TABLE user_cards ADD CONSTRAINT user_cards_user_card_unique UNIQUE (user_id, card_id) `; console.log('āœ… Added user_cards unique constraint'); } catch (error) { if (error.message.includes('already exists')) { console.log('āœ… User_cards unique constraint already exists'); } else { throw error; } } // Add the unique constraint to collection_cards console.log('šŸ”’ Adding unique constraint on collection_cards (collection_id, card_id)...'); try { await sql` ALTER TABLE collection_cards ADD CONSTRAINT collection_cards_collection_card_unique UNIQUE (collection_id, card_id) `; console.log('āœ… Added collection_cards unique constraint'); } catch (error) { if (error.message.includes('already exists')) { console.log('āœ… Collection_cards unique constraint already exists'); } else { throw error; } } // Now sync existing owned cards to "All My Cards" collections console.log('šŸ”„ Syncing owned cards to "All My Cards" collections...'); // Get all users with owned cards const usersWithOwnedCards = await sql` SELECT DISTINCT uc.user_id, u.email FROM user_cards uc JOIN users u ON uc.user_id = u.id WHERE uc.quantity > 0 `; console.log(`Found ${usersWithOwnedCards.length} users with owned cards`); for (const user of usersWithOwnedCards) { try { // Find the user's "All My Cards" collection const allMyCardsCollection = await sql` SELECT id FROM collections WHERE user_id = ${user.user_id} AND name = 'All My Cards' AND is_system_collection = true `; if (allMyCardsCollection.length === 0) { console.log(`āš ļø No "All My Cards" collection found for ${user.email}`); continue; } const collectionId = allMyCardsCollection[0].id; // Get all owned cards for this user const ownedCards = await sql` SELECT card_id, quantity FROM user_cards WHERE user_id = ${user.user_id} AND quantity > 0 `; console.log(`Syncing ${ownedCards.length} owned cards for ${user.email}...`); // Add each owned card to the "All My Cards" collection for (const ownedCard of ownedCards) { // Check if card is already in the collection const existingEntry = await sql` SELECT id, quantity FROM collection_cards WHERE collection_id = ${collectionId} AND card_id = ${ownedCard.card_id} `; if (existingEntry.length > 0) { // Update existing entry await sql` UPDATE collection_cards SET quantity = ${ownedCard.quantity} WHERE collection_id = ${collectionId} AND card_id = ${ownedCard.card_id} `; } else { // Insert new entry await sql` INSERT INTO collection_cards (collection_id, card_id, quantity, created_at) VALUES (${collectionId}, ${ownedCard.card_id}, ${ownedCard.quantity}, CURRENT_TIMESTAMP) `; } } console.log(` āœ… Synced ${ownedCards.length} cards for ${user.email}`); } catch (error) { console.error(` āŒ Failed to sync cards for ${user.email}:`, error.message); } } console.log('\nšŸŽ‰ Migration completed successfully!'); console.log('\nšŸ“‹ Summary:'); console.log(` • Fixed unique constraint on user_cards table`); console.log(` • Synced owned cards to "All My Cards" collections`); console.log(` • Card ownership API should now work properly`); } catch (error) { console.error('āŒ Migration failed:', error.message); console.error('Full error:', error); process.exit(1); } } if (import.meta.url === `file://${process.argv[1]}`) { fixUserCardsConstraints(); } export { fixUserCardsConstraints };