diff --git a/build.gradle.kts b/build.gradle.kts index 681bcc8..54d5659 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -58,6 +58,10 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-data-jpa") kapt("org.springframework.boot:spring-boot-configuration-processor") + /** querydsl */ + implementation("com.querydsl:querydsl-jpa:${DependencyVersion.QUERYDSL}:jakarta") + kapt("com.querydsl:querydsl-apt:${DependencyVersion.QUERYDSL}:jakarta") + /** kotlin */ implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("io.projectreactor.kotlin:reactor-kotlin-extensions") diff --git a/buildSrc/src/main/kotlin/DependencyVersion.kt b/buildSrc/src/main/kotlin/DependencyVersion.kt index de105cd..f50c155 100644 --- a/buildSrc/src/main/kotlin/DependencyVersion.kt +++ b/buildSrc/src/main/kotlin/DependencyVersion.kt @@ -1,4 +1,7 @@ object DependencyVersion { + /** querydsl */ + const val QUERYDSL = "5.0.0" + /** external */ const val ARROW_FX = "1.2.4" const val KOTLIN_LOGGING = "6.0.9" diff --git a/src/main/kotlin/com/hero/alignlab/domain/auth/application/AuthFacade.kt b/src/main/kotlin/com/hero/alignlab/domain/auth/application/AuthFacade.kt index 0098e4f..da0595c 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/auth/application/AuthFacade.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/auth/application/AuthFacade.kt @@ -17,6 +17,7 @@ import com.hero.alignlab.domain.user.domain.UserInfo import com.hero.alignlab.exception.ErrorCode import com.hero.alignlab.exception.InvalidRequestException import com.hero.alignlab.exception.InvalidTokenException +import com.hero.alignlab.extension.coExecute import org.springframework.stereotype.Service import reactor.core.publisher.Mono import java.time.LocalDateTime @@ -59,28 +60,35 @@ class AuthFacade( throw InvalidRequestException(ErrorCode.DUPLICATED_USERNAME_ERROR) } - val userInfo = userService.save(UserInfo(nickname = request.username)) + val userInfo = txTemplates.writer.coExecute { + val userInfo = userService.save(UserInfo(nickname = request.username)) - credentialUserInfoService.save( - CredentialUserInfo( - uid = userInfo.id, - username = request.username, - password = EncryptData.enc(request.password, encryptor) + credentialUserInfoService.save( + CredentialUserInfo( + uid = userInfo.id, + username = request.username, + password = EncryptData.enc(request.password, encryptor) + ) ) - ) - return SignUpResponse( - accessToken = jwtTokenService.createToken(userInfo.id, TOKEN_EXPIRED_DATE) - ) + userInfo + } + + val accessToken = jwtTokenService.createToken(userInfo.id, TOKEN_EXPIRED_DATE) + + return SignUpResponse(accessToken) } suspend fun signIn(request: SignInRequest): SignInResponse { - val credentialUserInfo = credentialUserInfoService.findByUsernameAndPassword(request.username, request.password) + val credentialUserInfo = credentialUserInfoService.findByUsernameAndPassword( + username = request.username, + password = request.password + ) - val user = userService.getUserByIdOrThrowSync(credentialUserInfo.uid) + val userInfo = userService.getUserByIdOrThrowSync(credentialUserInfo.uid) - return SignInResponse( - accessToken = jwtTokenService.createToken(user.id, TOKEN_EXPIRED_DATE) - ) + val accessToken = jwtTokenService.createToken(userInfo.id, TOKEN_EXPIRED_DATE) + + return SignInResponse(accessToken) } } diff --git a/src/main/kotlin/com/hero/alignlab/domain/user/application/UserService.kt b/src/main/kotlin/com/hero/alignlab/domain/user/application/UserService.kt index f68b42a..c0784ce 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/user/application/UserService.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/user/application/UserService.kt @@ -33,9 +33,6 @@ class UserService( getUserByIdOrThrowSync(user.uid) } - return UserInfoResponse( - uid = userInfo.id, - nickname = userInfo.nickname - ) + return UserInfoResponse.from(userInfo) } } diff --git a/src/main/kotlin/com/hero/alignlab/domain/user/infrastructure/CredentialUserInfoRepository.kt b/src/main/kotlin/com/hero/alignlab/domain/user/infrastructure/CredentialUserInfoRepository.kt index 384f99d..51f448a 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/user/infrastructure/CredentialUserInfoRepository.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/user/infrastructure/CredentialUserInfoRepository.kt @@ -2,14 +2,39 @@ package com.hero.alignlab.domain.user.infrastructure import com.hero.alignlab.common.encrypt.EncryptData import com.hero.alignlab.domain.user.domain.CredentialUserInfo +import com.hero.alignlab.domain.user.domain.QCredentialUserInfo +import com.hero.alignlab.domain.user.domain.QUserInfo +import jakarta.persistence.EntityManager +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport import org.springframework.stereotype.Repository import org.springframework.transaction.annotation.Transactional @Transactional(readOnly = true) @Repository -interface CredentialUserInfoRepository : JpaRepository { +interface CredentialUserInfoRepository : JpaRepository, CredentialUserInfoQRepository { fun existsByUsername(username: String): Boolean fun findByUsernameAndPassword(username: String, password: EncryptData): CredentialUserInfo? } + +@Transactional(readOnly = true) +interface CredentialUserInfoQRepository { + +} + +class CredentialUserInfoRepositoryImpl : CredentialUserInfoQRepository, + QuerydslRepositorySupport(CredentialUserInfo::class.java) { + @Autowired + @Qualifier("heroEntityManager") + override fun setEntityManager(entityManager: EntityManager) { + super.setEntityManager(entityManager) + } + + private val qCredentialUserInfo = QCredentialUserInfo.credentialUserInfo + private val qUserInfo = QUserInfo.userInfo + + +} diff --git a/src/main/kotlin/com/hero/alignlab/domain/user/model/response/UserInfoResponse.kt b/src/main/kotlin/com/hero/alignlab/domain/user/model/response/UserInfoResponse.kt index 4a4e173..08f898f 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/user/model/response/UserInfoResponse.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/user/model/response/UserInfoResponse.kt @@ -1,6 +1,17 @@ package com.hero.alignlab.domain.user.model.response +import com.hero.alignlab.domain.user.domain.UserInfo + data class UserInfoResponse( val uid: Long, val nickname: String, -) +) { + companion object { + fun from(user: UserInfo): UserInfoResponse { + return UserInfoResponse( + uid = user.id, + nickname = user.nickname + ) + } + } +} diff --git a/src/main/kotlin/com/hero/alignlab/extension/QuerydslExtension.kt b/src/main/kotlin/com/hero/alignlab/extension/QuerydslExtension.kt new file mode 100644 index 0000000..337b450 --- /dev/null +++ b/src/main/kotlin/com/hero/alignlab/extension/QuerydslExtension.kt @@ -0,0 +1,83 @@ +package com.hero.alignlab.extension + +import com.hero.alignlab.exception.AlignlabException +import com.hero.alignlab.exception.ErrorCode +import com.querydsl.core.types.dsl.* +import com.querydsl.jpa.impl.JPAQuery +import org.springframework.data.domain.* +import org.springframework.data.jpa.repository.support.Querydsl +import java.time.LocalDateTime + +fun Querydsl?.execute(query: JPAQuery, pageable: Pageable): Page { + return this.takeUnless { querydsl -> querydsl == null } + ?.let { queryDsl -> + queryDsl.applyPagination(pageable, query).run { + PageImpl(this.fetch(), pageable, this.fetchCount()) + } + } ?: throw AlignlabException(ErrorCode.QUERY_DSL_NOT_EXISTS_ERROR) +} + +fun Querydsl?.executeSlice(query: JPAQuery, pageable: Pageable): Slice { + return this.takeUnless { querydsl -> querydsl == null } + ?.let { queryDsl -> + queryDsl.applyPagination(pageable, query).run { + this.limit(pageable.pageSize + 1L) + .fetch() + }.run { + var hasNext = false + if (this.size > pageable.pageSize) { + hasNext = true + this.removeAt(pageable.pageSize) + } + SliceImpl(this, pageable, hasNext) + } + } ?: throw AlignlabException(ErrorCode.QUERY_DSL_NOT_EXISTS_ERROR) +} + +fun StringPath.isEquals(parameter: String?): BooleanExpression? { + return parameter?.let { param -> this.eq(param) } +} + +fun NumberPath.isEquals(parameter: Long?): BooleanExpression? { + return parameter?.let { param -> this.eq(param) } +} + +fun StringPath.isContains(parameter: String?): BooleanExpression? { + return parameter?.let { param -> this.contains(param) } +} + +fun NumberPath.isIn(parameters: Set?): BooleanExpression? { + return parameters.takeUnless { params -> params.isNullOrEmpty() }?.let { params -> this.`in`(params) } +} + +fun > EnumPath.isIn(parameters: Set?): BooleanExpression? { + return parameters?.takeIf { params -> params.isNotEmpty() }?.let { params -> this.`in`(params) } +} + +fun NumberPath.isGoe(parameter: Long?): BooleanExpression? { + return parameter?.let { param -> this.goe(param) } +} + +fun NumberExpression.isGoe(parameter: Long?): BooleanExpression? { + return parameter?.let { param -> this.goe(param) } +} + +fun NumberExpression.isLoe(parameter: Long?): BooleanExpression? { + return parameter?.let { param -> this.loe(param) } +} + +fun NumberPath.isLoe(parameter: Long?): BooleanExpression? { + return parameter?.let { param -> this.loe(param) } +} + +fun NumberPath.isNotIn(parameters: Set?): BooleanExpression? { + return parameters.takeUnless { params -> params.isNullOrEmpty() }?.let { params -> this.notIn(params) } +} + +fun DateTimePath.isGoe(parameter: LocalDateTime?): BooleanExpression? { + return parameter?.let { param -> this.goe(param) } +} + +fun DateTimePath.isLoe(parameter: LocalDateTime?): BooleanExpression? { + return parameter?.let { param -> this.loe(param) } +}