-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feature] JOOQ 기반 카테고리 가게 커서 조회 (#28)
- Loading branch information
Showing
18 changed files
with
581 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
src/main/kotlin/com/mjucow/eatda/common/config/JooqContextConfiguration.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.mjucow.eatda.common.config | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import jakarta.persistence.Entity | ||
import org.jooq.Record | ||
import org.jooq.RecordMapper | ||
import org.jooq.RecordMapperProvider | ||
import org.jooq.RecordType | ||
import org.jooq.SQLDialect | ||
import org.jooq.conf.RenderNameCase | ||
import org.jooq.impl.DataSourceConnectionProvider | ||
import org.jooq.impl.DefaultConfiguration | ||
import org.jooq.impl.DefaultDSLContext | ||
import org.jooq.impl.DefaultExecuteListenerProvider | ||
import org.jooq.impl.DefaultRecordMapper | ||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration | ||
import org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration | ||
import org.springframework.context.annotation.Bean | ||
import org.springframework.context.annotation.Configuration | ||
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy | ||
import org.springframework.transaction.annotation.EnableTransactionManagement | ||
import javax.sql.DataSource | ||
|
||
@Configuration | ||
@EnableTransactionManagement | ||
@ImportAutoConfiguration(JooqAutoConfiguration::class) | ||
class JooqContextConfiguration( | ||
private val dataSource: DataSource, | ||
private val objectMapper: ObjectMapper, | ||
) { | ||
|
||
@Bean | ||
fun connectionProvider() = DataSourceConnectionProvider(TransactionAwareDataSourceProxy(dataSource)) | ||
|
||
@Bean | ||
fun dsl() = DefaultDSLContext(configuration()) | ||
|
||
fun configuration(): DefaultConfiguration { | ||
val jooqConfiguration = DefaultConfiguration() | ||
|
||
val settings = jooqConfiguration.settings() | ||
.withExecuteWithOptimisticLocking(true) | ||
.withExecuteLogging(true) | ||
.withMapConstructorParameterNamesInKotlin(true) | ||
.withRenderNameCase(RenderNameCase.LOWER) | ||
|
||
jooqConfiguration.set(settings) | ||
jooqConfiguration.set(connectionProvider()) | ||
jooqConfiguration.set(DefaultExecuteListenerProvider(jooqToSpringExceptionTransformer())) | ||
jooqConfiguration.setSQLDialect(SQLDialect.POSTGRES) | ||
jooqConfiguration.setRecordMapperProvider(object : RecordMapperProvider { | ||
override fun <R : Record?, E : Any?> provide( | ||
recordType: RecordType<R>?, | ||
type: Class<out E>?, | ||
): RecordMapper<R, E> { | ||
if (type?.annotations?.any { it.annotationClass == Entity::class } == true) { | ||
return getEntityRecordMapper(type) | ||
} | ||
|
||
return DefaultRecordMapper(recordType, type) | ||
} | ||
}) | ||
|
||
return jooqConfiguration | ||
} | ||
|
||
@Bean | ||
fun jooqToSpringExceptionTransformer() = JooqToSpringExceptionTransformer() | ||
|
||
/** | ||
* JPA Entity의 Secondary Constrcutor로 DefaultRecordMapper가 Mapping되지 않아 | ||
* CustomerRecordMapper로 mapping 해야함. 클래스별로 따로 만들지 않고 map으로 변환 후 objectMapper로 mapping 처리 | ||
*/ | ||
private fun <R : Record?, E : Any?> getEntityRecordMapper(type: Class<out E>): RecordMapper<R, E> { | ||
return RecordMapper<R, E> { objectMapper.convertValue(it!!.intoMap(), type) } | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/kotlin/com/mjucow/eatda/common/config/JooqToSpringExceptionTransformer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.mjucow.eatda.common.config | ||
|
||
import org.jooq.ExecuteContext | ||
import org.jooq.ExecuteListener | ||
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator | ||
|
||
class JooqToSpringExceptionTransformer : ExecuteListener { | ||
override fun exception(ctx: ExecuteContext) { | ||
if (ctx.sqlException() == null) return | ||
|
||
val dialect = ctx.configuration().dialect() | ||
val translator = SQLErrorCodeSQLExceptionTranslator(dialect.name) | ||
|
||
ctx.exception(translator.translate("jOOQ", ctx.sql(), ctx.sqlException()!!)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/main/kotlin/com/mjucow/eatda/persistence/store/StoreCustomRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.mjucow.eatda.persistence.store | ||
|
||
import com.mjucow.eatda.domain.store.entity.Store | ||
import org.springframework.data.domain.Pageable | ||
import org.springframework.data.domain.Slice | ||
|
||
interface StoreCustomRepository { | ||
fun findIdsByCategoryIdOrderByIdDesc(categoryId: Long, page: Pageable, id: Long? = null): Slice<Long> | ||
fun findAllByIdLessThanOrderByIdDesc(page: Pageable, id: Long? = null): Slice<Store> | ||
} |
55 changes: 55 additions & 0 deletions
55
src/main/kotlin/com/mjucow/eatda/persistence/store/StoreCustomRepositoryImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package com.mjucow.eatda.persistence.store | ||
|
||
import com.mjucow.eatda.domain.store.entity.Store | ||
import com.mjucow.eatda.jooq.Tables.STORE | ||
import com.mjucow.eatda.jooq.Tables.STORE_CATEGORY | ||
import org.jooq.DSLContext | ||
import org.springframework.data.domain.Pageable | ||
import org.springframework.data.domain.Slice | ||
import org.springframework.data.domain.SliceImpl | ||
import org.springframework.stereotype.Repository | ||
import kotlin.math.min | ||
|
||
@Repository | ||
class StoreCustomRepositoryImpl( | ||
private val db: DSLContext, | ||
) : StoreCustomRepository { | ||
override fun findIdsByCategoryIdOrderByIdDesc(categoryId: Long, page: Pageable, id: Long?): Slice<Long> { | ||
val query = db.select(STORE_CATEGORY.STORE_ID) | ||
.from(STORE_CATEGORY) | ||
.where(STORE_CATEGORY.CATEGORY_ID.eq(categoryId)) | ||
|
||
if (id != null) { | ||
query.and(STORE_CATEGORY.STORE_ID.lessThan(id)) | ||
} | ||
|
||
val result = query.orderBy(STORE_CATEGORY.STORE_ID.desc()) | ||
.limit(page.pageSize + 1) | ||
.fetch() | ||
.into(Long::class.java) | ||
|
||
val content = result.subList(0, min(result.size, page.pageSize)) | ||
val hasNext = result.size > page.pageSize | ||
|
||
return SliceImpl(content, page, hasNext) | ||
} | ||
|
||
override fun findAllByIdLessThanOrderByIdDesc(page: Pageable, id: Long?): Slice<Store> { | ||
val query = db.select() | ||
.from(STORE) | ||
|
||
if (id != null) { | ||
query.where(STORE.ID.lessThan(id)) | ||
} | ||
|
||
val result = query.orderBy(STORE.ID.desc()) | ||
.limit(page.pageSize + 1) | ||
.fetch() | ||
.into(Store::class.java) | ||
|
||
val content = result.subList(0, min(result.size, page.pageSize)) | ||
val hasNext = result.size > page.pageSize | ||
|
||
return SliceImpl(content, page, hasNext) | ||
} | ||
} |
7 changes: 2 additions & 5 deletions
7
src/main/kotlin/com/mjucow/eatda/persistence/store/StoreRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,9 @@ | ||
package com.mjucow.eatda.persistence.store | ||
|
||
import com.mjucow.eatda.domain.store.entity.Store | ||
import org.springframework.data.domain.Pageable | ||
import org.springframework.data.domain.Slice | ||
import org.springframework.data.jpa.repository.JpaRepository | ||
|
||
interface StoreRepository : JpaRepository<Store, Long> { | ||
fun findAllByOrderByIdDesc(page: Pageable): Slice<Store> | ||
fun findByIdLessThanOrderByIdDesc(id: Long, page: Pageable): Slice<Store> | ||
interface StoreRepository : JpaRepository<Store, Long>, StoreCustomRepository { | ||
fun existsByName(name: String): Boolean | ||
fun findAllByIdInOrderByIdDesc(id: List<Long>): List<Store> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
src/main/resources/db/changelog/231006-add_store_cateogry_index.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
CREATE UNIQUE INDEX idx_store_category_category_id_store_id ON store_category(category_id, store_id); |
Oops, something went wrong.