Compare commits

..

11 Commits

6 changed files with 174 additions and 71 deletions

View File

@@ -1,5 +1,17 @@
# Changelog
## 0.13.2
* `Versions`:
* `Klock`: `3.1.0` -> `3.3.0`
* `Ktor`: `2.1.2` -> `2.1.3`
## 0.13.1
* `Repos`:
* `Exposed`:
* `AbstractExposedWriteCRUDRepo#createAndInsertId` now is optional and returns nullable value
## 0.13.0
**ALL DEPRECATIONS HAVE BEEN REMOVED**

View File

@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
# Project data
group=dev.inmo
version=0.13.0
android_code_version=158
version=0.13.2
android_code_version=160

View File

@@ -1,17 +1,17 @@
[versions]
kt = "1.7.10"
kt-serialization = "1.4.0"
kt-serialization = "1.4.1"
kt-coroutines = "1.6.4"
jb-compose = "1.2.0-beta02"
jb-compose = "1.2.0"
jb-exposed = "0.39.2"
jb-dokka = "1.7.10"
klock = "3.1.0"
klock = "3.3.0"
uuid = "0.5.0"
ktor = "2.1.2"
ktor = "2.1.3"
gh-release = "2.4.1"

View File

@@ -0,0 +1,138 @@
package dev.inmo.micro_utils.repos
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.doAllWithCurrentPaging
import kotlinx.coroutines.flow.Flow
/**
* Read part of [KeyValueRepo]
*
* @param Key This type will be used as key in all operations related to searches of data
* @param Value This type will be used as returning data in most "get" operations
*/
interface ReadKeyValueRepo<Key, Value> : Repo {
/**
* @return Result [Value] in case when it is presented in repo by its [k] or null otherwise
*/
suspend fun get(k: Key): Value?
/**
* This method should use sorted by [Key]s search and take the [PaginationResult]. By default, it should use
* ascending sort for [Key]s
*/
suspend fun values(pagination: Pagination, reversed: Boolean = false): PaginationResult<Value>
/**
* This method should use sorted by [Key]s search and take the [PaginationResult]. By default, it should use
* ascending sort for [Key]s
*/
suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
/**
* This method should use sorted by [Key]s search and take the [PaginationResult]. By default, it should use
* ascending sort for [Key]s
*
* @param v This value should be used to exclude from search the items with different [Value]s
*/
suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
/**
* @return true if [key] is presented in current collection or false otherwise
*/
suspend fun contains(key: Key): Boolean
/**
* @return count of all collection objects
*/
suspend fun count(): Long
}
typealias ReadStandardKeyValueRepo<Key,Value> = ReadKeyValueRepo<Key, Value>
/**
* Write part of [KeyValueRepo]
*
* @param Key This type will be used as key in all operations related to changes of data
* @param Value This type will be used as incoming data in most operations
*/
interface WriteKeyValueRepo<Key, Value> : Repo {
/**
* This flow must emit data each time when data by [Key] has been changed with [set] method or in any other way
* excluding cases of data removing
*
* @see onValueRemoved
*/
val onNewValue: Flow<Pair<Key, Value>>
/**
* This flow must emit data each time when data by [Key] has been removed with [unset]/[unsetWithValues] methods or
* in any other way
*
* @see onNewValue
*/
val onValueRemoved: Flow<Key>
/**
* Will set as batch [toSet] data in current repo. Must pass the data which were successfully updated in repo to
* [onNewValue]
*/
suspend fun set(toSet: Map<Key, Value>)
/**
* Will unset as batch data with keys from [toUnset]. Must pass the [Key]s which were successfully removed in repo to
* [onValueRemoved]
*/
suspend fun unset(toUnset: List<Key>)
/**
* Will unset as batch data with values from [toUnset]. Must pass the [Key]s which were successfully removed in repo
* to [onValueRemoved]
*/
suspend fun unsetWithValues(toUnset: List<Value>)
}
typealias WriteStandardKeyValueRepo<Key,Value> = WriteKeyValueRepo<Key, Value>
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
vararg toSet: Pair<Key, Value>
) = set(toSet.toMap())
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
k: Key, v: Value
) = set(k to v)
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unset(
vararg k: Key
) = unset(k.toList())
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unsetWithValues(
vararg v: Value
) = unsetWithValues(v.toList())
/**
* Full version of standard key-value repository with all set/unset/clear/get methods
*/
interface KeyValueRepo<Key, Value> : ReadKeyValueRepo<Key, Value>, WriteKeyValueRepo<Key, Value> {
/**
* By default, will walk throw all the [keys] with [Value]s from [toUnset] and run [doAllWithCurrentPaging] with
* [unset] of found data [Key]s
*/
override suspend fun unsetWithValues(toUnset: List<Value>) = toUnset.forEach { v ->
doAllWithCurrentPaging {
keys(v, it).also {
unset(it.results)
}
}
}
/**
* By default, will remove all the data of current repo using [doAllWithCurrentPaging], [keys] and [unset]
*/
suspend fun clear() {
doAllWithCurrentPaging { keys(it).also { unset(it.results) } }
}
}
typealias StandardKeyValueRepo<Key,Value> = KeyValueRepo<Key, Value>
class DelegateBasedKeyValueRepo<Key, Value>(
readDelegate: ReadKeyValueRepo<Key, Value>,
writeDelegate: WriteKeyValueRepo<Key, Value>
) : KeyValueRepo<Key, Value>,
ReadKeyValueRepo<Key, Value> by readDelegate,
WriteKeyValueRepo<Key, Value> by writeDelegate

