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 a3fd510198c..0bd7a87ace3 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 @@ -50,3 +50,8 @@ fun calculatePagesNumber(datasetSize: Int, pageSize: Int): Int = datasetSize.toLong(), pageSize ) + +/** + * @return calculated page number which can be correctly used in [PaginationResult] as [PaginationResult.page] value + */ +fun calculatePage(firstIndex: Int, resultsSize: Int): Int = firstIndex / resultsSize diff --git a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/PaginationResult.kt b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/PaginationResult.kt index ebca7b51ef8..608f0aaf750 100644 --- a/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/PaginationResult.kt +++ b/pagination/common/src/commonMain/kotlin/dev/inmo/micro_utils/pagination/PaginationResult.kt @@ -23,6 +23,19 @@ fun List.createPaginationResult( pagination.size ) +fun List.createPaginationResult( + firstIndex: Int, + commonObjectsNumber: Long +) = PaginationResult( + calculatePage(firstIndex, size), + calculatePagesNumber( + commonObjectsNumber, + size + ), + this, + size +) + fun Pair>.createPaginationResult( pagination: Pagination ) = second.createPaginationResult(pagination, first) diff --git a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartCRUDRepo.kt b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartCRUDRepo.kt index c8c193c5f29..28ad1ac34c7 100644 --- a/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartCRUDRepo.kt +++ b/repos/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/StandartCRUDRepo.kt @@ -8,6 +8,7 @@ interface ReadStandardCRUDRepo : Repo { suspend fun getByPagination(pagination: Pagination): PaginationResult suspend fun getById(id: IdType): ObjectType? suspend fun contains(id: IdType): Boolean + suspend fun count(): Long } typealias UpdatedValuePair = Pair diff --git a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/AbstractExposedReadCRUDRepo.kt b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/AbstractExposedReadCRUDRepo.kt index af9e7c268e4..916e0a80512 100644 --- a/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/AbstractExposedReadCRUDRepo.kt +++ b/repos/exposed/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/exposed/AbstractExposedReadCRUDRepo.kt @@ -33,4 +33,6 @@ abstract class AbstractExposedReadCRUDRepo( override suspend fun contains(id: IdType): Boolean = transaction(db = database) { select { selectById(id) }.limit(1).any() } + + override suspend fun count(): Long = transaction(db = database) { selectAll().count() } } diff --git a/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapCRUDRepo.kt b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapCRUDRepo.kt index fcd14d7e3f4..96bbbfa18b2 100644 --- a/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapCRUDRepo.kt +++ b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapCRUDRepo.kt @@ -12,13 +12,15 @@ class ReadMapCRUDRepo( map[it] }.createPaginationResult( pagination, - map.size.toLong() + count() ) } override suspend fun getById(id: IdType): ObjectType? = map[id] override suspend fun contains(id: IdType): Boolean = map.containsKey(id) + + override suspend fun count(): Long = map.size.toLong() } abstract class WriteMapCRUDRepo( 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 new file mode 100644 index 00000000000..ef86cf9ec7a --- /dev/null +++ b/repos/inmemory/src/commonMain/kotlin/dev/inmo/micro_utils/repos/MapKeyValueRepo.kt @@ -0,0 +1,74 @@ +package dev.inmo.micro_utils.repos + +import dev.inmo.micro_utils.coroutines.BroadcastFlow +import dev.inmo.micro_utils.pagination.* +import kotlinx.coroutines.flow.Flow + +class ReadMapKeyValueRepo( + private val map: Map = emptyMap() +) : StandardReadKeyValueRepo { + override suspend fun get(k: Key): Value? = map[k] + + override suspend fun values( + 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 + } + + 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 + } + + return map.keys.drop(firstIndex).take(pagination.size).createPaginationResult( + firstIndex, + count() + ) + } + + override suspend fun contains(key: Key): Boolean = map.containsKey(key) + + override suspend fun count(): Long = map.size.toLong() +} + +class WriteMapKeyValueRepo( + private val map: MutableMap = mutableMapOf() +) : StandardWriteKeyValueRepo { + private val _onNewValue: BroadcastFlow> = BroadcastFlow() + override val onNewValue: Flow> + get() = _onNewValue + private val _onValueRemoved: BroadcastFlow = BroadcastFlow() + override val onValueRemoved: Flow + get() = _onValueRemoved + + override suspend fun set(k: Key, v: Value) { + map[k] = v + _onNewValue.send(k to v) + } + + override suspend fun unset(k: Key) { + map.remove(k) ?.also { _onValueRemoved.send(k) } + } +} + +class MapKeyValueRepo( + private val map: MutableMap = mutableMapOf() +) : StandardKeyValueRepo, + StandardReadKeyValueRepo by ReadMapKeyValueRepo(map), + StandardWriteKeyValueRepo by WriteMapKeyValueRepo(map) + +fun MutableMap.asKeyValueRepo(): StandardKeyValueRepo = MapKeyValueRepo(this) diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt index 082e72a83fb..1a3d3a2bf67 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt @@ -47,4 +47,12 @@ class KtorReadStandardCrudRepo ( ), Boolean.serializer() ) + + override suspend fun count(): Long = client.uniget( + buildStandardUrl( + baseUrl, + countRouting + ), + Long.serializer() + ) } diff --git a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/crud/CrudReadRoutes.kt b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/crud/CrudReadRoutes.kt index dc44163c26e..00348cc409d 100644 --- a/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/crud/CrudReadRoutes.kt +++ b/repos/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/common/crud/CrudReadRoutes.kt @@ -3,3 +3,4 @@ package dev.inmo.micro_utils.repos.ktor.common.crud const val getByPaginationRouting = "getByPagination" const val getByIdRouting = "getById" const val containsRouting = "contains" +const val countRouting = "count" diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt index d876840b033..c270f8e47b9 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt @@ -2,12 +2,10 @@ package dev.inmo.micro_utils.repos.ktor.server.crud import dev.inmo.micro_utils.ktor.server.decodeUrlQueryValueOrSendError import dev.inmo.micro_utils.ktor.server.unianswer -import dev.inmo.micro_utils.repos.ktor.common.crud.containsRouting -import dev.inmo.micro_utils.repos.ktor.common.crud.getByIdRouting -import dev.inmo.micro_utils.repos.ktor.common.crud.getByPaginationRouting import dev.inmo.micro_utils.pagination.PaginationResult import dev.inmo.micro_utils.pagination.extractPagination import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo +import dev.inmo.micro_utils.repos.ktor.common.crud.* import io.ktor.application.call import io.ktor.routing.Route import io.ktor.routing.get @@ -54,4 +52,11 @@ fun Route.configureReadStandardCrudRepoRoutes( originalRepo.contains(id) ) } + + get(countRouting) { + call.unianswer( + Long.serializer(), + originalRepo.count() + ) + } }