#!/usr/bin/env node /** * Media Library Database Test Script * Tests all database operations for uploads and folders */ const { pool } = require("./config/database"); const logger = require("./config/logger"); async function testDatabaseOperations() { console.log("\n🧪 Testing Media Library Database Operations\n"); console.log("=".repeat(60)); try { // Test 1: Check database connection console.log("\n1ļøāƒ£ Testing Database Connection..."); const connectionTest = await pool.query("SELECT NOW()"); console.log(" āœ… Database connected:", connectionTest.rows[0].now); // Test 2: Check uploads table structure console.log("\n2ļøāƒ£ Checking uploads table structure..."); const uploadsSchema = await pool.query(` SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name = 'uploads' ORDER BY ordinal_position `); console.log(" āœ… Uploads table columns:"); uploadsSchema.rows.forEach((col) => { console.log( ` - ${col.column_name} (${col.data_type}, nullable: ${col.is_nullable})` ); }); // Test 3: Check media_folders table structure console.log("\n3ļøāƒ£ Checking media_folders table structure..."); const foldersSchema = await pool.query(` SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name = 'media_folders' ORDER BY ordinal_position `); console.log(" āœ… Media folders table columns:"); foldersSchema.rows.forEach((col) => { console.log( ` - ${col.column_name} (${col.data_type}, nullable: ${col.is_nullable})` ); }); // Test 4: Check foreign key constraints console.log("\n4ļøāƒ£ Checking foreign key constraints..."); const constraints = await pool.query(` SELECT tc.constraint_name, tc.table_name, kcu.column_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name FROM information_schema.table_constraints AS tc JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name AND ccu.table_schema = tc.table_schema WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_name IN ('uploads', 'media_folders') `); console.log(" āœ… Foreign key constraints:"); constraints.rows.forEach((fk) => { console.log( ` - ${fk.table_name}.${fk.column_name} → ${fk.foreign_table_name}.${fk.foreign_column_name}` ); }); // Test 5: Count existing data console.log("\n5ļøāƒ£ Counting existing data..."); const fileCount = await pool.query("SELECT COUNT(*) as count FROM uploads"); const folderCount = await pool.query( "SELECT COUNT(*) as count FROM media_folders" ); console.log(` āœ… Total files: ${fileCount.rows[0].count}`); console.log(` āœ… Total folders: ${folderCount.rows[0].count}`); // Test 6: List all files if (parseInt(fileCount.rows[0].count) > 0) { console.log("\n6ļøāƒ£ Listing all files in database..."); const files = await pool.query(` SELECT id, original_name, file_size, folder_id, uploaded_by, created_at FROM uploads ORDER BY created_at DESC LIMIT 10 `); console.log(" āœ… Recent files:"); files.rows.forEach((file) => { const size = (file.file_size / 1024).toFixed(2) + " KB"; const folder = file.folder_id ? `Folder #${file.folder_id}` : "Root"; console.log( ` - [ID: ${file.id}] ${file.original_name} (${size}) - ${folder}` ); }); } // Test 7: List all folders if (parseInt(folderCount.rows[0].count) > 0) { console.log("\n7ļøāƒ£ Listing all folders in database..."); const folders = await pool.query(` SELECT id, name, parent_id, created_by, created_at, (SELECT COUNT(*) FROM uploads WHERE folder_id = media_folders.id) as file_count FROM media_folders ORDER BY created_at DESC `); console.log(" āœ… Folders:"); folders.rows.forEach((folder) => { const parent = folder.parent_id ? `Parent #${folder.parent_id}` : "Root"; console.log( ` - [ID: ${folder.id}] ${folder.name} (${folder.file_count} files) - ${parent}` ); }); } // Test 8: Test folder query with file counts console.log("\n8ļøāƒ£ Testing folder query with file counts..."); const foldersWithCounts = await pool.query(` SELECT mf.*, COUNT(u.id) as file_count FROM media_folders mf LEFT JOIN uploads u ON u.folder_id = mf.id GROUP BY mf.id ORDER BY mf.created_at DESC `); console.log( ` āœ… Query returned ${foldersWithCounts.rows.length} folders with accurate file counts` ); // Test 9: Test cascade delete (dry run) console.log("\n9ļøāƒ£ Testing cascade delete rules..."); const cascadeRules = await pool.query(` SELECT tc.constraint_name, rc.delete_rule FROM information_schema.table_constraints tc JOIN information_schema.referential_constraints rc ON tc.constraint_name = rc.constraint_name WHERE tc.table_name IN ('uploads', 'media_folders') AND tc.constraint_type = 'FOREIGN KEY' `); console.log(" āœ… Delete rules:"); cascadeRules.rows.forEach((rule) => { console.log(` - ${rule.constraint_name}: ${rule.delete_rule}`); }); // Test 10: Verify indexes console.log("\nšŸ”Ÿ Checking database indexes..."); const indexes = await pool.query(` SELECT tablename, indexname, indexdef FROM pg_indexes WHERE tablename IN ('uploads', 'media_folders') AND schemaname = 'public' ORDER BY tablename, indexname `); console.log(" āœ… Indexes:"); indexes.rows.forEach((idx) => { console.log(` - ${idx.tablename}.${idx.indexname}`); }); console.log("\n" + "=".repeat(60)); console.log("āœ… All database tests passed successfully!\n"); console.log("šŸ“Š Summary:"); console.log(` - Database: Connected and operational`); console.log( ` - Tables: uploads (${uploadsSchema.rows.length} columns), media_folders (${foldersSchema.rows.length} columns)` ); console.log( ` - Data: ${fileCount.rows[0].count} files, ${folderCount.rows[0].count} folders` ); console.log( ` - Constraints: ${constraints.rows.length} foreign keys configured` ); console.log(` - Indexes: ${indexes.rows.length} indexes for performance`); console.log( "\nāœ… Media library database is properly configured and operational!\n" ); } catch (error) { console.error("\nāŒ Database test failed:", error.message); console.error("Stack trace:", error.stack); process.exit(1); } finally { await pool.end(); } } // Run tests testDatabaseOperations();