Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
package com.valensas.util.autoconfigure

import com.valensas.util.config.PageableConfig
import com.valensas.util.pagination.Pageable
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Configuration

@Configuration
@RegisterReflectionForBinding(classes = [Pageable::class])
@EnableConfigurationProperties(PageableConfig::class)
class PaginationAutoConfiguration(
@Value("\${spring.data.rest.max-page-size:50}") private val maxPageSize: Int,
@Value("\${spring.data.rest.default-page-size:20}") private val defaultPageSize: Int
pageableConfig: PageableConfig
) {
init {
Companion.defaultPageSize = defaultPageSize
Companion.maxPageSize = maxPageSize
}

companion object {
var defaultPageSize = 20
var maxPageSize = 50
pageableConfig.defaultPageSize?.let {
Pageable.defaultPageSize = it
}
pageableConfig.maxPageSize?.let {
Pageable.maxPageSize = it
}
}
}
9 changes: 9 additions & 0 deletions src/main/kotlin/com/valensas/util/config/PageableConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.valensas.util.config

import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties(prefix = "spring.data.rest")
data class PageableConfig(
val defaultPageSize: Int?,
val maxPageSize: Int?
)
9 changes: 7 additions & 2 deletions src/main/kotlin/com/valensas/util/exception/Exceptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ package com.valensas.util.exception

import com.valensas.exception.BadRequest

class InvalidPageSize : BadRequest(
"Page size must not be less than one",
class InvalidPageSize(max: Int) : BadRequest(
"Page size must be between 0 and $max",
"INVALID_PAGE_SIZE"
)

class InvalidPageNumber : BadRequest(
"Page number must not be less than zero",
"INVALID_PAGE_NUMBER"
)

class InvalidSortDirection(direction: String) : BadRequest(
"Invalid value:$direction, has to be either 'desc' or 'asc' (case insensitive)",
"INVALID_SORT_DIRECTION"
Expand Down
34 changes: 21 additions & 13 deletions src/main/kotlin/com/valensas/util/pagination/Pageable.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.valensas.util.pagination

import com.valensas.util.autoconfigure.PaginationAutoConfiguration
import com.valensas.util.exception.InvalidPageNumber
import com.valensas.util.exception.InvalidPageSize
import com.valensas.util.exception.InvalidSortDirection
import org.springframework.data.domain.PageRequest
Expand All @@ -9,27 +9,35 @@ import org.springframework.util.StringUtils
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.util.UriBuilder
import java.io.Serializable
import kotlin.math.min

class Pageable(
@RequestParam(required = false) val page: Int?,
@RequestParam(required = false) val size: Int?,
@RequestParam(required = false) var page: Int?,
@RequestParam(required = false) var size: Int?,
@RequestParam(required = false) val sort: String?
) : Serializable
) : Serializable {
companion object {
var defaultPageSize = 20
var maxPageSize = 1000
}

init {
size = size ?: defaultPageSize
size?.let {
if (it < 0) throw InvalidPageSize(maxPageSize)
if (it > maxPageSize) throw InvalidPageSize(maxPageSize)
}
page = page ?: 0

page?.let { if (it < 0) throw InvalidPageNumber() }
}
}

fun Pageable.toJavaPageable(): PageRequest {
val sortParam = parseParameterIntoSort(sort)
val pageParam = this.page ?: 0
val sizeParam = calculateSize(this.size)
return PageRequest.of(pageParam, sizeParam, sortParam)
return PageRequest.of(pageParam, this.size ?: Pageable.defaultPageSize, sortParam)
}

private fun calculateSize(size: Int?) =
size
.run { this ?: PaginationAutoConfiguration.defaultPageSize }
.also { if (it < 1) throw InvalidPageSize() }
.let { min(PaginationAutoConfiguration.maxPageSize, it) }

private fun parseParameterIntoSort(sort: String?): Sort {
return sort?.replace(" ", "")
?.split(";")
Expand Down
36 changes: 21 additions & 15 deletions src/test/kotlin/com/valensas/util/PageableTest.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.valensas.util

import com.valensas.util.autoconfigure.PaginationAutoConfiguration
import com.valensas.util.exception.InvalidPageNumber
import com.valensas.util.exception.InvalidPageSize
import com.valensas.util.exception.InvalidSortDirection
import com.valensas.util.pagination.Pageable
import com.valensas.util.pagination.toJavaPageable
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.assertThrows
Expand All @@ -19,31 +20,36 @@ class PageableTest {
val pageable =
Pageable(null, null, null)
val page = pageable.toJavaPageable()
Assertions.assertNotNull(page)
Assertions.assertEquals(Sort.unsorted(), page.sort)
Assertions.assertEquals(0, page.pageNumber)
Assertions.assertEquals(PaginationAutoConfiguration.defaultPageSize, page.pageSize)
assertNotNull(page)
assertEquals(Sort.unsorted(), page.sort)
assertEquals(0, page.pageNumber)
assertEquals(Pageable.defaultPageSize, page.pageSize)
}

@Test
fun `initiate pageable with correct values`() {
val pageable =
Pageable(1, 5, "created_date,desc")
val page = pageable.toJavaPageable()
Assertions.assertNotNull(page)
Assertions.assertNotNull(page.sort)
Assertions.assertNotNull(page.sort.getOrderFor("created_date"))
Assertions.assertEquals(Sort.Direction.DESC, page.sort.getOrderFor("created_date")!!.direction)
Assertions.assertEquals(1, page.pageNumber)
Assertions.assertEquals(min(pageable.size!!, PaginationAutoConfiguration.defaultPageSize), page.pageSize)
assertNotNull(page)
assertNotNull(page.sort)
assertNotNull(page.sort.getOrderFor("created_date"))
assertEquals(Sort.Direction.DESC, page.sort.getOrderFor("created_date")!!.direction)
assertEquals(1, page.pageNumber)
assertEquals(min(pageable.size!!, Pageable.defaultPageSize), page.pageSize)
}

@Test
fun `try to initiate javaPageable with invalid size`() {
val pageable =
Pageable(null, 0, null)
assertThrows<InvalidPageSize> {
pageable.toJavaPageable()
Pageable(null, -1, null)
}
}

@Test
fun `try to initiate javaPageable with invalid page number`() {
assertThrows<InvalidPageNumber> {
Pageable(-1, null, null)
}
}

Expand Down
Loading