Skip to content

Commit 1e756fe

Browse files
authored
Merge pull request #54 from aws-samples/fix/comment-class-id-mapping
Fix Comment-Class ID mapping and refactor data management
2 parents 93aa82f + 6a316f5 commit 1e756fe

File tree

2 files changed

+278
-237
lines changed

2 files changed

+278
-237
lines changed
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
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

Comments
 (0)