diff --git a/CHANGELOG.md b/CHANGELOG.md index c143cf1c1db..dfc58b0982d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.2.1 + +* `Pagination` + * `Common`: + * Extension `Pagination#reverse` has been added + * Factory `PaginationByIndexes` + * Shortcut `calculatePagesNumber` with reversed parameters + ## 0.2.0 * `Repos` diff --git a/gradle.properties b/gradle.properties index 56b84d298cd..03f3e2ae9bb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,4 +19,4 @@ github_release_plugin_version=2.2.12 uuidVersion=0.2.2 group=dev.inmo -version=0.2.0 +version=0.2.1 diff --git a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/Pagination.kt b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/Pagination.kt index 53d8958dc42..2ea52f141ae 100644 --- a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/Pagination.kt +++ b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/Pagination.kt @@ -43,6 +43,11 @@ val Pagination.lastIndex: Int fun calculatePagesNumber(datasetSize: Long, pageSize: Int): Int { return ceil(datasetSize.toDouble() / pageSize).toInt() } +/** + * Calculates pages count for given [datasetSize]. As a fact, it is shortcut for [calculatePagesNumber] + * @return calculated page number which can be correctly used in [PaginationResult] as [PaginationResult.page] value + */ +fun calculatePagesNumber(pageSize: Int, datasetSize: Long): Int = calculatePagesNumber(datasetSize, pageSize) /** * Calculates pages count for given [datasetSize] */ diff --git a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/SimplePagination.kt b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/SimplePagination.kt index 900bf745794..f3ca4e1e8db 100644 --- a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/SimplePagination.kt +++ b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/SimplePagination.kt @@ -27,7 +27,21 @@ data class SimplePagination( override val size: Int ) : Pagination +/** + * Factory for [SimplePagination] + */ fun Pagination( page: Int, size: Int ) = SimplePagination(page, size) + +/** + * @param firstIndex Inclusive first index of pagination + * @param lastIndex INCLUSIVE last index of pagination (last index of object covered by result [SimplePagination]) + */ +fun PaginationByIndexes( + firstIndex: Int, + lastIndex: Int +) = maxOf(0, (lastIndex - firstIndex + 1)).let { size -> + Pagination(calculatePage(firstIndex, size), size) +} diff --git a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/utils/PaginationReversing.kt b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/utils/PaginationReversing.kt new file mode 100644 index 00000000000..678b7976bc6 --- /dev/null +++ b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/utils/PaginationReversing.kt @@ -0,0 +1,34 @@ +package dev.inmo.micro_utils.pagination.utils + +import dev.inmo.micro_utils.pagination.* + +/** + * Example: + * + * * `|__f__l_______________________|` will be transformed to `|_______________________f__l__|` + * * `|__f__l_|` will be transformed to `|__f__l_|` + * + * @return Reversed version of this [Pagination] + */ +fun Pagination.reverse(objectsCount: Long): SimplePagination { + val firstIndex = (objectsCount - (this.lastIndex + 1)).let { + when { + it < 0 -> it + it > objectsCount -> objectsCount + else -> it + } + }.toInt() + val lastIndex = (objectsCount - (this.firstIndex + 1)).let { + when { + it < 0 -> it + it > objectsCount -> objectsCount + else -> it + } + }.toInt() + return PaginationByIndexes(firstIndex, lastIndex) +} + +/** + * Shortcut for [reverse] + */ +fun Pagination.reverse(objectsCount: Int) = reverse(objectsCount.toLong()) diff --git a/pagination/common/src/commonTest/kotlin/dev/inmo/micro_utils/pagination/utils/PaginationReversing.kt b/pagination/common/src/commonTest/kotlin/dev/inmo/micro_utils/pagination/utils/PaginationReversing.kt new file mode 100644 index 00000000000..4ba6b148b3a --- /dev/null +++ b/pagination/common/src/commonTest/kotlin/dev/inmo/micro_utils/pagination/utils/PaginationReversing.kt @@ -0,0 +1,24 @@ +package dev.inmo.micro_utils.pagination.utils + +import dev.inmo.micro_utils.pagination.* +import kotlin.test.Test +import kotlin.test.assertEquals + +class PaginationReversingTests { + @Test + fun testThatCommonCaseWorksOk() { + val pageSize = 2 + val collectionSize = 8 + val pages = calculatePage(collectionSize, pageSize) + + doWithPagination(FirstPagePagination(pageSize)) { + val reversed = it.reverse(collectionSize.toLong()) + assertEquals(Pagination(calculatePage(collectionSize - it.firstIndex - it.size, it.size), it.size), reversed) + if (it.page < pages) { + it.nextPage() + } else { + null + } + } + } +} diff --git a/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapKeyValueRepo.kt b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapKeyValueRepo.kt index 506033e6c70..dcdec6ca564 100644 --- a/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapKeyValueRepo.kt +++ b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapKeyValueRepo.kt @@ -2,6 +2,8 @@ package dev.inmo.micro_utils.repos import dev.inmo.micro_utils.coroutines.BroadcastFlow import dev.inmo.micro_utils.pagination.* +import dev.inmo.micro_utils.pagination.utils.paginate +import dev.inmo.micro_utils.pagination.utils.reverse import kotlinx.coroutines.flow.Flow class ReadMapKeyValueRepo( @@ -13,31 +15,27 @@ class ReadMapKeyValueRepo( pagination: Pagination, reversed: Boolean ): PaginationResult { - val firstIndex: Int = if (reversed) { - val size = map.size - (size - pagination.lastIndex).let { if (it < 0) 0 else it } - } else { - pagination.firstIndex + val values = map.values + val actualPagination = if (reversed) pagination.reverse(values.size) else pagination + return values.paginate(actualPagination).let { + if (reversed) { + it.copy(results = it.results.reversed()) + } else { + it + } } - - return map.keys.drop(firstIndex).take(pagination.size).mapNotNull { map[it] }.createPaginationResult( - firstIndex, - count() - ) } override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult { - val firstIndex: Int = if (reversed) { - val size = map.size - (size - pagination.lastIndex).let { if (it < 0) 0 else it } - } else { - pagination.firstIndex + val keys = map.keys + val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination + return keys.paginate(actualPagination).let { + if (reversed) { + it.copy(results = it.results.reversed()) + } else { + it + } } - - return map.keys.drop(firstIndex).take(pagination.size).createPaginationResult( - firstIndex, - count() - ) } override suspend fun contains(key: Key): Boolean = map.containsKey(key) diff --git a/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapOneToManyKeyValueRepo.kt b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapOneToManyKeyValueRepo.kt index 266f98c3baa..47cdb32b4a5 100644 --- a/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapOneToManyKeyValueRepo.kt +++ b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapOneToManyKeyValueRepo.kt @@ -3,6 +3,7 @@ package dev.inmo.micro_utils.repos import dev.inmo.micro_utils.coroutines.BroadcastFlow import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.pagination.utils.paginate +import dev.inmo.micro_utils.pagination.utils.reverse import kotlinx.coroutines.flow.Flow class MapReadOneToManyKeyValueRepo( @@ -13,8 +14,7 @@ class MapReadOneToManyKeyValueRepo( return list.paginate( if (reversed) { - val firstIndex = (map.size - pagination.lastIndex).let { if (it < 0) 0 else it } - SimplePagination(firstIndex, pagination.size) + pagination.reverse(list.size) } else { pagination } @@ -22,17 +22,15 @@ class MapReadOneToManyKeyValueRepo( } override suspend fun keys(pagination: Pagination, reversed: Boolean): PaginationResult { - val firstIndex: Int = if (reversed) { - val size = map.size - (size - pagination.lastIndex).let { if (it < 0) 0 else it } - } else { - pagination.firstIndex + val keys = map.keys + val actualPagination = if (reversed) pagination.reverse(keys.size) else pagination + return keys.paginate(actualPagination).let { + if (reversed) { + it.copy(results = it.results.reversed()) + } else { + it + } } - - return map.keys.drop(firstIndex).take(pagination.size).createPaginationResult( - firstIndex, - count() - ) } override suspend fun contains(k: Key): Boolean = map.containsKey(k)