diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/application/TimetableService.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/application/TimetableService.kt index 33b936f1..39241bf5 100644 --- a/src/main/kotlin/com/asap/asapbackend/domain/timetable/application/TimetableService.kt +++ b/src/main/kotlin/com/asap/asapbackend/domain/timetable/application/TimetableService.kt @@ -4,6 +4,7 @@ import com.asap.asapbackend.domain.child.domain.service.ChildReader import com.asap.asapbackend.domain.classroom.domain.service.ClassroomReader import com.asap.asapbackend.domain.timetable.application.dto.GetThisWeekTimetable import com.asap.asapbackend.domain.timetable.application.dto.GetTodayTimetable +import com.asap.asapbackend.domain.timetable.domain.service.SubjectReader import com.asap.asapbackend.domain.timetable.domain.service.TimetableReader import com.asap.asapbackend.global.security.getCurrentUserId import org.springframework.stereotype.Service @@ -14,15 +15,18 @@ import org.springframework.transaction.annotation.Transactional class TimetableService( private val classroomReader: ClassroomReader, private val childReader: ChildReader, - private val timetableReader: TimetableReader + private val timetableReader: TimetableReader, + private val subjectReader: SubjectReader ) { + fun getTodayTimetable(): GetTodayTimetable.Response { val userId = getCurrentUserId() val studentId = childReader.findPrimaryChild(userId).id val classroomId = classroomReader.findByStudent(studentId).id val todayTimetables = timetableReader.findTodayTimetableByClassroomId(classroomId) + val subjectMap = subjectReader.findSubjectMapByClassroomId(classroomId) val timetables = todayTimetables.map { - GetTodayTimetable.Timetable(it.time, it.subject.name) + GetTodayTimetable.Timetable(it.time, subjectMap[it.subject.id]?.name ?: "") } return GetTodayTimetable.Response(timetables) } @@ -32,9 +36,10 @@ class TimetableService( val studentId = childReader.findPrimaryChild(userId).id val classroomId = classroomReader.findByStudent(studentId).id val weekTimetables = timetableReader.findThisWeekTimetableByClassroomId(classroomId) + val subjectMap = subjectReader.findSubjectMapByClassroomId(classroomId) val weekDataList = weekTimetables.mapValues { (_, timetables) -> timetables.map { timetable -> - GetThisWeekTimetable.Timetable(timetable?.time, timetable?.subject?.name) + GetThisWeekTimetable.Timetable(timetable.time, subjectMap[timetable.subject.id]?.name ?: "") } } return GetThisWeekTimetable.Response(weekDataList) diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/application/dto/GetThisWeekTimetable.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/application/dto/GetThisWeekTimetable.kt index def811cc..f989e603 100644 --- a/src/main/kotlin/com/asap/asapbackend/domain/timetable/application/dto/GetThisWeekTimetable.kt +++ b/src/main/kotlin/com/asap/asapbackend/domain/timetable/application/dto/GetThisWeekTimetable.kt @@ -7,7 +7,7 @@ class GetThisWeekTimetable { val timetables : Map> ) data class Timetable( - val time: Int?, - val subject: String? + val time: Int, + val subject: String ) } \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/model/Subject.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/model/Subject.kt index 225cc494..8742b676 100644 --- a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/model/Subject.kt +++ b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/model/Subject.kt @@ -1,26 +1,32 @@ package com.asap.asapbackend.domain.timetable.domain.model -import com.asap.asapbackend.domain.classroom.domain.model.Classroom -import com.asap.asapbackend.global.domain.BaseDateEntity -import jakarta.persistence.Entity -import jakarta.persistence.FetchType -import jakarta.persistence.ManyToOne +import java.time.LocalDateTime -@Entity class Subject( - classroom: Classroom, + id: Long = 0, + classroomId: Long, name: String, - semester: String -) : BaseDateEntity() { + semester: String, + createdAt: LocalDateTime = LocalDateTime.now(), + updatedAt: LocalDateTime = LocalDateTime.now() +) { + val id: Long = id val name : String = name val semester : String = semester - @ManyToOne(fetch = FetchType.LAZY) - val classroom: Classroom = classroom + val classroomId: Long = classroomId - fun isSameSubject(subject: Subject): Boolean { - return this.name == subject.name && this.semester == subject.semester && this.classroom.id == subject.classroom.id + val createdAt: LocalDateTime = createdAt + val updatedAt: LocalDateTime = updatedAt + + + fun isSameSubject( + name: String, + semester: String, + classroomId: Long + ): Boolean { + return this.name == name && this.semester == semester && this.classroomId == classroomId } } \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/model/Timetable.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/model/Timetable.kt index 56ed5a3c..3ecba4b3 100644 --- a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/model/Timetable.kt +++ b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/model/Timetable.kt @@ -1,22 +1,24 @@ package com.asap.asapbackend.domain.timetable.domain.model -import com.asap.asapbackend.global.domain.BaseDateEntity -import jakarta.persistence.Entity -import jakarta.persistence.FetchType -import jakarta.persistence.ManyToOne import java.time.LocalDate +import java.time.LocalDateTime -@Entity class Timetable( + id: Long = 0, subject: Subject, day: LocalDate, - time: Int -) : BaseDateEntity() { + time: Int, + createdAt: LocalDateTime = LocalDateTime.now(), + updatedAt: LocalDateTime = LocalDateTime.now() +) { + val id: Long = id - @ManyToOne(fetch = FetchType.LAZY) val subject: Subject = subject val day: LocalDate = day val time: Int = time + + val createdAt: LocalDateTime = createdAt + val updatedAt: LocalDateTime = updatedAt } \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/SubjectRepository.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/SubjectRepository.kt index 2c9e55f9..844411af 100644 --- a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/SubjectRepository.kt +++ b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/SubjectRepository.kt @@ -2,8 +2,12 @@ package com.asap.asapbackend.domain.timetable.domain.repository import com.asap.asapbackend.domain.classroom.domain.model.Classroom import com.asap.asapbackend.domain.timetable.domain.model.Subject -import org.springframework.data.jpa.repository.JpaRepository -interface SubjectRepository : JpaRepository { +interface SubjectRepository{ fun findByClassroomIn(classroom: List) : List + fun saveAll(subjects: List): List + fun findOriginalSubjectsByClassroomIn(classroom: List) : List + + fun findAllByClassroomId(classroomId: Long): List + fun save(subject: Subject): Subject } \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/TimetableJdbcRepository.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/TimetableJdbcRepository.kt deleted file mode 100644 index 622a7e3b..00000000 --- a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/TimetableJdbcRepository.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.asap.asapbackend.domain.timetable.domain.repository - -import com.asap.asapbackend.domain.timetable.domain.model.Timetable -import org.springframework.jdbc.core.JdbcTemplate -import org.springframework.stereotype.Repository - -@Repository -class TimetableJdbcRepository( - private val jdbcTemplate: JdbcTemplate -) { - - fun insertBatch(timetables: Collection) { - jdbcTemplate.batchUpdate( - "INSERT INTO timetable (subject_id, day, time, created_at, updated_at) VALUES (?, ?, ?, now(), now())", - timetables.map { - arrayOf(it.subject.id, it.day, it.time) - } - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/TimetableRepository.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/TimetableRepository.kt index 066ad878..8756c058 100644 --- a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/TimetableRepository.kt +++ b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/repository/TimetableRepository.kt @@ -1,9 +1,10 @@ package com.asap.asapbackend.domain.timetable.domain.repository import com.asap.asapbackend.domain.timetable.domain.model.Timetable -import org.springframework.data.jpa.repository.JpaRepository import java.time.LocalDate -interface TimetableRepository : JpaRepository { - fun findBySubjectClassroomIdAndDayOrderByTime(classroomId: Long, day: LocalDate) : List +interface TimetableRepository{ + fun findByClassroomIdAndDayOrderByTime(classroomId: Long, day: LocalDate) : List + + fun insertBatch(timetables: Collection) } \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/SubjectReader.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/SubjectReader.kt new file mode 100644 index 00000000..3f63284a --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/SubjectReader.kt @@ -0,0 +1,15 @@ +package com.asap.asapbackend.domain.timetable.domain.service + +import com.asap.asapbackend.domain.timetable.domain.model.Subject +import com.asap.asapbackend.domain.timetable.domain.repository.SubjectRepository +import org.springframework.stereotype.Service + +@Service +class SubjectReader( + private val subjectRepository: SubjectRepository +) { + + fun findSubjectMapByClassroomId(classroomId: Long): Map { + return subjectRepository.findAllByClassroomId(classroomId).associateBy { it.id } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/TimetableAppender.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/TimetableAppender.kt index 3afd0d0d..e09fc560 100644 --- a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/TimetableAppender.kt +++ b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/TimetableAppender.kt @@ -3,10 +3,13 @@ package com.asap.asapbackend.domain.timetable.domain.service import com.asap.asapbackend.batch.timetable.TimetableInfoProvider import com.asap.asapbackend.domain.classroom.domain.model.Classroom import com.asap.asapbackend.domain.classroom.domain.repository.ClassroomRepository +import com.asap.asapbackend.domain.school.domain.model.School import com.asap.asapbackend.domain.timetable.domain.model.Subject import com.asap.asapbackend.domain.timetable.domain.model.Timetable import com.asap.asapbackend.domain.timetable.domain.repository.SubjectRepository -import com.asap.asapbackend.domain.timetable.domain.repository.TimetableJdbcRepository +import com.asap.asapbackend.domain.timetable.domain.repository.TimetableRepository +import com.asap.asapbackend.domain.timetable.event.MultiSubjectCreateEvent +import org.springframework.context.ApplicationEventPublisher import org.springframework.stereotype.Service @@ -14,39 +17,64 @@ import org.springframework.stereotype.Service class TimetableAppender( private val classroomRepository: ClassroomRepository, private val subjectRepository: SubjectRepository, - private val timetableJdbcRepository: TimetableJdbcRepository + private val timetableRepository: TimetableRepository, + private val applicationEventPublisher: ApplicationEventPublisher ) { fun addSubjectAndTimetable(timetables: List) { val existClassroomMap = classroomRepository.findBySchoolIn(timetables.map { it.school }) .groupBy { it.school } - val timetableList = mutableSetOf() - val subjectList = subjectRepository.findByClassroomIn(existClassroomMap.values.flatten()) - .groupByTo(mutableMapOf()) { it.classroom } + val subjectList = subjectRepository.findOriginalSubjectsByClassroomIn(existClassroomMap.values.flatten()) + .groupByTo(mutableMapOf()) { it.classroomId } + + val savedTimetables = mutableSetOf() + + handleTimetables(timetables, existClassroomMap, subjectList) { subject, timetableResponse -> + savedTimetables.add( + Timetable( + subject = subject, + day = timetableResponse.day, + time = timetableResponse.time + ) + ) + } + + timetableRepository.insertBatch(savedTimetables) + + applicationEventPublisher.publishEvent(MultiSubjectCreateEvent(subjectList.values.flatten().toSet())) + } + + private fun handleTimetables( + timetables: List, + existClassroomMap: Map>, + subjectList: MutableMap>, + subjectHandler: (Subject, TimetableInfoProvider.TimetableResponse) -> Unit = { _, _ -> } + ) { timetables.forEach { if (it.name == null) return@forEach - val classroom = existClassroomMap[it.school]?.find { classroom -> - classroom.isSameClassroom(Classroom(it.grade, it.className, it.school)) + val classroom = existClassroomMap[it.school]?.find { subject -> + subject.isSameClassroom(Classroom(it.grade, it.className, it.school)) } ?: return@forEach - - val existSubject = subjectList[classroom]?.find { subject -> - subject.isSameSubject(Subject(classroom, it.name, it.semester)) - } ?: Subject(classroom, it.name, it.semester).also { - subjectList.getOrPut(classroom) { mutableListOf() }.add(it) + val subject = subjectList[classroom.id]?.let { findSubjectList -> + findSubjectList.find { subject -> + subject.isSameSubject(it.name, it.semester, classroom.id) + } + } ?: run { + val savedSubject = subjectRepository.save( + Subject( + name = it.name, + semester = it.semester, + classroomId = classroom.id + ) + ) + subjectList.getOrPut(classroom.id) { mutableListOf() }.add(savedSubject) + savedSubject } - val timetable = Timetable( - subject = existSubject, - day = it.day, - time = it.time - ) - timetableList.add(timetable) + subjectHandler(subject, it) } - - subjectRepository.saveAll(subjectList.values.flatten()) - timetableJdbcRepository.insertBatch(timetableList) } } \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/TimetableReader.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/TimetableReader.kt index 1295fa18..669f261a 100644 --- a/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/TimetableReader.kt +++ b/src/main/kotlin/com/asap/asapbackend/domain/timetable/domain/service/TimetableReader.kt @@ -11,10 +11,10 @@ class TimetableReader( private val timetableRepository: TimetableRepository ) { fun findTodayTimetableByClassroomId(classroomId: Long): List { - return timetableRepository.findBySubjectClassroomIdAndDayOrderByTime(classroomId, LocalDate.now()) + return timetableRepository.findByClassroomIdAndDayOrderByTime(classroomId, LocalDate.now()) } - fun findThisWeekTimetableByClassroomId(classroomId: Long): Map> { + fun findThisWeekTimetableByClassroomId(classroomId: Long): Map> { val daysOfWeek = listOf( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, @@ -23,7 +23,7 @@ class TimetableReader( DayOfWeek.FRIDAY ) return daysOfWeek.associateWith { day -> - timetableRepository.findBySubjectClassroomIdAndDayOrderByTime(classroomId, LocalDate.now().with(day)) + timetableRepository.findByClassroomIdAndDayOrderByTime(classroomId, LocalDate.now().with(day)) } } } \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/domain/timetable/event/TimetableCreateEvent.kt b/src/main/kotlin/com/asap/asapbackend/domain/timetable/event/TimetableCreateEvent.kt new file mode 100644 index 00000000..2cd45f14 --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/domain/timetable/event/TimetableCreateEvent.kt @@ -0,0 +1,9 @@ +package com.asap.asapbackend.domain.timetable.event + +import com.asap.asapbackend.domain.timetable.domain.model.Subject + + +data class MultiSubjectCreateEvent( + val subjects: Set +) { +} diff --git a/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/SubjectRepositoryImpl.kt b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/SubjectRepositoryImpl.kt new file mode 100644 index 00000000..07a8c4bd --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/SubjectRepositoryImpl.kt @@ -0,0 +1,64 @@ +package com.asap.asapbackend.infrastructure.jpa.timetable + +import com.asap.asapbackend.domain.classroom.domain.model.Classroom +import com.asap.asapbackend.domain.timetable.domain.model.Subject +import com.asap.asapbackend.domain.timetable.domain.repository.SubjectRepository +import com.asap.asapbackend.global.util.LanguageExtractor +import com.asap.asapbackend.infrastructure.jpa.MultiLanguageId +import com.asap.asapbackend.infrastructure.jpa.timetable.TimetableMapper.toSubjectModel +import com.asap.asapbackend.infrastructure.jpa.timetable.repository.SubjectJpaRepository +import com.asap.asapbackend.infrastructure.jpa.timetable.repository.TranslatedSubjectJpaRepository +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Repository + +@Repository +class SubjectRepositoryImpl( + private val subjectJpaRepository: SubjectJpaRepository, + private val translatedSubjectJpaRepository: TranslatedSubjectJpaRepository, + private val languageExtractor: LanguageExtractor +) : SubjectRepository { + override fun findByClassroomIn(classroom: List): List { + return subjectJpaRepository.findAllByClassroomIdIn(classroom.map { it.id }) + .map { + val translatedSubject = translatedSubjectJpaRepository.findByIdOrNull( + MultiLanguageId( + it.id, + languageExtractor.getRequestLanguage() + ) + ) + it.changeName(translatedSubject?.name) + toSubjectModel(it) + } + } + + + override fun saveAll(subjects: List): List { + val savedSubjects = subjectJpaRepository.saveAll(subjects.map { TimetableMapper.toSubjectEntity(it) }) + return savedSubjects.map { toSubjectModel(it) } + } + + override fun findOriginalSubjectsByClassroomIn(classroom: List): List { + return subjectJpaRepository.findAllByClassroomIdIn(classroom.map { it.id }) + .map { toSubjectModel(it) } + } + + override fun findAllByClassroomId(classroomId: Long): List { + return subjectJpaRepository.findAllByClassroomId(classroomId) + .map { + val translatedSubject = translatedSubjectJpaRepository.findByIdOrNull( + MultiLanguageId( + it.id, + languageExtractor.getRequestLanguage() + ) + ) + + it.changeName(translatedSubject?.name) + toSubjectModel(it) + } + } + + override fun save(subject: Subject): Subject { + val savedSubject = subjectJpaRepository.save(TimetableMapper.toSubjectEntity(subject)) + return toSubjectModel(savedSubject) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/TimetableMapper.kt b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/TimetableMapper.kt new file mode 100644 index 00000000..cb5ed946 --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/TimetableMapper.kt @@ -0,0 +1,53 @@ +package com.asap.asapbackend.infrastructure.jpa.timetable + +import com.asap.asapbackend.domain.timetable.domain.model.Subject +import com.asap.asapbackend.domain.timetable.domain.model.Timetable +import com.asap.asapbackend.infrastructure.jpa.timetable.entity.SubjectEntity +import com.asap.asapbackend.infrastructure.jpa.timetable.entity.TimetableEntity + +object TimetableMapper { + + fun toTimetableModel(timetableEntity: TimetableEntity): Timetable { + return Timetable( + id = timetableEntity.id, + day = timetableEntity.day, + time = timetableEntity.time, + subject = toSubjectModel(timetableEntity.subject), + createdAt = timetableEntity.createdAt, + updatedAt = timetableEntity.updatedAt + ) + } + + fun toSubjectModel(subjectEntity: SubjectEntity): Subject { + return Subject( + id = subjectEntity.id, + classroomId = subjectEntity.classroomId, + name = subjectEntity.name, + semester = subjectEntity.semester, + createdAt = subjectEntity.createdAt, + updatedAt = subjectEntity.updatedAt + ) + } + + fun toTimetableEntity(timetable: Timetable): TimetableEntity { + return TimetableEntity( + id = timetable.id, + day = timetable.day, + time = timetable.time, + subjectId = timetable.subject.id, + createdAt = timetable.createdAt, + updatedAt = timetable.updatedAt + ) + } + + fun toSubjectEntity(subject: Subject): SubjectEntity { + return SubjectEntity( + id = subject.id, + classroomId = subject.classroomId, + name = subject.name, + semester = subject.semester, + createdAt = subject.createdAt, + updatedAt = subject.updatedAt + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/TimetableRepositoryImpl.kt b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/TimetableRepositoryImpl.kt new file mode 100644 index 00000000..a2467cc6 --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/TimetableRepositoryImpl.kt @@ -0,0 +1,28 @@ +package com.asap.asapbackend.infrastructure.jpa.timetable + +import com.asap.asapbackend.domain.timetable.domain.model.Timetable +import com.asap.asapbackend.domain.timetable.domain.repository.TimetableRepository +import com.asap.asapbackend.infrastructure.jpa.timetable.repository.TimetableJpaRepository +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.stereotype.Repository +import java.time.LocalDate + +@Repository +class TimetableRepositoryImpl( + private val timetableJpaRepository: TimetableJpaRepository, + private val jdbcTemplate: JdbcTemplate +): TimetableRepository { + override fun findByClassroomIdAndDayOrderByTime(classroomId: Long, day: LocalDate): List { + return timetableJpaRepository.findByClassroomIdAndDayOrderByTime(classroomId, day) + .map { TimetableMapper.toTimetableModel(it) } + } + + override fun insertBatch(timetables: Collection) { + jdbcTemplate.batchUpdate( + "INSERT INTO timetable (subject_id, day, time, created_at, updated_at) VALUES (?, ?, ?, now(), now())", + timetables.map { + arrayOf(it.subject.id, it.day, it.time) + } + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/entity/SubjectEntity.kt b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/entity/SubjectEntity.kt new file mode 100644 index 00000000..81d5f150 --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/entity/SubjectEntity.kt @@ -0,0 +1,40 @@ +package com.asap.asapbackend.infrastructure.jpa.timetable.entity + +import jakarta.persistence.* +import java.time.LocalDateTime + +@Entity +@Table( + name = "subject", + indexes = [ + Index(name = "idx_subject_classroom_id", columnList = "classroom_id") + ] +) +class SubjectEntity( + id: Long, + classroomId: Long, + name: String, + semester: String, + createdAt: LocalDateTime, + updatedAt: LocalDateTime +) { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long = id + + val classroomId: Long = classroomId + + var name : String = name + + val semester : String = semester + + val createdAt: LocalDateTime = createdAt + val updatedAt: LocalDateTime = updatedAt + + fun changeName(name: String?) { + name?.let { + this.name = it + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/entity/TimetableEntity.kt b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/entity/TimetableEntity.kt new file mode 100644 index 00000000..aa0353bc --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/entity/TimetableEntity.kt @@ -0,0 +1,40 @@ +package com.asap.asapbackend.infrastructure.jpa.timetable.entity + +import jakarta.persistence.* +import java.time.LocalDate +import java.time.LocalDateTime + +@Entity +@Table( + name = "timetable", + indexes = [ + Index(name = "idx_timetable_subject_id", columnList = "subject_id"), + Index(name="unique_timetable_day_time_subject_id", columnList = "day, time, subject_id", unique = true) + ] +) +class TimetableEntity( + id: Long, + subjectId: Long, + day: LocalDate, + time: Int, + createdAt: LocalDateTime, + updatedAt: LocalDateTime +) { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long = id + + @Column(name = "subject_id") + val subjectId: Long = subjectId + + @JoinColumn(name = "subject_id", insertable = false, updatable = false, nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + lateinit var subject: SubjectEntity + + val day: LocalDate = day + val time: Int = time + + val createdAt: LocalDateTime = createdAt + val updatedAt: LocalDateTime = updatedAt +} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/entity/TranslatedSubjectEntity.kt b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/entity/TranslatedSubjectEntity.kt new file mode 100644 index 00000000..455b44c1 --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/entity/TranslatedSubjectEntity.kt @@ -0,0 +1,22 @@ +package com.asap.asapbackend.infrastructure.jpa.timetable.entity + +import com.asap.asapbackend.global.vo.Language +import com.asap.asapbackend.infrastructure.jpa.MultiLanguageId +import jakarta.persistence.EmbeddedId +import jakarta.persistence.Entity +import jakarta.persistence.Table + +@Entity +@Table( + name = "translated_subject" +) +class TranslatedSubjectEntity( + subjectId: Long, + language: Language, + name: String +) { + @EmbeddedId + val id: MultiLanguageId = MultiLanguageId(subjectId, language) + + val name: String = name +} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/handler/SubjectTranslateHandler.kt b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/handler/SubjectTranslateHandler.kt new file mode 100644 index 00000000..9aac9e8a --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/handler/SubjectTranslateHandler.kt @@ -0,0 +1,30 @@ +package com.asap.asapbackend.infrastructure.jpa.timetable.handler + +import com.asap.asapbackend.domain.timetable.event.MultiSubjectCreateEvent +import com.asap.asapbackend.global.util.TextTranslator +import com.asap.asapbackend.infrastructure.jpa.timetable.entity.TranslatedSubjectEntity +import com.asap.asapbackend.infrastructure.jpa.timetable.repository.TranslatedSubjectJpaRepository +import org.springframework.modulith.events.ApplicationModuleListener +import org.springframework.stereotype.Component + +@Component +class SubjectTranslateHandler( + private val textTranslator: TextTranslator, + private val translatedSubjectJpaRepository: TranslatedSubjectJpaRepository +) { + + @ApplicationModuleListener + fun translate(event: MultiSubjectCreateEvent) { + val translatedSubjects = event.subjects.map { subject -> + val translatedNames = textTranslator.translate(subject.name).translations.map { result -> + result.language to result.text + } + + translatedNames.map { (language, name) -> + TranslatedSubjectEntity(subject.id, language, name) + } + }.flatten() + + translatedSubjectJpaRepository.saveAll(translatedSubjects) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/repository/SubjectJpaRepository.kt b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/repository/SubjectJpaRepository.kt new file mode 100644 index 00000000..6c895237 --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/repository/SubjectJpaRepository.kt @@ -0,0 +1,10 @@ +package com.asap.asapbackend.infrastructure.jpa.timetable.repository + +import com.asap.asapbackend.infrastructure.jpa.timetable.entity.SubjectEntity +import org.springframework.data.jpa.repository.JpaRepository + +interface SubjectJpaRepository : JpaRepository{ + fun findAllByClassroomIdIn(classroomIds: List): List + + fun findAllByClassroomId(classroomId: Long): List +} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/repository/TimetableJpaRepository.kt b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/repository/TimetableJpaRepository.kt new file mode 100644 index 00000000..e9612d3b --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/repository/TimetableJpaRepository.kt @@ -0,0 +1,19 @@ +package com.asap.asapbackend.infrastructure.jpa.timetable.repository + +import com.asap.asapbackend.infrastructure.jpa.timetable.entity.TimetableEntity +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import java.time.LocalDate + +interface TimetableJpaRepository : JpaRepository { + @Query( + """ + SELECT t + FROM TimetableEntity t + WHERE t.subject.classroomId = :classroomId + AND t.day = :day + ORDER BY t.time + """ + ) + fun findByClassroomIdAndDayOrderByTime(classroomId: Long, day: LocalDate): List +} \ No newline at end of file diff --git a/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/repository/TranslatedSubjectJpaRepository.kt b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/repository/TranslatedSubjectJpaRepository.kt new file mode 100644 index 00000000..865bc704 --- /dev/null +++ b/src/main/kotlin/com/asap/asapbackend/infrastructure/jpa/timetable/repository/TranslatedSubjectJpaRepository.kt @@ -0,0 +1,8 @@ +package com.asap.asapbackend.infrastructure.jpa.timetable.repository + +import com.asap.asapbackend.infrastructure.jpa.MultiLanguageId +import com.asap.asapbackend.infrastructure.jpa.timetable.entity.TranslatedSubjectEntity +import org.springframework.data.jpa.repository.JpaRepository + +interface TranslatedSubjectJpaRepository: JpaRepository { +} \ No newline at end of file