View File

@@ -1,63 +0,0 @@
package dev.inmo.micro_utils.repos
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.doAllWithCurrentPaging
import kotlinx.coroutines.flow.Flow
interface ReadKeyValueRepo<Key, Value> : Repo {
suspend fun get(k: Key): Value?
suspend fun values(pagination: Pagination, reversed: Boolean = false): PaginationResult<Value>
suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean = false): PaginationResult<Key>
suspend fun contains(key: Key): Boolean
suspend fun count(): Long
}
typealias ReadStandardKeyValueRepo<Key,Value> = ReadKeyValueRepo<Key, Value>
interface WriteKeyValueRepo<Key, Value> : Repo {
val onNewValue: Flow<Pair<Key, Value>>
val onValueRemoved: Flow<Key>
suspend fun set(toSet: Map<Key, Value>)
suspend fun unset(toUnset: List<Key>)
suspend fun unsetWithValues(toUnset: List<Value>)
}
typealias WriteStandardKeyValueRepo<Key,Value> = WriteKeyValueRepo<Key, Value>
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
vararg toSet: Pair<Key, Value>
) = set(toSet.toMap())
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
k: Key, v: Value
) = set(k to v)
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unset(
vararg k: Key
) = unset(k.toList())
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unsetWithValues(
vararg v: Value
) = unsetWithValues(v.toList())
interface KeyValueRepo<Key, Value> : ReadKeyValueRepo<Key, Value>, WriteKeyValueRepo<Key, Value> {
override suspend fun unsetWithValues(toUnset: List<Value>) = toUnset.forEach { v ->
doAllWithCurrentPaging {
keys(v, it).also {
unset(it.results)
}
}
}
suspend fun clear() {
doAllWithCurrentPaging { keys(it).also { unset(it.results) } }
}
}
typealias StandardKeyValueRepo<Key,Value> = KeyValueRepo<Key, Value>
class DelegateBasedKeyValueRepo<Key, Value>(
readDelegate: ReadKeyValueRepo<Key, Value>,
writeDelegate: WriteKeyValueRepo<Key, Value>
) : KeyValueRepo<Key, Value>,
ReadKeyValueRepo<Key, Value> by readDelegate,
WriteKeyValueRepo<Key, Value> by writeDelegate

View File

@@ -27,8 +27,24 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
protected abstract fun InsertStatement<Number>.asObject(value: InputValueType): ObjectType
protected abstract fun update(id: IdType, value: InputValueType, it: UpdateBuilder<Int>)
protected abstract fun createAndInsertId(value: InputValueType, it: InsertStatement<Number>): IdType
/**
* @param id Can be null only if [createAndInsertId] have returned null (it can be useful when you have
* autoincrement identifier)
* @param it Will be [UpdateStatement] when it is called from [update] method or [InsertStatement] from the [create]
* one. Anyway, it is main method where you should put the logic of table filling by [value] data
*
* @see createAndInsertId
*/
protected abstract fun update(id: IdType?, value: InputValueType, it: UpdateBuilder<Int>)
/**
* Override this method to interact with [it] ([InsertStatement]) and put there new id with [IdType].
*
* By default, have null value due to the fact that in the most cases users have [autoIncrement]ing id columns
*
* @return In case when id for the model has been created new [IdType] should be returned
*/
protected open fun createAndInsertId(value: InputValueType, it: InsertStatement<Number>): IdType? = null
protected open fun insert(value: InputValueType, it: InsertStatement<Number>) {
val id = createAndInsertId(value, it)