diff --git a/packages/server/src/module/quiz/quizzes/quiz.controller.ts b/packages/server/src/module/quiz/quizzes/quiz.controller.ts index 7588ce7..d66a013 100644 --- a/packages/server/src/module/quiz/quizzes/quiz.controller.ts +++ b/packages/server/src/module/quiz/quizzes/quiz.controller.ts @@ -33,7 +33,7 @@ export class QuizController { @Post('classes/:classId/quizzes') @UseInterceptors(new TransformInterceptor(ResponseDto)) async createQuiz(@Param('classId') classId: number, @Body() dto: CreateQuizListRequestDto) { - return await this.quizService.createQuiz(classId, dto); + return await this.quizService.createBulkQuizWithChoices(classId, dto); } @Get('classes') diff --git a/packages/server/src/module/quiz/quizzes/quiz.service.ts b/packages/server/src/module/quiz/quizzes/quiz.service.ts index 21693aa..39f9dc8 100644 --- a/packages/server/src/module/quiz/quizzes/quiz.service.ts +++ b/packages/server/src/module/quiz/quizzes/quiz.service.ts @@ -1,23 +1,13 @@ -import { - Injectable, - HttpException, - HttpStatus, - Param, - NotFoundException, - InternalServerErrorException, -} from '@nestjs/common'; -import { DataSource } from 'typeorm'; +import { Injectable, HttpException, HttpStatus, NotFoundException } from '@nestjs/common'; +import { DataSource, InsertResult } from 'typeorm'; import { QuizRepository } from './repositories/quiz.repository'; import { ChoiceRepository } from './repositories/choice.repository'; import { ClassRepository } from './repositories/class.repository'; import { CreateClassRequestDto } from './dto/request/create-class.request.dto'; import { CreateClassResponseDto } from './dto/response/create-class.response.dto'; import { CreateQuizListRequestDto } from './dto/request/create-quizlist.request.dto'; -import { ResponseDto } from '../../utils/dto/response.dto'; -import { Quiz } from './entities/quiz.entity'; import { QuizResponseDto } from './dto/response/quiz.response.dto'; import { UpdateClassRequestDto } from './dto/request/update-class.request.dto'; -import { UpdateQuizRequestDto } from './dto/request/update-quiz.request.dto'; import { UpdateQuizListRequestDto } from './dto/request/update-quizlist.request.dto'; import { GetClassResponseDto } from './dto/response/get-class.response.dto'; import { Class } from './entities/class.entity'; @@ -39,31 +29,44 @@ export class QuizService { return responseDto; } - async createQuiz(classId: number, quizData: CreateQuizListRequestDto): Promise { - const queryRunner = this.dataSource.createQueryRunner(); - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { + async createBulkQuizWithChoices( + classId: number, + quizData: CreateQuizListRequestDto, + ): Promise { + return this.dataSource.transaction(async (manager) => { await this.classRepository.findClassById(classId); - await Promise.all( - quizData.quizzes.map(async (quiz) => { - const quizEntity = await this.quizRepository.create(classId, quiz); - await Promise.all( - quiz.choices.map(async (choice) => { - await this.choiceRepository.create(quizEntity.id, choice); - }), - ); - }), - ); - await queryRunner.commitTransaction(); - } catch (error) { - await queryRunner.rollbackTransaction(); - if (error instanceof HttpException) throw error; - throw new InternalServerErrorException('Failed to create quiz'); - } finally { - await queryRunner.release(); - } + + const quizValues = this.prepareQuizData(classId, quizData); + const insertedQuizzes = await this.quizRepository.createBulkQuizzes(manager, quizValues); + + const choiceValues = this.prepareChoiceData(quizData, insertedQuizzes); + await this.choiceRepository.createBulkChoices(manager, choiceValues); + }); + } + + private prepareQuizData(classId: number, quizData: CreateQuizListRequestDto) { + return quizData.quizzes.map((quiz) => ({ + classId, + content: quiz.content, + quizType: quiz.quizType, + timeLimit: quiz.timeLimit, + point: quiz.point, + position: quiz.position, + createdAt: new Date(), + })); + } + + private prepareChoiceData(quizData: CreateQuizListRequestDto, insertedQuizzes: InsertResult) { + const quizIds = insertedQuizzes.identifiers.map((identifier) => identifier.id); + return quizData.quizzes.flatMap((quiz, index) => + quiz.choices.map((choice) => ({ + quizId: quizIds[index], + content: choice.content, + isCorrect: choice.isCorrect, + position: choice.position, + createdAt: new Date(), + })), + ); } async getAllClasses(): Promise { @@ -72,7 +75,7 @@ export class QuizService { return classEntities.map((classEntity: Class) => GetClassResponseDto.fromEntity(classEntity)); } - async getQuizzesByClassId(classId: number): Promise { + async getQuizzesByClassId(classId: number): Promise { const quizzes = await this.quizRepository.findByClassId(classId); if (!quizzes || quizzes.length === 0) { diff --git a/packages/server/src/module/quiz/quizzes/repositories/choice.repository.ts b/packages/server/src/module/quiz/quizzes/repositories/choice.repository.ts index 59291d7..de889c8 100644 --- a/packages/server/src/module/quiz/quizzes/repositories/choice.repository.ts +++ b/packages/server/src/module/quiz/quizzes/repositories/choice.repository.ts @@ -34,6 +34,18 @@ export class ChoiceRepository { } } + async createBulkChoices(manager: EntityManager, choiceData: any[]) { + try { + if (!choiceData.length) { + throw new Error('Choice data array is empty'); + } + + return await manager.createQueryBuilder().insert().into(Choice).values(choiceData).execute(); + } catch (error) { + throw new InternalServerErrorException('Failed to create choices'); + } + } + async findById(id: number): Promise { try { const choice = await this.repository.findOne({ where: { id } }); diff --git a/packages/server/src/module/quiz/quizzes/repositories/class.repository.ts b/packages/server/src/module/quiz/quizzes/repositories/class.repository.ts index 503c493..6ab4da5 100644 --- a/packages/server/src/module/quiz/quizzes/repositories/class.repository.ts +++ b/packages/server/src/module/quiz/quizzes/repositories/class.repository.ts @@ -2,8 +2,6 @@ import { Injectable, InternalServerErrorException, NotFoundException } from '@ne import { InjectRepository } from '@nestjs/typeorm'; import { DataSource, Repository } from 'typeorm'; import { Class } from '../entities/class.entity'; -import { Quiz } from '../entities/quiz.entity'; -import { Choice } from '../entities/choice.entity'; @Injectable() export class ClassRepository { diff --git a/packages/server/src/module/quiz/quizzes/repositories/quiz.repository.ts b/packages/server/src/module/quiz/quizzes/repositories/quiz.repository.ts index 3a18007..cb3db41 100644 --- a/packages/server/src/module/quiz/quizzes/repositories/quiz.repository.ts +++ b/packages/server/src/module/quiz/quizzes/repositories/quiz.repository.ts @@ -1,6 +1,6 @@ import { Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { DataSource, In, Repository } from 'typeorm'; +import { DataSource, EntityManager, Repository } from 'typeorm'; import { Quiz } from '../entities/quiz.entity'; import { Choice } from '../entities/choice.entity'; import { CreateQuizRequestDto } from '../dto/request/create-quiz.request.dto'; @@ -32,6 +32,18 @@ export class QuizRepository { } } + async createBulkQuizzes(manager: EntityManager, quizData: any[]) { + try { + if (!quizData.length) { + throw new Error('Quiz data array is empty'); + } + + return await manager.createQueryBuilder().insert().into(Quiz).values(quizData).execute(); + } catch (error) { + throw new InternalServerErrorException('Failed to create quizzes'); + } + } + async findAll(): Promise { try { const result = await this.repository.find();