diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d8335471..22ea6fb7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -38,11 +38,13 @@ jjwt-jackson = { module = "io.jsonwebtoken:jjwt-jackson", version.ref = "jjwt" } hibernate-spatial = { module = "org.hibernate:hibernate-spatial", version = "6.2.6.Final" } -kotlin-jdsl = { module = "com.linecorp.kotlin-jdsl:spring-data-kotlin-jdsl-starter-jakarta", version = "2.2.1.RELEASE" } - database-h2 = { module = "com.h2database:h2" } connector-mysql = { module = "com.mysql:mysql-connector-j" } +kotlin-jdsl-jpql-dsl = { module = "com.linecorp.kotlin-jdsl:jpql-dsl", version = "3.0.0" } +kotlin-jdsl-jpql-render = { module = "com.linecorp.kotlin-jdsl:jpql-render", version = "3.0.0" } +kotlin-jdsl-spring-data-jpa-support = { module = "com.linecorp.kotlin-jdsl:spring-data-jpa-support", version = "3.0.0" } + ## test spring-starter-test = { module = "org.springframework.boot:spring-boot-starter-test" } spring-graphql-test = { module = "org.springframework.graphql:spring-graphql-test" } @@ -75,6 +77,11 @@ kotlin-libs = [ "reactor-kotlin-extensions", "jackson-module-kotlin", ] +kotlin-jdsl = [ + "kotlin-jdsl-jpql-dsl", + "kotlin-jdsl-jpql-render", + "kotlin-jdsl-spring-data-jpa-support", +] ## test kotest = ["kotest-runner-junit5", "kotest-assertions-arrow", "kotest-extensions-spring"] diff --git a/server-app/build.gradle.kts b/server-app/build.gradle.kts index 84cbcdd4..98e7189e 100644 --- a/server-app/build.gradle.kts +++ b/server-app/build.gradle.kts @@ -15,7 +15,7 @@ dependencies { implementation(libs.spring.security) implementation(libs.spring.data.jpa) implementation(libs.hibernate.spatial) - implementation(libs.kotlin.jdsl) + implementation(libs.bundles.kotlin.jdsl) implementation(libs.jjwt.api) runtimeOnly(libs.jjwt.impl) diff --git a/server-app/src/main/kotlin/com/santaclose/app/appUser/repository/AppUserAppQueryRepositoryImpl.kt b/server-app/src/main/kotlin/com/santaclose/app/appUser/repository/AppUserAppQueryRepositoryImpl.kt index 3c5aea04..6032900b 100644 --- a/server-app/src/main/kotlin/com/santaclose/app/appUser/repository/AppUserAppQueryRepositoryImpl.kt +++ b/server-app/src/main/kotlin/com/santaclose/app/appUser/repository/AppUserAppQueryRepositoryImpl.kt @@ -2,24 +2,33 @@ package com.santaclose.app.appUser.repository import arrow.core.Either import arrow.core.Either.Companion.catch -import com.linecorp.kotlinjdsl.querydsl.expression.col -import com.linecorp.kotlinjdsl.spring.data.SpringDataQueryFactory -import com.linecorp.kotlinjdsl.spring.data.listQuery +import com.linecorp.kotlinjdsl.dsl.jpql.jpql +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext +import com.linecorp.kotlinjdsl.support.spring.data.jpa.extension.createQuery import com.santaclose.lib.entity.appUser.AppUser +import jakarta.persistence.EntityManager import org.springframework.stereotype.Repository @Repository class AppUserAppQueryRepositoryImpl( - private val springDataQueryFactory: SpringDataQueryFactory, + private val entityManager: EntityManager, + private val jpqlRenderContext: JpqlRenderContext, ) : AppUserAppQueryRepository { override fun findBySocialId(socialId: String): Either = catch { - springDataQueryFactory - .listQuery { - select(entity(AppUser::class)) - from(AppUser::class) - where(col(AppUser::socialId).equal(socialId)) - limit(1) - } + val query = jpql { + select( + entity(AppUser::class), + ).from( + entity(AppUser::class), + ).where( + path(AppUser::socialId).eq(socialId), + ) + } + + entityManager + .createQuery(query, jpqlRenderContext) + .apply { maxResults = 1 } + .resultList .firstOrNull() } } diff --git a/server-app/src/main/kotlin/com/santaclose/app/mountain/repository/MountainAppQueryRepositoryImpl.kt b/server-app/src/main/kotlin/com/santaclose/app/mountain/repository/MountainAppQueryRepositoryImpl.kt index 5d56bbe8..075b85a3 100644 --- a/server-app/src/main/kotlin/com/santaclose/app/mountain/repository/MountainAppQueryRepositoryImpl.kt +++ b/server-app/src/main/kotlin/com/santaclose/app/mountain/repository/MountainAppQueryRepositoryImpl.kt @@ -1,13 +1,9 @@ package com.santaclose.app.mountain.repository import arrow.core.Either -import arrow.core.recover -import com.linecorp.kotlinjdsl.querydsl.expression.col -import com.linecorp.kotlinjdsl.querydsl.from.fetch -import com.linecorp.kotlinjdsl.querydsl.from.join -import com.linecorp.kotlinjdsl.spring.data.SpringDataQueryFactory -import com.linecorp.kotlinjdsl.spring.data.listQuery -import com.linecorp.kotlinjdsl.spring.data.singleQuery +import com.linecorp.kotlinjdsl.dsl.jpql.jpql +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext +import com.linecorp.kotlinjdsl.support.spring.data.jpa.extension.createQuery import com.santaclose.app.mountain.repository.dto.MountainLocationDto import com.santaclose.lib.entity.location.Location import com.santaclose.lib.entity.mountain.Mountain @@ -15,40 +11,47 @@ import com.santaclose.lib.entity.mountainRestaurant.MountainRestaurant import com.santaclose.lib.entity.restaurant.Restaurant import com.santaclose.lib.web.exception.DomainError.DBFailure import com.santaclose.lib.web.exception.catchDB -import jakarta.persistence.NoResultException -import jakarta.persistence.criteria.JoinType +import jakarta.persistence.EntityManager import org.springframework.stereotype.Repository @Repository class MountainAppQueryRepositoryImpl( - private val springDataQueryFactory: SpringDataQueryFactory, + private val entityManager: EntityManager, + private val jpqlRenderContext: JpqlRenderContext, ) : MountainAppQueryRepository { override fun findOneWithLocation(id: Long): Either = - Either.catch { - springDataQueryFactory.singleQuery { - select(entity(Mountain::class)) - from(Mountain::class) - fetch(Mountain::location, JoinType.INNER) - where(col(Mountain::id).equal(id)) - } - }.recover { - if (it is NoResultException) { - null - } else { - raise(DBFailure(it)) + Either.catchDB { + val query = jpql { + select( + entity(Mountain::class), + ).from( + entity(Mountain::class), + innerFetchJoin(Mountain::location), + ).where( + path(Mountain::id).eq(id), + ) } + + entityManager.createQuery(query, jpqlRenderContext).resultList.firstOrNull() } override fun findLocationByRestaurant(restaurantId: Long): Either> = Either.catchDB { - springDataQueryFactory.listQuery { - selectMulti(col(Mountain::id), col(Location::point)) - from(Mountain::class) - join(Mountain::mountainRestaurant, JoinType.INNER) - join(MountainRestaurant::restaurant, JoinType.INNER) - join(Mountain::location, JoinType.INNER) - where(col(Restaurant::id).equal(restaurantId)) + val query = jpql { + selectNew( + path(Mountain::id), + path(Location::point), + ).from( + entity(Mountain::class), + innerJoin(Mountain::mountainRestaurant), + innerJoin(MountainRestaurant::restaurant), + innerJoin(Mountain::location), + ).where( + path(Restaurant::id).eq(restaurantId), + ) } + + entityManager.createQuery(query, jpqlRenderContext).resultList } } diff --git a/server-app/src/main/kotlin/com/santaclose/app/mountainRestaurant/repository/MountainRestaurantAppQueryRepositoryImpl.kt b/server-app/src/main/kotlin/com/santaclose/app/mountainRestaurant/repository/MountainRestaurantAppQueryRepositoryImpl.kt index d282e8b0..75e72ef4 100644 --- a/server-app/src/main/kotlin/com/santaclose/app/mountainRestaurant/repository/MountainRestaurantAppQueryRepositoryImpl.kt +++ b/server-app/src/main/kotlin/com/santaclose/app/mountainRestaurant/repository/MountainRestaurantAppQueryRepositoryImpl.kt @@ -1,10 +1,9 @@ package com.santaclose.app.mountainRestaurant.repository import arrow.core.Either -import com.linecorp.kotlinjdsl.querydsl.expression.col -import com.linecorp.kotlinjdsl.querydsl.from.join -import com.linecorp.kotlinjdsl.spring.data.SpringDataQueryFactory -import com.linecorp.kotlinjdsl.spring.data.listQuery +import com.linecorp.kotlinjdsl.dsl.jpql.jpql +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext +import com.linecorp.kotlinjdsl.support.spring.data.jpa.extension.createQuery import com.santaclose.app.mountainRestaurant.repository.dto.LatestMountainDto import com.santaclose.app.mountainRestaurant.repository.dto.LatestRestaurantDto import com.santaclose.lib.entity.mountain.Mountain @@ -12,36 +11,57 @@ import com.santaclose.lib.entity.mountainRestaurant.MountainRestaurant import com.santaclose.lib.entity.restaurant.Restaurant import com.santaclose.lib.web.exception.DomainError.DBFailure import com.santaclose.lib.web.exception.catchDB -import jakarta.persistence.criteria.JoinType +import jakarta.persistence.EntityManager import org.springframework.stereotype.Repository @Repository class MountainRestaurantAppQueryRepositoryImpl( - private val springDataQueryFactory: SpringDataQueryFactory, + private val entityManager: EntityManager, + private val jpqlRenderContext: JpqlRenderContext, ) : MountainRestaurantAppQueryRepository { override fun findMountainByRestaurant(id: Long, limit: Int): Either> = Either.catchDB { - springDataQueryFactory.listQuery { - selectMulti(col(Mountain::id), col(Mountain::name)) - from(MountainRestaurant::class) - join(MountainRestaurant::mountain, JoinType.INNER) - join(MountainRestaurant::restaurant, JoinType.INNER) - where(col(Restaurant::id).equal(id)) - orderBy(col(Mountain::id).desc()) - limit(limit) + val query = jpql { + selectNew( + path(Mountain::id), + path(Mountain::name), + ).from( + entity(Mountain::class), + innerJoin(Mountain::mountainRestaurant), + innerJoin(MountainRestaurant::restaurant), + ).where( + path(Restaurant::id).eq(id), + ).orderBy( + path(Mountain::id).desc(), + ) } + + entityManager + .createQuery(query, jpqlRenderContext) + .apply { maxResults = limit } + .resultList } override fun findRestaurantByMountain(id: Long, limit: Int): Either> = Either.catchDB { - springDataQueryFactory.listQuery { - selectMulti(col(Restaurant::id), col(Restaurant::name)) - from(MountainRestaurant::class) - join(MountainRestaurant::mountain, JoinType.INNER) - join(MountainRestaurant::restaurant, JoinType.INNER) - where(col(Mountain::id).equal(id)) - orderBy(col(Restaurant::id).desc()) - limit(limit) + val query = jpql { + selectNew( + path(Restaurant::id), + path(Restaurant::name), + ).from( + entity(MountainRestaurant::class), + innerJoin(MountainRestaurant::mountain), + innerJoin(MountainRestaurant::restaurant), + ).where( + path(Mountain::id).eq(id), + ).orderBy( + path(Restaurant::id).desc(), + ) } + + entityManager + .createQuery(query, jpqlRenderContext) + .apply { maxResults = limit } + .resultList } } diff --git a/server-app/src/main/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppQueryRepositoryImpl.kt b/server-app/src/main/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppQueryRepositoryImpl.kt index 321ae892..ae043a2c 100644 --- a/server-app/src/main/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppQueryRepositoryImpl.kt +++ b/server-app/src/main/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppQueryRepositoryImpl.kt @@ -2,60 +2,68 @@ package com.santaclose.app.mountainReview.repository import arrow.core.Either import arrow.core.recover -import com.linecorp.kotlinjdsl.query.spec.expression.EntitySpec -import com.linecorp.kotlinjdsl.querydsl.expression.avg -import com.linecorp.kotlinjdsl.querydsl.expression.col -import com.linecorp.kotlinjdsl.querydsl.from.fetch -import com.linecorp.kotlinjdsl.querydsl.from.join -import com.linecorp.kotlinjdsl.spring.data.SpringDataQueryFactory -import com.linecorp.kotlinjdsl.spring.data.listQuery -import com.linecorp.kotlinjdsl.spring.data.singleQuery +import com.linecorp.kotlinjdsl.dsl.jpql.jpql +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext +import com.linecorp.kotlinjdsl.support.spring.data.jpa.extension.createQuery import com.santaclose.app.mountainReview.repository.dto.MountainRatingAverageDto import com.santaclose.lib.entity.mountain.Mountain import com.santaclose.lib.entity.mountainReview.MountainRating import com.santaclose.lib.entity.mountainReview.MountainReview import com.santaclose.lib.web.exception.DomainError.DBFailure import com.santaclose.lib.web.exception.catchDB +import jakarta.persistence.EntityManager import jakarta.persistence.PersistenceException -import jakarta.persistence.criteria.JoinType import org.springframework.stereotype.Repository @Repository class MountainReviewAppQueryRepositoryImpl( - private val springDataQueryFactory: SpringDataQueryFactory, + private val entityManager: EntityManager, + private val jpqlRenderContext: JpqlRenderContext, ) : MountainReviewAppQueryRepository { override fun findAllByMountainId(mountainId: Long, limit: Int): Either> = Either.catchDB { - springDataQueryFactory.listQuery { - val mountainReview: EntitySpec = entity(MountainReview::class) - select(mountainReview) - from(mountainReview) - fetch(MountainReview::mountain, JoinType.INNER) - where(col(Mountain::id).equal(mountainId)) - orderBy(col(Mountain::id).desc()) - limit(limit) + val query = jpql { + select( + entity(MountainReview::class), + ).from( + entity(MountainReview::class), + innerJoin(MountainReview::mountain), + ).where( + path(Mountain::id).eq(mountainId), + ).orderBy( + path(Mountain::id).desc(), + ) } + + entityManager + .createQuery(query, jpqlRenderContext) + .apply { maxResults = limit } + .resultList } override fun findMountainRatingAverages(mountainId: Long): Either = Either.catch { - springDataQueryFactory.singleQuery { - val mountainReview: EntitySpec = entity(MountainReview::class) - selectMulti( - avg(MountainRating::scenery), - avg(MountainRating::tree), - avg(MountainRating::trail), - avg(MountainRating::parking), - avg(MountainRating::toilet), - avg(MountainRating::traffic), - count(col(MountainReview::id)), + val query = jpql { + selectNew( + avg(path(MountainReview::rating)(MountainRating::scenery)), + avg(path(MountainReview::rating)(MountainRating::tree)), + avg(path(MountainReview::rating)(MountainRating::trail)), + avg(path(MountainReview::rating)(MountainRating::parking)), + avg(path(MountainReview::rating)(MountainRating::toilet)), + avg(path(MountainReview::rating)(MountainRating::traffic)), + count(MountainReview::id), + ).from( + entity(MountainReview::class), + innerJoin(MountainReview::mountain), + ).where( + path(Mountain::id).eq(mountainId), ) - associate(MountainReview::class, MountainRating::class, on(MountainReview::rating)) - from(mountainReview) - join(MountainReview::mountain, JoinType.INNER) - where(col(Mountain::id).equal(mountainId)) } + + entityManager + .createQuery(query, jpqlRenderContext) + .singleResult }.recover { if (it is PersistenceException) { MountainRatingAverageDto.empty diff --git a/server-app/src/main/kotlin/com/santaclose/app/restaurant/repository/RestaurantAppQueryRepositoryImpl.kt b/server-app/src/main/kotlin/com/santaclose/app/restaurant/repository/RestaurantAppQueryRepositoryImpl.kt index 2fb68889..42048a88 100644 --- a/server-app/src/main/kotlin/com/santaclose/app/restaurant/repository/RestaurantAppQueryRepositoryImpl.kt +++ b/server-app/src/main/kotlin/com/santaclose/app/restaurant/repository/RestaurantAppQueryRepositoryImpl.kt @@ -1,12 +1,9 @@ package com.santaclose.app.restaurant.repository import arrow.core.Either -import com.linecorp.kotlinjdsl.querydsl.expression.col -import com.linecorp.kotlinjdsl.querydsl.from.fetch -import com.linecorp.kotlinjdsl.querydsl.from.join -import com.linecorp.kotlinjdsl.spring.data.SpringDataQueryFactory -import com.linecorp.kotlinjdsl.spring.data.listQuery -import com.linecorp.kotlinjdsl.spring.data.singleQuery +import com.linecorp.kotlinjdsl.dsl.jpql.jpql +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext +import com.linecorp.kotlinjdsl.support.spring.data.jpa.extension.createQuery import com.santaclose.app.restaurant.repository.dto.RestaurantLocationDto import com.santaclose.lib.entity.location.Location import com.santaclose.lib.entity.mountain.Mountain @@ -14,32 +11,48 @@ import com.santaclose.lib.entity.mountainRestaurant.MountainRestaurant import com.santaclose.lib.entity.restaurant.Restaurant import com.santaclose.lib.web.exception.DomainError.DBFailure import com.santaclose.lib.web.exception.catchDB -import jakarta.persistence.criteria.JoinType +import jakarta.persistence.EntityManager import org.springframework.stereotype.Repository @Repository -class RestaurantAppQueryRepositoryImpl(private val springDataQueryFactory: SpringDataQueryFactory) : +class RestaurantAppQueryRepositoryImpl( + private val entityManager: EntityManager, + private val jpqlRenderContext: JpqlRenderContext, +) : RestaurantAppQueryRepository { override fun findOneWithLocation(id: Long): Either = Either.catchDB { - springDataQueryFactory.singleQuery { - select(entity(Restaurant::class)) - from(Restaurant::class) - where(col(Restaurant::id).equal(id)) - fetch(Restaurant::location, JoinType.INNER) + val query = jpql { + select( + entity(Restaurant::class), + ).from( + entity(Restaurant::class), + innerFetchJoin(Restaurant::location), + ).where( + path(Restaurant::id).eq(id), + ) } + + entityManager.createQuery(query, jpqlRenderContext).singleResult } override fun findLocationByMountain(mountainId: Long): Either> = Either.catchDB { - this.springDataQueryFactory.listQuery { - selectMulti(col(Restaurant::id), col(Location::point)) - from(Mountain::class) - join(Mountain::mountainRestaurant, JoinType.INNER) - join(MountainRestaurant::restaurant, JoinType.INNER) - join(Restaurant::location, JoinType.INNER) - where(col(Mountain::id).equal(mountainId)) + val query = jpql { + selectNew( + path(Restaurant::id), + path(Location::point), + ).from( + entity(Mountain::class), + innerJoin(Mountain::mountainRestaurant), + innerJoin(MountainRestaurant::restaurant), + innerJoin(Restaurant::location), + ).where( + path(Mountain::id).eq(mountainId), + ) } + + entityManager.createQuery(query, jpqlRenderContext).resultList } } diff --git a/server-app/src/main/kotlin/com/santaclose/app/restaurantReview/repository/RestaurantReviewAppQueryRepositoryImpl.kt b/server-app/src/main/kotlin/com/santaclose/app/restaurantReview/repository/RestaurantReviewAppQueryRepositoryImpl.kt index 7e647eae..91e27304 100644 --- a/server-app/src/main/kotlin/com/santaclose/app/restaurantReview/repository/RestaurantReviewAppQueryRepositoryImpl.kt +++ b/server-app/src/main/kotlin/com/santaclose/app/restaurantReview/repository/RestaurantReviewAppQueryRepositoryImpl.kt @@ -2,13 +2,9 @@ package com.santaclose.app.restaurantReview.repository import arrow.core.Either import arrow.core.recover -import com.linecorp.kotlinjdsl.querydsl.expression.avg -import com.linecorp.kotlinjdsl.querydsl.expression.col -import com.linecorp.kotlinjdsl.querydsl.expression.count -import com.linecorp.kotlinjdsl.querydsl.from.join -import com.linecorp.kotlinjdsl.spring.data.SpringDataQueryFactory -import com.linecorp.kotlinjdsl.spring.data.listQuery -import com.linecorp.kotlinjdsl.spring.data.singleQuery +import com.linecorp.kotlinjdsl.dsl.jpql.jpql +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext +import com.linecorp.kotlinjdsl.support.spring.data.jpa.extension.createQuery import com.santaclose.app.restaurantReview.repository.dto.LatestRestaurantReviewDto import com.santaclose.app.restaurantReview.repository.dto.RestaurantRatingAverageDto import com.santaclose.lib.entity.restaurant.Restaurant @@ -16,49 +12,62 @@ import com.santaclose.lib.entity.restaurantReview.RestaurantRating import com.santaclose.lib.entity.restaurantReview.RestaurantReview import com.santaclose.lib.web.exception.DomainError.DBFailure import com.santaclose.lib.web.exception.catchDB +import jakarta.persistence.EntityManager import jakarta.persistence.PersistenceException -import jakarta.persistence.criteria.JoinType import org.springframework.stereotype.Repository @Repository class RestaurantReviewAppQueryRepositoryImpl( - private val springDataQueryFactory: SpringDataQueryFactory, + private val entityManager: EntityManager, + private val jpqlRenderContext: JpqlRenderContext, ) : RestaurantReviewAppQueryRepository { override fun findAllByRestaurant( restaurantId: Long, limit: Int, ): Either> = Either.catchDB { - springDataQueryFactory.listQuery { - selectMulti( - col(RestaurantReview::id), - col(RestaurantReview::title), - col(RestaurantReview::content), + val query = jpql { + selectNew( + path(RestaurantReview::id), + path(RestaurantReview::title), + path(RestaurantReview::content), + ).from( + entity(RestaurantReview::class), + innerJoin(RestaurantReview::restaurant), + ).where( + path(Restaurant::id).eq(restaurantId), + ).orderBy( + path(RestaurantReview::id).desc(), ) - from(RestaurantReview::class) - join(RestaurantReview::restaurant, JoinType.INNER) - where(col(Restaurant::id).equal(restaurantId)) - orderBy(col(RestaurantReview::id).desc()) - limit(limit) } + + entityManager + .createQuery(query, jpqlRenderContext) + .apply { maxResults = limit } + .resultList } override fun findRestaurantRatingAverages(restaurantId: Long): Either = Either.catch { - springDataQueryFactory.singleQuery { - selectMulti( - avg(RestaurantRating::taste), - avg(RestaurantRating::parkingSpace), - avg(RestaurantRating::kind), - avg(RestaurantRating::clean), - avg(RestaurantRating::mood), + val query = jpql { + selectNew( + avg(path(RestaurantReview::rating)(RestaurantRating::taste)), + avg(path(RestaurantReview::rating)(RestaurantRating::parkingSpace)), + avg(path(RestaurantReview::rating)(RestaurantRating::kind)), + avg(path(RestaurantReview::rating)(RestaurantRating::clean)), + avg(path(RestaurantReview::rating)(RestaurantRating::mood)), count(RestaurantReview::id), + ).from( + entity(RestaurantReview::class), + innerJoin(RestaurantReview::restaurant), + ).where( + path(Restaurant::id).eq(restaurantId), ) - from(RestaurantReview::class) - join(RestaurantReview::restaurant, JoinType.INNER) - associate(RestaurantReview::class, RestaurantRating::class, on(RestaurantReview::rating)) - where(col(Restaurant::id).equal(restaurantId)) } + + entityManager + .createQuery(query, jpqlRenderContext) + .singleResult }.recover { if (it is PersistenceException) { RestaurantRatingAverageDto.empty diff --git a/server-app/src/main/kotlin/com/santaclose/app/sample/repository/SampleAppQueryRepositoryImpl.kt b/server-app/src/main/kotlin/com/santaclose/app/sample/repository/SampleAppQueryRepositoryImpl.kt index 0f01259a..18b0ae5c 100644 --- a/server-app/src/main/kotlin/com/santaclose/app/sample/repository/SampleAppQueryRepositoryImpl.kt +++ b/server-app/src/main/kotlin/com/santaclose/app/sample/repository/SampleAppQueryRepositoryImpl.kt @@ -1,25 +1,35 @@ package com.santaclose.app.sample.repository import arrow.core.Either -import com.linecorp.kotlinjdsl.querydsl.expression.col -import com.linecorp.kotlinjdsl.spring.data.SpringDataQueryFactory -import com.linecorp.kotlinjdsl.spring.data.singleQuery +import com.linecorp.kotlinjdsl.dsl.jpql.jpql +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext +import com.linecorp.kotlinjdsl.support.spring.data.jpa.extension.createQuery import com.santaclose.app.sample.controller.dto.SampleAppDetail import com.santaclose.lib.entity.sample.Sample import com.santaclose.lib.web.exception.DomainError.DBFailure import com.santaclose.lib.web.exception.catchDB +import jakarta.persistence.EntityManager import org.springframework.stereotype.Repository @Repository class SampleAppQueryRepositoryImpl( - private val springDataQueryFactory: SpringDataQueryFactory, + private val entityManager: EntityManager, + private val jpqlRenderContext: JpqlRenderContext, ) : SampleAppQueryRepository { override fun findByPrice(price: Int): Either = Either.catchDB { - springDataQueryFactory.singleQuery { - selectMulti(col(Sample::name), col(Sample::price), col(Sample::status)) - from(Sample::class) - where(col(Sample::price).equal(price)) + val query = jpql { + selectNew( + path(Sample::name), + path(Sample::price), + path(Sample::status), + ).from( + entity(Sample::class), + ).where( + path(Sample::price).eq(price), + ) } + + entityManager.createQuery(query, jpqlRenderContext).singleResult } } diff --git a/server-app/src/test/kotlin/com/santaclose/app/appUser/repository/AppUserAppQueryRepositoryImplTest.kt b/server-app/src/test/kotlin/com/santaclose/app/appUser/repository/AppUserAppQueryRepositoryImplTest.kt index 67bbb4dc..c905bbaa 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/appUser/repository/AppUserAppQueryRepositoryImplTest.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/appUser/repository/AppUserAppQueryRepositoryImplTest.kt @@ -1,6 +1,6 @@ package com.santaclose.app.appUser.repository -import com.santaclose.app.util.createQueryFactory +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.santaclose.lib.entity.appUser.AppUser import io.kotest.assertions.arrow.core.shouldBeRight import jakarta.persistence.EntityManager @@ -13,7 +13,7 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest internal class AppUserAppQueryRepositoryImplTest @Autowired constructor( private val em: EntityManager, ) { - private val appUserAppRepository = AppUserAppQueryRepositoryImpl(em.createQueryFactory()) + private val appUserAppRepository = AppUserAppQueryRepositoryImpl(em, JpqlRenderContext()) @Nested inner class FindBySocialId { diff --git a/server-app/src/test/kotlin/com/santaclose/app/mountain/repository/MountainAppQueryRepositoryImplTest.kt b/server-app/src/test/kotlin/com/santaclose/app/mountain/repository/MountainAppQueryRepositoryImplTest.kt index 0c9fb896..27419c15 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/mountain/repository/MountainAppQueryRepositoryImplTest.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/mountain/repository/MountainAppQueryRepositoryImplTest.kt @@ -1,10 +1,10 @@ package com.santaclose.app.mountain.repository +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.santaclose.app.util.createAppUser import com.santaclose.app.util.createLocation import com.santaclose.app.util.createMountain import com.santaclose.app.util.createMountainRestaurant -import com.santaclose.app.util.createQueryFactory import com.santaclose.app.util.createRestaurant import com.santaclose.lib.entity.location.Location import io.kotest.assertions.arrow.core.shouldBeRight @@ -21,7 +21,7 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest internal class MountainAppQueryRepositoryImplTest @Autowired constructor( private val em: EntityManager, ) { - private val mountainAppQueryRepository = MountainAppQueryRepositoryImpl(em.createQueryFactory()) + private val mountainAppQueryRepository = MountainAppQueryRepositoryImpl(em, JpqlRenderContext()) @Nested inner class FindOneWithLocation { diff --git a/server-app/src/test/kotlin/com/santaclose/app/mountain/service/MountainAppQueryServiceTest.kt b/server-app/src/test/kotlin/com/santaclose/app/mountain/service/MountainAppQueryServiceTest.kt index 0dff8ac6..82cfcf4c 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/mountain/service/MountainAppQueryServiceTest.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/mountain/service/MountainAppQueryServiceTest.kt @@ -1,5 +1,6 @@ package com.santaclose.app.mountain.service +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.santaclose.app.mountain.repository.MountainAppQueryRepositoryImpl import com.santaclose.app.mountainRestaurant.repository.MountainRestaurantAppQueryRepositoryImpl import com.santaclose.app.mountainReview.repository.MountainReviewAppQueryRepositoryImpl @@ -8,7 +9,6 @@ import com.santaclose.app.util.createAppUser import com.santaclose.app.util.createMountain import com.santaclose.app.util.createMountainRestaurant import com.santaclose.app.util.createMountainReview -import com.santaclose.app.util.createQueryFactory import com.santaclose.app.util.createRestaurant import com.santaclose.lib.web.exception.DomainError.NotFound import io.kotest.assertions.arrow.core.shouldBeLeft @@ -25,12 +25,13 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest internal class MountainAppQueryServiceTest @Autowired constructor( private val em: EntityManager, ) { + private val jpqlRenderContext = JpqlRenderContext() private val mountainAppQueryService = MountainAppQueryService( - MountainAppQueryRepositoryImpl(em.createQueryFactory()), - MountainReviewAppQueryRepositoryImpl(em.createQueryFactory()), - RestaurantAppQueryRepositoryImpl(em.createQueryFactory()), - MountainRestaurantAppQueryRepositoryImpl(em.createQueryFactory()), + MountainAppQueryRepositoryImpl(em, jpqlRenderContext), + MountainReviewAppQueryRepositoryImpl(em, jpqlRenderContext), + RestaurantAppQueryRepositoryImpl(em, jpqlRenderContext), + MountainRestaurantAppQueryRepositoryImpl(em, jpqlRenderContext), ) @Nested diff --git a/server-app/src/test/kotlin/com/santaclose/app/mountainRestaurant/repository/MountainRestaurantAppQueryRepositoryImplTest.kt b/server-app/src/test/kotlin/com/santaclose/app/mountainRestaurant/repository/MountainRestaurantAppQueryRepositoryImplTest.kt index 7e9270ec..cdaff419 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/mountainRestaurant/repository/MountainRestaurantAppQueryRepositoryImplTest.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/mountainRestaurant/repository/MountainRestaurantAppQueryRepositoryImplTest.kt @@ -1,9 +1,9 @@ package com.santaclose.app.mountainRestaurant.repository +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.santaclose.app.util.createAppUser import com.santaclose.app.util.createMountain import com.santaclose.app.util.createMountainRestaurant -import com.santaclose.app.util.createQueryFactory import com.santaclose.app.util.createRestaurant import io.kotest.assertions.arrow.core.shouldBeRight import io.kotest.matchers.collections.shouldBeSortedWith @@ -19,7 +19,7 @@ internal class MountainRestaurantAppQueryRepositoryImplTest @Autowired construct private val em: EntityManager, ) { private val mountainRestaurantAppQueryRepository = - MountainRestaurantAppQueryRepositoryImpl(em.createQueryFactory()) + MountainRestaurantAppQueryRepositoryImpl(em, JpqlRenderContext()) @Nested inner class FindMountainByRestaurant { diff --git a/server-app/src/test/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppQueryRepositoryImplTest.kt b/server-app/src/test/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppQueryRepositoryImplTest.kt index 2b03473e..b9897221 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppQueryRepositoryImplTest.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppQueryRepositoryImplTest.kt @@ -1,10 +1,10 @@ package com.santaclose.app.mountainReview.repository +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.santaclose.app.mountainReview.repository.dto.MountainRatingAverageDto import com.santaclose.app.util.createAppUser import com.santaclose.app.util.createMountain import com.santaclose.app.util.createMountainReview -import com.santaclose.app.util.createQueryFactory import com.santaclose.lib.entity.mountainReview.MountainRating import com.santaclose.lib.entity.mountainReview.MountainReview import com.santaclose.lib.entity.mountainReview.type.MountainDifficulty @@ -21,7 +21,7 @@ internal class MountainReviewAppQueryRepositoryImplTest @Autowired constructor( private val em: EntityManager, ) { private val mountainReviewAppQueryRepository = - MountainReviewAppQueryRepositoryImpl(em.createQueryFactory()) + MountainReviewAppQueryRepositoryImpl(em, JpqlRenderContext()) @Nested inner class FindMountainRatingAverages { diff --git a/server-app/src/test/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppRepositoryTest.kt b/server-app/src/test/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppRepositoryTest.kt index b8f4bbaf..5319a156 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppRepositoryTest.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/mountainReview/repository/MountainReviewAppRepositoryTest.kt @@ -1,9 +1,9 @@ package com.santaclose.app.mountainReview.repository +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.santaclose.app.util.createAppUser import com.santaclose.app.util.createMountain import com.santaclose.app.util.createMountainReview -import com.santaclose.app.util.createQueryFactory import com.santaclose.lib.entity.mountainReview.MountainRating import com.santaclose.lib.entity.mountainReview.MountainReview import com.santaclose.lib.entity.mountainReview.type.MountainDifficulty.EASY @@ -26,7 +26,7 @@ internal class MountainReviewAppRepositoryTest @Autowired constructor( private val em: EntityManager, ) { val mountainReviewAppQueryRepository = - MountainReviewAppQueryRepositoryImpl(em.createQueryFactory()) + MountainReviewAppQueryRepositoryImpl(em, JpqlRenderContext()) @Nested inner class Create { diff --git a/server-app/src/test/kotlin/com/santaclose/app/restaurant/repository/RestaurantAppQueryRepositoryImplTest.kt b/server-app/src/test/kotlin/com/santaclose/app/restaurant/repository/RestaurantAppQueryRepositoryImplTest.kt index 28472c67..14daae78 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/restaurant/repository/RestaurantAppQueryRepositoryImplTest.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/restaurant/repository/RestaurantAppQueryRepositoryImplTest.kt @@ -1,10 +1,10 @@ package com.santaclose.app.restaurant.repository +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.santaclose.app.util.createAppUser import com.santaclose.app.util.createLocation import com.santaclose.app.util.createMountain import com.santaclose.app.util.createMountainRestaurant -import com.santaclose.app.util.createQueryFactory import com.santaclose.app.util.createRestaurant import io.kotest.assertions.arrow.core.shouldBeRight import io.kotest.matchers.collections.shouldHaveSize @@ -20,7 +20,7 @@ internal class RestaurantAppQueryRepositoryImplTest @Autowired constructor( private val em: EntityManager, ) { private val restaurantAppQueryRepository = - RestaurantAppQueryRepositoryImpl(em.createQueryFactory()) + RestaurantAppQueryRepositoryImpl(em, JpqlRenderContext()) @Nested inner class FindLocationByMountain { diff --git a/server-app/src/test/kotlin/com/santaclose/app/restaurant/service/RestaurantAppQueryServiceTest.kt b/server-app/src/test/kotlin/com/santaclose/app/restaurant/service/RestaurantAppQueryServiceTest.kt index 663e011a..488aa998 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/restaurant/service/RestaurantAppQueryServiceTest.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/restaurant/service/RestaurantAppQueryServiceTest.kt @@ -1,5 +1,6 @@ package com.santaclose.app.restaurant.service +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.santaclose.app.mountain.repository.MountainAppQueryRepositoryImpl import com.santaclose.app.mountainRestaurant.repository.MountainRestaurantAppQueryRepositoryImpl import com.santaclose.app.restaurant.repository.RestaurantAppQueryRepositoryImpl @@ -8,7 +9,6 @@ import com.santaclose.app.restaurantReview.repository.RestaurantReviewAppQueryRe import com.santaclose.app.util.createAppUser import com.santaclose.app.util.createMountain import com.santaclose.app.util.createMountainRestaurant -import com.santaclose.app.util.createQueryFactory import com.santaclose.app.util.createRestaurant import com.santaclose.app.util.createRestaurantReview import io.kotest.assertions.arrow.core.shouldBeRight @@ -25,14 +25,15 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest internal class RestaurantAppQueryServiceTest @Autowired constructor( private val em: EntityManager, ) { + private val jpqlRenderContext = JpqlRenderContext() private val restaurantAppQueryRepository = - RestaurantAppQueryRepositoryImpl(em.createQueryFactory()) + RestaurantAppQueryRepositoryImpl(em, jpqlRenderContext) private val restaurantReviewAppQueryRepository = - RestaurantReviewAppQueryRepositoryImpl(em.createQueryFactory()) + RestaurantReviewAppQueryRepositoryImpl(em, jpqlRenderContext) private val mountainRestaurantAppQueryRepository = - MountainRestaurantAppQueryRepositoryImpl(em.createQueryFactory()) + MountainRestaurantAppQueryRepositoryImpl(em, jpqlRenderContext) private val mountainAppQueryRepository = - MountainAppQueryRepositoryImpl(em.createQueryFactory()) + MountainAppQueryRepositoryImpl(em, jpqlRenderContext) private val restaurantAppQueryService = RestaurantAppQueryService( diff --git a/server-app/src/test/kotlin/com/santaclose/app/restaurantReview/repository/RestaurantReviewAppQueryRepositoryImplTest.kt b/server-app/src/test/kotlin/com/santaclose/app/restaurantReview/repository/RestaurantReviewAppQueryRepositoryImplTest.kt index da5afddb..314690ce 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/restaurantReview/repository/RestaurantReviewAppQueryRepositoryImplTest.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/restaurantReview/repository/RestaurantReviewAppQueryRepositoryImplTest.kt @@ -1,7 +1,7 @@ package com.santaclose.app.restaurantReview.repository +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.santaclose.app.util.createAppUser -import com.santaclose.app.util.createQueryFactory import com.santaclose.app.util.createRestaurant import com.santaclose.app.util.createRestaurantReview import io.kotest.assertions.arrow.core.shouldBeRight @@ -19,7 +19,7 @@ internal class RestaurantReviewAppQueryRepositoryImplTest @Autowired constructor private val em: EntityManager, ) { private val restaurantReviewAppQueryRepository = - RestaurantReviewAppQueryRepositoryImpl(em.createQueryFactory()) + RestaurantReviewAppQueryRepositoryImpl(em, JpqlRenderContext()) @Nested inner class FindAllByRestaurant { diff --git a/server-app/src/test/kotlin/com/santaclose/app/sample/repository/SampleAppQueryRepositoryImplTest.kt b/server-app/src/test/kotlin/com/santaclose/app/sample/repository/SampleAppQueryRepositoryImplTest.kt index 8fa4efbb..577defa5 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/sample/repository/SampleAppQueryRepositoryImplTest.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/sample/repository/SampleAppQueryRepositoryImplTest.kt @@ -1,7 +1,7 @@ package com.santaclose.app.sample.repository +import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext import com.santaclose.app.sample.controller.dto.SampleAppDetail -import com.santaclose.app.util.createQueryFactory import com.santaclose.lib.entity.sample.Sample import com.santaclose.lib.entity.sample.type.SampleStatus import io.kotest.assertions.arrow.core.shouldBeRight @@ -18,7 +18,7 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest internal class SampleAppQueryRepositoryImplTest @Autowired constructor( private val em: EntityManager, ) { - private val sampleAppQueryRepository = SampleAppQueryRepositoryImpl(em.createQueryFactory()) + private val sampleAppQueryRepository = SampleAppQueryRepositoryImpl(em, JpqlRenderContext()) @Nested inner class FindByPrice { diff --git a/server-app/src/test/kotlin/com/santaclose/app/util/EntityManagerExtension.kt b/server-app/src/test/kotlin/com/santaclose/app/util/EntityManagerExtension.kt index 14e4133f..a813f63a 100644 --- a/server-app/src/test/kotlin/com/santaclose/app/util/EntityManagerExtension.kt +++ b/server-app/src/test/kotlin/com/santaclose/app/util/EntityManagerExtension.kt @@ -1,8 +1,5 @@ package com.santaclose.app.util -import com.linecorp.kotlinjdsl.query.creator.CriteriaQueryCreatorImpl -import com.linecorp.kotlinjdsl.query.creator.SubqueryCreatorImpl -import com.linecorp.kotlinjdsl.spring.data.SpringDataQueryFactoryImpl import com.santaclose.lib.entity.appUser.AppUser import com.santaclose.lib.entity.appUser.type.AppUserRole import com.santaclose.lib.entity.location.Location @@ -25,12 +22,6 @@ inline fun EntityManager.findAll(): List { return createQuery(query).resultList } -fun EntityManager.createQueryFactory() = - SpringDataQueryFactoryImpl( - criteriaQueryCreator = CriteriaQueryCreatorImpl(this), - subqueryCreator = SubqueryCreatorImpl(), - ) - fun EntityManager.createAppUser( user: AppUser = AppUser("name", "email", "socialId", AppUserRole.USER), ): AppUser = user.also { persist(it) }