init with pagination

This commit is contained in:
2020-09-15 18:57:41 +06:00
parent 97a83250f4
commit c6d0b0920e
22 changed files with 737 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply from: "$mppProjectWithSerializationPresetPath"

View File

@@ -0,0 +1,52 @@
package dev.inmo.micro_utils.pagination
import kotlin.math.ceil
/**
* Base interface of pagination
*
* If you want to request something, you should use [SimplePagination]. If you need to return some result including
* pagination - [PaginationResult]
*/
interface Pagination {
/**
* Started with 0.
* Number of page inside of pagination. Offset can be calculated as [page] * [size]
*/
val page: Int
/**
* Can be 0, but can't be < 0
* Size of current page. Offset can be calculated as [page] * [size]
*/
val size: Int
}
/**
* First number in index of objects. It can be used as offset for databases or other data sources
*/
val Pagination.firstIndex: Int
get() = page * size
/**
* Last number in index of objects. In fact, one [Pagination] object represent data in next range:
*
* [[firstIndex], [lastIndex]]; That means, that for [Pagination] with [Pagination.size] == 10 and [Pagination.page] == 1
* you will retrieve [Pagination.firstIndex] == 10 and [Pagination.lastIndex] == 19.
*/
val Pagination.lastIndex: Int
get() = firstIndex + size - 1
/**
* Calculates pages count for given [datasetSize]
*/
fun calculatePagesNumber(datasetSize: Long, pageSize: Int): Int {
return ceil(datasetSize.toDouble() / pageSize).toInt()
}
/**
* Calculates pages count for given [datasetSize]
*/
fun calculatePagesNumber(datasetSize: Int, pageSize: Int): Int =
calculatePagesNumber(
datasetSize.toLong(),
pageSize
)

View File

@@ -0,0 +1,28 @@
package dev.inmo.micro_utils.pagination
import kotlinx.serialization.Serializable
@Serializable
data class PaginationResult<T>(
override val page: Int,
val pagesNumber: Int,
val results: List<T>,
override val size: Int
) : Pagination
fun <T> List<T>.createPaginationResult(
pagination: Pagination,
commonObjectsNumber: Long
) = PaginationResult(
pagination.page,
calculatePagesNumber(
commonObjectsNumber,
pagination.size
),
this,
pagination.size
)
fun <T> Pair<Long, List<T>>.createPaginationResult(
pagination: Pagination
) = second.createPaginationResult(pagination, first)

View File

@@ -0,0 +1,33 @@
package dev.inmo.micro_utils.pagination
import kotlinx.serialization.Serializable
const val defaultSmallPageSize = 2
const val defaultMediumPageSize = 5
const val defaultLargePageSize = 10
const val defaultExtraLargePageSize = 15
@Suppress("NOTHING_TO_INLINE", "FunctionName")
inline fun FirstPagePagination(size: Int = defaultMediumPageSize) =
SimplePagination(
page = 0,
size = size
)
@Suppress("NOTHING_TO_INLINE")
inline fun Pagination.nextPage() =
SimplePagination(
page + 1,
size
)
@Serializable
data class SimplePagination(
override val page: Int,
override val size: Int
) : Pagination
fun Pagination(
page: Int,
size: Int
) = SimplePagination(page, size)

View File

@@ -0,0 +1,28 @@
package dev.inmo.micro_utils.pagination
inline fun doWithPagination(
startPagination: Pagination = FirstPagePagination(),
requestMaker: (pagination: Pagination) -> Pagination?
) = requestMaker(startPagination).let {
var pagination = it
while (pagination != null) {
pagination = requestMaker(pagination)
}
}
@Suppress("NOTHING_TO_INLINE")
inline fun PaginationResult<*>.nextPageIfNotEmpty() = if (results.isNotEmpty()) {
SimplePagination(
page + 1,
size
)
} else {
null
}
@Suppress("NOTHING_TO_INLINE")
inline fun PaginationResult<*>.thisPageIfNotEmpty(): Pagination? = if (results.isNotEmpty()) {
this
} else {
null
}

View File

@@ -0,0 +1,16 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply from: "$mppJavaProjectPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api internalProject("micro_utils.pagination.common")
}
}
}
}

View File

@@ -0,0 +1,27 @@
package dev.inmo.micro_utils.pagination
import org.jetbrains.exposed.sql.*
fun Query.paginate(with: Pagination, orderBy: Pair<Expression<*>, SortOrder>? = null) = limit(
with.size,
(if (orderBy ?.second == SortOrder.DESC) {
with.lastIndex
} else {
with.firstIndex
}).toLong()
).let {
if (orderBy != null) {
it.orderBy(
orderBy.first,
orderBy.second
)
} else {
it
}
}
fun Query.paginate(with: Pagination, orderBy: Expression<*>?, reversed: Boolean = false) = paginate(
with,
orderBy ?.let { it to if (reversed) SortOrder.DESC else SortOrder.ASC }
)

View File

@@ -0,0 +1,16 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply from: "$mppProjectWithSerializationPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api internalProject("micro_utils.pagination.common")
}
}
}
}

View File

@@ -0,0 +1,23 @@
package dev.inmo.micro_utils.pagination
const val paginationPageKey = "ppage"
const val paginationSizeKey = "psize"
val Pagination.asUrlQueryParts
get() = mapOf(
paginationPageKey to page.toString(),
paginationSizeKey to size.toString()
)
val Pagination.asUrlQueryArrayParts
get() = arrayOf(
paginationPageKey to page.toString(),
paginationSizeKey to size.toString()
)
val Map<String, String?>.extractPagination: Pagination
get() = SimplePagination(
get(paginationPageKey) ?.toIntOrNull() ?: 0,
get(paginationSizeKey) ?.toIntOrNull() ?: defaultMediumPageSize
)

View File

@@ -0,0 +1,23 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply from: "$mppJavaProjectPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api internalProject("micro_utils.pagination.ktor.common")
}
}
jvmMain {
dependencies {
api "io.ktor:ktor-server:$ktor_version"
api "io.ktor:ktor-server-host-common:$ktor_version"
}
}
}
}

View File

@@ -0,0 +1,14 @@
package dev.inmo.micro_utils.pagination
import io.ktor.application.ApplicationCall
import io.ktor.http.Parameters
val Parameters.extractPagination: Pagination
get() = SimplePagination(
get("page") ?.toIntOrNull() ?: 0,
get("size") ?.toIntOrNull() ?: defaultMediumPageSize
)
val ApplicationCall.extractPagination: Pagination
get() = request.queryParameters.extractPagination