|
| 1 | +import { generateClient } from 'aws-amplify/data'; |
| 2 | +import type { Schema } from '../../../amplify/data/resource'; |
| 3 | + |
| 4 | +import channelData from '../../../script/init/Channel.json'; |
| 5 | +import classData from '../../../script/init/Class.json'; |
| 6 | +import commentData from '../../../script/init/Comment.json'; |
| 7 | +import courseData from '../../../script/init/Course.json'; |
| 8 | + |
| 9 | +const client = generateClient<Schema>(); |
| 10 | + |
| 11 | +export const testConnection = async () => { |
| 12 | + console.log('=== Testing Amplify connection ==='); |
| 13 | + try { |
| 14 | + const testCourse = await client.models.Course.create({ |
| 15 | + name: 'Test Course' |
| 16 | + }); |
| 17 | + console.log('Test course created:', testCourse); |
| 18 | + |
| 19 | + const courses = await client.models.Course.list(); |
| 20 | + console.log('All courses:', courses); |
| 21 | + |
| 22 | + if (testCourse.data?.id) { |
| 23 | + await client.models.Course.delete({ id: testCourse.data.id }); |
| 24 | + console.log('Test course deleted'); |
| 25 | + } |
| 26 | + |
| 27 | + return { success: true, message: 'Connection test successful!' }; |
| 28 | + } catch (error) { |
| 29 | + console.error('Connection test failed:', error); |
| 30 | + return { success: false, message: `Connection test failed: ${error}` }; |
| 31 | + } |
| 32 | +}; |
| 33 | + |
| 34 | +export const convertDynamoDBItem = (item: any) => { |
| 35 | + console.log('Converting DynamoDB item:', item); |
| 36 | + const converted: any = {}; |
| 37 | + for (const [key, value] of Object.entries(item)) { |
| 38 | + if (typeof value === 'object' && value !== null) { |
| 39 | + if ('S' in value) { |
| 40 | + converted[key] = value.S; |
| 41 | + console.log(`Converted ${key}: ${value.S} (String)`); |
| 42 | + } else if ('N' in value) { |
| 43 | + converted[key] = parseInt(value.N); |
| 44 | + console.log(`Converted ${key}: ${value.N} (Number)`); |
| 45 | + } else if ('BOOL' in value) { |
| 46 | + converted[key] = value.BOOL; |
| 47 | + console.log(`Converted ${key}: ${value.BOOL} (Boolean)`); |
| 48 | + } else { |
| 49 | + console.warn(`Unknown DynamoDB type for ${key}:`, value); |
| 50 | + } |
| 51 | + } |
| 52 | + } |
| 53 | + console.log('Final converted item:', converted); |
| 54 | + return converted; |
| 55 | +}; |
| 56 | + |
| 57 | +export const uploadSampleData = async ( |
| 58 | + setProgress: (progress: number) => void, |
| 59 | + setMessage: (message: { type: 'success' | 'error', text: string }) => void |
| 60 | +) => { |
| 61 | + console.log('=== Starting sample data upload ==='); |
| 62 | + setProgress(0); |
| 63 | + |
| 64 | + try { |
| 65 | + const courseItems = courseData.Course || []; |
| 66 | + const classItems = classData.Class || []; |
| 67 | + const commentItems = commentData.Comment || []; |
| 68 | + |
| 69 | + console.log(`Found items - Course: ${courseItems.length}, Class: ${classItems.length}, Comment: ${commentItems.length}`); |
| 70 | + |
| 71 | + console.log('=== Starting Course upload ==='); |
| 72 | + setProgress(10); |
| 73 | + const courseIdMap: Record<string, string> = {}; |
| 74 | + |
| 75 | + const coursePromises = courseItems.map(async (item) => { |
| 76 | + const course = convertDynamoDBItem(item.PutRequest.Item); |
| 77 | + const result = await client.models.Course.create({ name: course.name }); |
| 78 | + if (result.data?.id) { |
| 79 | + courseIdMap[course.id] = result.data.id; |
| 80 | + console.log(`Course mapping: ${course.id} -> ${result.data.id}`); |
| 81 | + } |
| 82 | + return result; |
| 83 | + }); |
| 84 | + await Promise.all(coursePromises); |
| 85 | + console.log('All courses uploaded'); |
| 86 | + setProgress(30); |
| 87 | + |
| 88 | + console.log('=== Starting Class upload ==='); |
| 89 | + const classPromises = classItems.map(async (item) => { |
| 90 | + const classItem = convertDynamoDBItem(item.PutRequest.Item); |
| 91 | + const mappedCourseId = courseIdMap[classItem.courseId] || classItem.courseId; |
| 92 | + |
| 93 | + console.log(`Class ${classItem.name}: id ${classItem.id}, courseId ${classItem.courseId} -> ${mappedCourseId}`); |
| 94 | + |
| 95 | + return client.models.Class.create({ |
| 96 | + id: classItem.id, |
| 97 | + name: classItem.name, |
| 98 | + courseId: mappedCourseId, |
| 99 | + description: classItem.description || undefined, |
| 100 | + image: classItem.image || undefined, |
| 101 | + class_flag: classItem.class_flag || 0, |
| 102 | + url: classItem.url || undefined, |
| 103 | + transcript: classItem.transcript || undefined, |
| 104 | + author: classItem.author || undefined, |
| 105 | + }); |
| 106 | + }); |
| 107 | + await Promise.all(classPromises); |
| 108 | + console.log('All classes uploaded'); |
| 109 | + setProgress(60); |
| 110 | + |
| 111 | + console.log('=== Starting Comment upload (batch processing) ==='); |
| 112 | + const batchSize = 10; |
| 113 | + const commentBatches = []; |
| 114 | + |
| 115 | + for (let i = 0; i < commentItems.length; i += batchSize) { |
| 116 | + commentBatches.push(commentItems.slice(i, i + batchSize)); |
| 117 | + } |
| 118 | + |
| 119 | + console.log(`Processing ${commentBatches.length} batches of comments`); |
| 120 | + |
| 121 | + for (let batchIndex = 0; batchIndex < commentBatches.length; batchIndex++) { |
| 122 | + const batch = commentBatches[batchIndex]; |
| 123 | + const batchPromises = batch.map(async (item) => { |
| 124 | + const comment = convertDynamoDBItem(item.PutRequest.Item); |
| 125 | + return client.models.Comment.create({ |
| 126 | + classId: comment.classId || undefined, |
| 127 | + content: comment.content || undefined, |
| 128 | + commentVersion: comment.commentVersion || undefined, |
| 129 | + }); |
| 130 | + }); |
| 131 | + |
| 132 | + await Promise.all(batchPromises); |
| 133 | + const progress = 60 + ((batchIndex + 1) / commentBatches.length) * 40; |
| 134 | + setProgress(progress); |
| 135 | + console.log(`Batch ${batchIndex + 1}/${commentBatches.length} completed`); |
| 136 | + } |
| 137 | + |
| 138 | + console.log('=== Upload completed successfully ==='); |
| 139 | + setMessage({ |
| 140 | + type: 'success', |
| 141 | + text: `Sample data upload completed with courseId mapping! (Course: ${courseItems.length}, Class: ${classItems.length}, Comment: ${commentItems.length})` |
| 142 | + }); |
| 143 | + } catch (error) { |
| 144 | + console.error('=== Upload failed ===', error); |
| 145 | + setMessage({ |
| 146 | + type: 'error', |
| 147 | + text: `Upload failed: ${error instanceof Error ? error.message : 'Unknown error'}` |
| 148 | + }); |
| 149 | + } |
| 150 | +}; |
| 151 | + |
| 152 | +export const deleteSampleData = async ( |
| 153 | + setProgress: (progress: number) => void, |
| 154 | + setMessage: (message: { type: 'success' | 'error', text: string }) => void |
| 155 | +) => { |
| 156 | + console.log('=== Starting data deletion ==='); |
| 157 | + setProgress(0); |
| 158 | + |
| 159 | + try { |
| 160 | + let totalDeleted = 0; |
| 161 | + let totalItems = 0; |
| 162 | + |
| 163 | + console.log('=== Counting all items ==='); |
| 164 | + const comments = await client.models.Comment.list({ limit: 1000 }); |
| 165 | + const classes = await client.models.Class.list({ limit: 1000 }); |
| 166 | + const courses = await client.models.Course.list({ limit: 1000 }); |
| 167 | + |
| 168 | + totalItems = comments.data.length + classes.data.length + courses.data.length; |
| 169 | + console.log(`Total items to delete: ${totalItems} (Comments: ${comments.data.length}, Classes: ${classes.data.length}, Courses: ${courses.data.length})`); |
| 170 | + |
| 171 | + if (totalItems === 0) { |
| 172 | + setMessage({ type: 'success', text: 'No data to delete. Database is already empty.' }); |
| 173 | + return; |
| 174 | + } |
| 175 | + |
| 176 | + console.log('=== Starting Comment deletion ==='); |
| 177 | + const batchSize = 20; |
| 178 | + for (let i = 0; i < comments.data.length; i += batchSize) { |
| 179 | + const batch = comments.data.slice(i, i + batchSize); |
| 180 | + console.log(`Deleting comment batch ${Math.floor(i/batchSize) + 1}/${Math.ceil(comments.data.length/batchSize)}`); |
| 181 | + |
| 182 | + const deletePromises = batch.map(async (comment) => { |
| 183 | + try { |
| 184 | + const result = await client.models.Comment.delete({ id: comment.id }); |
| 185 | + return result.errors ? false : true; |
| 186 | + } catch (error) { |
| 187 | + console.error('Failed to delete Comment:', comment.id, error); |
| 188 | + return false; |
| 189 | + } |
| 190 | + }); |
| 191 | + |
| 192 | + const results = await Promise.all(deletePromises); |
| 193 | + const successCount = results.filter(Boolean).length; |
| 194 | + totalDeleted += successCount; |
| 195 | + console.log(`Batch completed: ${successCount}/${batch.length} deleted`); |
| 196 | + setProgress(Math.round((totalDeleted / totalItems) * 100)); |
| 197 | + } |
| 198 | + |
| 199 | + console.log('=== Starting Class deletion ==='); |
| 200 | + for (let i = 0; i < classes.data.length; i += batchSize) { |
| 201 | + const batch = classes.data.slice(i, i + batchSize); |
| 202 | + console.log(`Deleting class batch ${Math.floor(i/batchSize) + 1}/${Math.ceil(classes.data.length/batchSize)}`); |
| 203 | + |
| 204 | + const deletePromises = batch.map(async (classItem) => { |
| 205 | + try { |
| 206 | + const result = await client.models.Class.delete({ id: classItem.id }); |
| 207 | + return result.errors ? false : true; |
| 208 | + } catch (error) { |
| 209 | + console.error('Failed to delete Class:', classItem.id, error); |
| 210 | + return false; |
| 211 | + } |
| 212 | + }); |
| 213 | + |
| 214 | + const results = await Promise.all(deletePromises); |
| 215 | + const successCount = results.filter(Boolean).length; |
| 216 | + totalDeleted += successCount; |
| 217 | + console.log(`Batch completed: ${successCount}/${batch.length} deleted`); |
| 218 | + setProgress(Math.round((totalDeleted / totalItems) * 100)); |
| 219 | + } |
| 220 | + |
| 221 | + console.log('=== Starting Course deletion ==='); |
| 222 | + for (let i = 0; i < courses.data.length; i += batchSize) { |
| 223 | + const batch = courses.data.slice(i, i + batchSize); |
| 224 | + console.log(`Deleting course batch ${Math.floor(i/batchSize) + 1}/${Math.ceil(courses.data.length/batchSize)}`); |
| 225 | + |
| 226 | + const deletePromises = batch.map(async (course) => { |
| 227 | + try { |
| 228 | + const result = await client.models.Course.delete({ id: course.id }); |
| 229 | + return result.errors ? false : true; |
| 230 | + } catch (error) { |
| 231 | + console.error('Failed to delete Course:', course.id, error); |
| 232 | + return false; |
| 233 | + } |
| 234 | + }); |
| 235 | + |
| 236 | + const results = await Promise.all(deletePromises); |
| 237 | + const successCount = results.filter(Boolean).length; |
| 238 | + totalDeleted += successCount; |
| 239 | + console.log(`Batch completed: ${successCount}/${batch.length} deleted`); |
| 240 | + setProgress(Math.round((totalDeleted / totalItems) * 100)); |
| 241 | + } |
| 242 | + |
| 243 | + console.log('=== Deletion completed successfully ==='); |
| 244 | + console.log(`Actually deleted: ${totalDeleted}/${totalItems} items`); |
| 245 | + setMessage({ |
| 246 | + type: 'success', |
| 247 | + text: `Data deletion completed! (${totalDeleted}/${totalItems} items deleted - Comments: ${comments.data.length}, Classes: ${classes.data.length}, Courses: ${courses.data.length})` |
| 248 | + }); |
| 249 | + } catch (error) { |
| 250 | + console.error('=== Deletion failed ===', error); |
| 251 | + setMessage({ |
| 252 | + type: 'error', |
| 253 | + text: `Deletion failed: ${error instanceof Error ? error.message : 'Unknown error'}` |
| 254 | + }); |
| 255 | + } |
| 256 | +}; |
0 commit comments