Initial commit
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function validateDatabaseIntegrity() {
|
||||
console.log('🔍 Running comprehensive database integrity check...');
|
||||
|
||||
try {
|
||||
// 1. Check Video table integrity
|
||||
console.log('\n📹 Checking Video table...');
|
||||
const videos = await prisma.video.findMany({
|
||||
include: {
|
||||
playlist: true,
|
||||
uploader: true,
|
||||
_count: {
|
||||
select: {
|
||||
comments: true,
|
||||
likes: true,
|
||||
progress: true,
|
||||
unlocks: true,
|
||||
watchSegments: true,
|
||||
videoCourses: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log(`✅ Found ${videos.length} videos`);
|
||||
|
||||
// 2. Check for videos with missing playlists
|
||||
const videosWithMissingPlaylists = videos.filter(v => !v.playlist);
|
||||
if (videosWithMissingPlaylists.length > 0) {
|
||||
console.log(`⚠️ Found ${videosWithMissingPlaylists.length} videos with missing playlists:`);
|
||||
videosWithMissingPlaylists.forEach(v => {
|
||||
console.log(` - Video ID: ${v.id}, Title: "${v.title}", Playlist ID: ${v.playlistId}`);
|
||||
});
|
||||
}
|
||||
|
||||
// 3. Check for playlists with no videos
|
||||
console.log('\n📋 Checking Playlist table...');
|
||||
const playlists = await prisma.playlist.findMany({
|
||||
include: {
|
||||
videos: true,
|
||||
course: true,
|
||||
_count: {
|
||||
select: {
|
||||
videos: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log(`✅ Found ${playlists.length} playlists`);
|
||||
|
||||
const emptyPlaylists = playlists.filter(p => p.videos.length === 0);
|
||||
if (emptyPlaylists.length > 0) {
|
||||
console.log(`⚠️ Found ${emptyPlaylists.length} empty playlists:`);
|
||||
emptyPlaylists.forEach(p => {
|
||||
console.log(` - Playlist ID: ${p.id}, Title: "${p.title}", Course: ${p.course?.title || 'Unknown'}`);
|
||||
});
|
||||
}
|
||||
|
||||
// 4. Check VideoProgress integrity
|
||||
console.log('\n📊 Checking VideoProgress table...');
|
||||
const progressCount = await prisma.videoProgress.count();
|
||||
console.log(`✅ Found ${progressCount} progress records`);
|
||||
|
||||
// Check for progress records with invalid video references
|
||||
const invalidProgress = await prisma.$queryRaw`
|
||||
SELECT vp.id, vp."videoId", vp."userId"
|
||||
FROM "VideoProgress" vp
|
||||
LEFT JOIN "Video" v ON vp."videoId" = v.id
|
||||
WHERE v.id IS NULL
|
||||
` as Array<{id: string, videoId: string, userId: string}>;
|
||||
|
||||
if (invalidProgress.length > 0) {
|
||||
console.log(`❌ Found ${invalidProgress.length} progress records with invalid video references:`);
|
||||
invalidProgress.forEach(p => {
|
||||
console.log(` - Progress ID: ${p.id}, Video ID: ${p.videoId}, User ID: ${p.userId}`);
|
||||
});
|
||||
}
|
||||
|
||||
// 5. Check VideoWatchSegment integrity
|
||||
console.log('\n⏱️ Checking VideoWatchSegment table...');
|
||||
const segmentsCount = await prisma.videoWatchSegment.count();
|
||||
console.log(`✅ Found ${segmentsCount} watch segments`);
|
||||
|
||||
// Check for segments with invalid video references
|
||||
const invalidSegments = await prisma.$queryRaw`
|
||||
SELECT vws.id, vws."videoId", vws."userId"
|
||||
FROM "VideoWatchSegment" vws
|
||||
LEFT JOIN "Video" v ON vws."videoId" = v.id
|
||||
WHERE v.id IS NULL
|
||||
` as Array<{id: string, videoId: string, userId: string}>;
|
||||
|
||||
if (invalidSegments.length > 0) {
|
||||
console.log(`❌ Found ${invalidSegments.length} watch segments with invalid video references:`);
|
||||
invalidSegments.forEach(s => {
|
||||
console.log(` - Segment ID: ${s.id}, Video ID: ${s.videoId}, User ID: ${s.userId}`);
|
||||
});
|
||||
}
|
||||
|
||||
// 6. Check for duplicate video indexes within playlists
|
||||
console.log('\n🔄 Checking for duplicate video indexes...');
|
||||
for (const playlist of playlists) {
|
||||
if (playlist.videos.length > 0) {
|
||||
const indexes = playlist.videos.map(v => v.index);
|
||||
const uniqueIndexes = [...new Set(indexes)];
|
||||
if (indexes.length !== uniqueIndexes.length) {
|
||||
console.log(`⚠️ Playlist "${playlist.title}" has duplicate video indexes:`);
|
||||
const duplicates = indexes.filter((item, index) => indexes.indexOf(item) !== index);
|
||||
console.log(` - Duplicate indexes: ${duplicates.join(', ')}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Check Enrollment integrity
|
||||
console.log('\n📚 Checking Enrollment table...');
|
||||
const enrollments = await prisma.enrollment.findMany({
|
||||
include: {
|
||||
user: true,
|
||||
course: true
|
||||
}
|
||||
});
|
||||
console.log(`✅ Found ${enrollments.length} enrollments`);
|
||||
|
||||
const enrollmentsWithMissingUser = enrollments.filter(e => !e.user);
|
||||
const enrollmentsWithMissingCourse = enrollments.filter(e => !e.course);
|
||||
|
||||
if (enrollmentsWithMissingUser.length > 0) {
|
||||
console.log(`❌ Found ${enrollmentsWithMissingUser.length} enrollments with missing users`);
|
||||
}
|
||||
if (enrollmentsWithMissingCourse.length > 0) {
|
||||
console.log(`❌ Found ${enrollmentsWithMissingCourse.length} enrollments with missing courses`);
|
||||
}
|
||||
|
||||
// 8. Summary
|
||||
console.log('\n📋 Database Integrity Summary:');
|
||||
console.log(` Videos: ${videos.length}`);
|
||||
console.log(` Playlists: ${playlists.length} (${emptyPlaylists.length} empty)`);
|
||||
console.log(` Progress Records: ${progressCount}`);
|
||||
console.log(` Watch Segments: ${segmentsCount}`);
|
||||
console.log(` Enrollments: ${enrollments.length}`);
|
||||
|
||||
const hasIssues = videosWithMissingPlaylists.length > 0 ||
|
||||
invalidProgress.length > 0 ||
|
||||
invalidSegments.length > 0 ||
|
||||
enrollmentsWithMissingUser.length > 0 ||
|
||||
enrollmentsWithMissingCourse.length > 0;
|
||||
|
||||
if (!hasIssues) {
|
||||
console.log('✨ All integrity checks passed! Database appears healthy.');
|
||||
} else {
|
||||
console.log('⚠️ Some integrity issues found. See details above.');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error during integrity check:', error);
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// Run the integrity check
|
||||
validateDatabaseIntegrity()
|
||||
.then(() => {
|
||||
console.log('🔧 Database integrity check completed');
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('💥 Integrity check failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user