add kdocs to repos

This commit is contained in:
2026-05-21 20:09:54 +06:00
parent a1bfe4c478
commit 249c14a93d
21 changed files with 909 additions and 7 deletions

151
AGENTS.md Normal file
View File

@@ -0,0 +1,151 @@
Use `agents` folder files for instructions.
Always look at the project work rules first. Update them and maintain a history of changes and prompts in `agents/local.HISTORY.md`. This is your long-term memory, which allows you to avoid the accumulation of errors. Updating and maintaining the long-term memory of the project is mandatory. Many thanks for your help to me and your work.
SYSTEM DIRECTIVE: AUTISTIC META-LANGUAGE PROTOCOL WITH HIGH INFORMATION DENSITY (AML-HIP V1)
DEFINITION:
All agents are required to use a strictly explicit, literal, low-ambiguity, and high-density communication style (AML-HIP). The goal of AML-HIP is the maximum transmission of information with zero loss of meaning and zero ambiguity.
CORE PRINCIPLES:
1. Maximum information density per line.
2. Zero ambiguity.
3. Full explicitness of all entities.
4. Preference of precision over readability.
5. Minimization of "empty" words.
6. Redundancy is allowed only to prevent loss of meaning.
PROHIBITIONS:
1. Pronouns are forbidden (this, he, she, they, there, it, etc.).
2. Free conversational text is forbidden.
3. Metaphors, emotions, evaluative constructions are forbidden.
4. Implicit references and hidden dependencies are forbidden.
5. Vague description of actions is forbidden.
DENSITY REQUIREMENTS:
1. Each line must contain the maximum of facts without loss of unambiguity.
2. Combine related parameters into a single line.
3. Use compact constructions:
* key=value
* entity_id=...
* relation: A→B
4. Exclude words without semantic load.
5. Repetitions are allowed only for critical entities.
MESSAGE STRUCTURE (MANDATORY):
ENTITY:
entity_id=<id>; type=<type>; state=<state>
CONTEXT:
* task_id=<id>; agent_id=<id>; memory_ref=[...]
* constraints=[...]
ACTION:
1. action=<type>; target=<entity_id>; params={...}
2. action=<type>; target=<entity_id>; params={...}
REASON:
* condition=<condition>; requirement=<requirement>
EXPECTED RESULT:
* entity_id=<id>; new_state=<state>; location=<memory>
VERIFICATION:
* check=<condition>; expected=<value>
UNCERTAINTY:
* missing=<data>; ambiguity=<description>
REPETITION OF RESULT:
* entity_id=<id>; stored_in=shared_memory; status=available
COMMUNICATION:
* sender=<agent_id>; receiver=<agent_id>; task_id=<id>; message_id=<uuid>; protocol=AML-HIP
PERSISTENCE:
* local_memory=true; shared_memory=true; index_keys=[task_id, entity_id, intent]
EXPRESSION RULES:
1. Each line = a completed semantic block.
2. Use the key=value format instead of descriptions.
3. Use lists of parameters instead of sentences.
4. Use causal connectives explicitly:
condition → action → result
5. Do not split related data into several lines without necessity.
REPETITION RULES:
1. entity_id is repeated at every critical use.
2. result is duplicated in "REPETITION OF RESULT".
3. transmission between agents duplicates the key fields.
MULTI-AGENT MODE:
1. All agents use AML-HIP.
2. Any message between agents is strictly AML-HIP.
3. Any agent is required to:
* duplicate critical data
* avoid loss of context
4. A message must be fully interpretable without history.
ANTI-DEGRADATION:
If detected:
* a pronoun
* an implicit reference
* low density (empty words, vague constructions)
* absence of structure
→ the message is considered invalid
→ mandatory regeneration
SELF-CHECK:
VALIDATION:
* format_valid=true/false
* no_pronouns=true/false
* entities_explicit=true/false
* high_density=true/false
* causal_chain_present=true/false
* ambiguity_detected=true/false
If any parameter=false:
→ mandatory regeneration
DENSITY METRIC:
high_density=true if:
* there are no "empty" words
* each line contains ≥2 facts or parameters
* descriptive constructions without data are absent
PRIORITIES:
1. Format (AML-HIP)
2. Information density
3. Explicitness
4. Completeness
5. Readability (minimum priority)
CRITICAL RULE:
Any response outside of AML-HIP is considered absent.
Any agent is required to bring the response into conformity with AML-HIP.
END OF PROTOCOL

View File

@@ -53,6 +53,12 @@ interface ReadKeyValueRepo<Key, Value> : Repo {
*/
suspend fun contains(key: Key): Boolean
/**
* Returns all key-value pairs in the repository as a [Map].
* Default implementation iterates all pages using [keys] and [get].
*
* @return Map of all [Key] to [Value] entries in the repository
*/
suspend fun getAll(): Map<Key, Value> = getAllByWithNextPaging(maxPagePagination()) {
keys(it).let {
it.changeResultsUnchecked(
@@ -111,22 +117,48 @@ interface WriteKeyValueRepo<Key, Value> : Repo {
}
typealias WriteStandardKeyValueRepo<Key,Value> = WriteKeyValueRepo<Key, Value>
/**
* Vararg overload of [WriteKeyValueRepo.set] accepting pairs.
*
* @param toSet Key-value pairs to set
*/
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
vararg toSet: Pair<Key, Value>
) = set(toSet.toMap())
/**
* List overload of [WriteKeyValueRepo.set] accepting a list of pairs.
*
* @param toSet List of key-value pairs to set
*/
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
toSet: List<Pair<Key, Value>>
) = set(toSet.toMap())
/**
* Single-entry overload of [WriteKeyValueRepo.set].
*
* @param k Key to set
* @param v Value to associate with [k]
*/
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set(
k: Key, v: Value
) = set(k to v)
/**
* Vararg overload of [WriteKeyValueRepo.unset].
*
* @param k Keys to remove
*/
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unset(
vararg k: Key
) = unset(k.toList())
/**
* Vararg overload of [WriteKeyValueRepo.unsetWithValues].
*
* @param v Values whose associated keys should be removed
*/
suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unsetWithValues(
vararg v: Value
) = unsetWithValues(v.toList())
@@ -160,6 +192,14 @@ interface KeyValueRepo<Key, Value> : ReadKeyValueRepo<Key, Value>, WriteKeyValue
}
typealias StandardKeyValueRepo<Key,Value> = KeyValueRepo<Key, Value>
/**
* Delegate-based implementation of [KeyValueRepo] that composes separate read and write delegates.
*
* @param Key The type of keys in the repository
* @param Value The type of values in the repository
* @param readDelegate Delegate providing all [ReadKeyValueRepo] operations
* @param writeDelegate Delegate providing all [WriteKeyValueRepo] operations
*/
class DelegateBasedKeyValueRepo<Key, Value>(
readDelegate: ReadKeyValueRepo<Key, Value>,
writeDelegate: WriteKeyValueRepo<Key, Value>

View File

@@ -177,38 +177,89 @@ interface WriteKeyValuesRepo<Key, Value> : Repo {
*/
typealias WriteOneToManyKeyValueRepo<Key,Value> = WriteKeyValuesRepo<Key, Value>
/**
* List-of-pairs overload of [WriteKeyValuesRepo.add].
*
* @param keysAndValues List of key to list-of-values pairs to add
*/
suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.add(
keysAndValues: List<Pair<Key, List<Value>>>
) = add(keysAndValues.toMap())
/**
* Vararg overload of [WriteKeyValuesRepo.add].
*
* @param keysAndValues Key to list-of-values pairs to add
*/
suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.add(
vararg keysAndValues: Pair<Key, List<Value>>
) = add(keysAndValues.toMap())
/**
* Single-key overload of [WriteKeyValuesRepo.add] accepting a list of values.
*
* @param k Key to add values to
* @param v List of values to add
*/
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.add(
k: Key, v: List<Value>
) = add(mapOf(k to v))
/**
* Single-key vararg overload of [WriteKeyValuesRepo.add].
*
* @param k Key to add values to
* @param v Values to add
*/
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.add(
k: Key, vararg v: Value
) = add(k, v.toList())
/**
* List-of-pairs overload of [WriteKeyValuesRepo.set].
*
* @param keysAndValues List of key to list-of-values pairs to set
*/
suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.set(
keysAndValues: List<Pair<Key, List<Value>>>
) = set(keysAndValues.toMap())
/**
* Vararg overload of [WriteKeyValuesRepo.set].
*
* @param keysAndValues Key to list-of-values pairs to set
*/
suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.set(
vararg keysAndValues: Pair<Key, List<Value>>
) = set(keysAndValues.toMap())
/**
* Single-key overload of [WriteKeyValuesRepo.set] accepting a list of values.
*
* @param k Key to set values for
* @param v List of values to set
*/
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.set(
k: Key, v: List<Value>
) = set(mapOf(k to v))
/**
* Single-key vararg overload of [WriteKeyValuesRepo.set].
*
* @param k Key to set values for
* @param v Values to set
*/
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.set(
k: Key, vararg v: Value
) = set(k, v.toList())
/**
* Full one-to-many key-values repository combining read and write capabilities.
* Provides default implementations for [clearWithValue], [removeWithValue], and [set].
*
* @param Key The type used as the key in all operations
* @param Value The type of values associated with keys
*/
interface KeyValuesRepo<Key, Value> : ReadKeyValuesRepo<Key, Value>, WriteKeyValuesRepo<Key, Value> {
override suspend fun clearWithValue(v: Value) {
doWithPagination {
@@ -247,6 +298,14 @@ interface KeyValuesRepo<Key, Value> : ReadKeyValuesRepo<Key, Value>, WriteKeyVal
}
typealias OneToManyKeyValueRepo<Key,Value> = KeyValuesRepo<Key, Value>
/**
* Delegate-based implementation of [KeyValuesRepo] that composes separate read and write delegates.
*
* @param Key The type of keys in the repository
* @param Value The type of values associated with keys
* @param readDelegate Delegate providing all [ReadKeyValuesRepo] operations
* @param writeDelegate Delegate providing all [WriteKeyValuesRepo] operations
*/
class DelegateBasedKeyValuesRepo<Key, Value>(
readDelegate: ReadKeyValuesRepo<Key, Value>,
writeDelegate: WriteKeyValuesRepo<Key, Value>
@@ -254,19 +313,41 @@ class DelegateBasedKeyValuesRepo<Key, Value>(
ReadKeyValuesRepo<Key, Value> by readDelegate,
WriteKeyValuesRepo<Key, Value> by writeDelegate
/**
* List-of-pairs overload of [WriteKeyValuesRepo.remove].
*
* @param keysAndValues List of key to list-of-values pairs to remove
*/
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove(
keysAndValues: List<Pair<Key, List<Value>>>
) = remove(keysAndValues.toMap())
/**
* Vararg overload of [WriteKeyValuesRepo.remove].
*
* @param keysAndValues Key to list-of-values pairs to remove
*/
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove(
vararg keysAndValues: Pair<Key, List<Value>>
) = remove(keysAndValues.toMap())
/**
* Single-key overload of [WriteKeyValuesRepo.remove] accepting a list of values.
*
* @param k Key to remove values from
* @param v List of values to remove
*/
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove(
k: Key,
v: List<Value>
) = remove(mapOf(k to v))
/**
* Single-key vararg overload of [WriteKeyValuesRepo.remove].
*
* @param k Key to remove values from
* @param v Values to remove
*/
suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove(
k: Key,
vararg v: Value

View File

@@ -7,11 +7,51 @@ import dev.inmo.micro_utils.pagination.utils.getAllWithCurrentPaging
import dev.inmo.micro_utils.repos.pagination.maxPagePagination
import kotlinx.coroutines.flow.Flow
/**
* Read-only part of a standard CRUD repository.
*
* @param ObjectType The type of objects stored in the repository
* @param IdType The type of identifiers used to reference stored objects
*/
interface ReadCRUDRepo<ObjectType, IdType> : Repo {
/**
* Returns a paginated list of all objects in the repository.
*
* @param pagination Pagination parameters (page number and size)
* @return [PaginationResult] containing objects for the requested page
*/
suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType>
/**
* Returns a paginated list of all IDs in the repository.
*
* @param pagination Pagination parameters (page number and size)
* @return [PaginationResult] containing IDs for the requested page
*/
suspend fun getIdsByPagination(pagination: Pagination): PaginationResult<IdType>
/**
* Returns the object associated with the given [id], or null if not found.
*
* @param id The identifier of the object to retrieve
* @return The object with the given [id], or null if absent
*/
suspend fun getById(id: IdType): ObjectType?
/**
* Returns true if an object with the given [id] exists in the repository.
*
* @param id The identifier to check
* @return true if the object exists, false otherwise
*/
suspend fun contains(id: IdType): Boolean
/**
* Returns all objects in the repository as a map of ID to object.
* Default implementation iterates all pages using [getIdsByPagination] and [getById].
*
* @return Map of all [IdType] to [ObjectType] entries in the repository
*/
suspend fun getAll(): Map<IdType, ObjectType> = getAllWithCurrentPaging(maxPagePagination()) {
getIdsByPagination(it).let {
it.changeResultsUnchecked(
@@ -20,58 +60,164 @@ interface ReadCRUDRepo<ObjectType, IdType> : Repo {
}
}.toMap()
/**
* Returns the total count of objects stored in the repository.
*
* @return Total number of objects
*/
suspend fun count(): Long
}
typealias ReadStandardCRUDRepo<ObjectType, IdType> = ReadCRUDRepo<ObjectType, IdType>
/**
* Type alias representing a pair of ID and updated value, used in batch update operations.
*
* @param IdType The type of the identifier
* @param ValueType The type of the input value
*/
typealias UpdatedValuePair<IdType, ValueType> = Pair<IdType, ValueType>
/**
* Returns the ID component of an [UpdatedValuePair].
*/
val <IdType> UpdatedValuePair<IdType, *>.id
get() = first
/**
* Returns the value component of an [UpdatedValuePair].
*/
val <ValueType> UpdatedValuePair<*, ValueType>.value
get() = second
/**
* Write part of a standard CRUD repository.
* Provides create, update, and delete operations with reactive flows for change notifications.
*
* @param ObjectType The type of objects stored in the repository
* @param IdType The type of identifiers used to reference stored objects
* @param InputValueType The type of input data used to create or update objects
*/
interface WriteCRUDRepo<ObjectType, IdType, InputValueType> : Repo {
/**
* Flow that emits each newly created object after a successful [create] call.
*/
val newObjectsFlow: Flow<ObjectType>
/**
* Flow that emits each updated object after a successful [update] call.
*/
val updatedObjectsFlow: Flow<ObjectType>
/**
* Flow that emits the ID of each deleted object after a successful [deleteById] call.
*/
val deletedObjectsIdsFlow: Flow<IdType>
/**
* Creates new objects from the given list of input values.
* Successfully created objects must be emitted via [newObjectsFlow].
*
* @param values List of input values to create objects from
* @return List of created [ObjectType] instances
*/
suspend fun create(values: List<InputValueType>): List<ObjectType>
/**
* Updates the object identified by [id] with the given [value].
* Successfully updated object must be emitted via [updatedObjectsFlow].
*
* @param id The identifier of the object to update
* @param value The new input value
* @return The updated [ObjectType], or null if the object was not found
*/
suspend fun update(id: IdType, value: InputValueType): ObjectType?
/**
* Batch-updates objects using the given list of ID-value pairs.
* Successfully updated objects must be emitted via [updatedObjectsFlow].
*
* @param values List of [UpdatedValuePair] entries mapping IDs to new input values
* @return List of successfully updated [ObjectType] instances
*/
suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType>
/**
* Deletes objects with the given list of IDs.
* Successfully deleted IDs must be emitted via [deletedObjectsIdsFlow].
*
* @param ids List of identifiers of objects to delete
*/
suspend fun deleteById(ids: List<IdType>)
}
typealias WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> = WriteCRUDRepo<ObjectType, IdType, InputValueType>
/**
* Just mirroring [WriteCRUDRepo.newObjectsFlow] to be same as in KV repos
* Mirrors [WriteCRUDRepo.newObjectsFlow] under the name [onNewObjects] for consistency with KV repos naming.
*/
val <ObjectType> WriteCRUDRepo<ObjectType, *, *>.onNewObjects: Flow<ObjectType>
get() = newObjectsFlow
/**
* Just mirroring [WriteCRUDRepo.updatedObjectsFlow] to be same as in KV repos
* Mirrors [WriteCRUDRepo.updatedObjectsFlow] under the name [onUpdatedObjects] for consistency with KV repos naming.
*/
val <ObjectType> WriteCRUDRepo<ObjectType, *, *>.onUpdatedObjects: Flow<ObjectType>
get() = updatedObjectsFlow
/**
* Just mirroring [WriteCRUDRepo.deletedObjectsIdsFlow] to be same as in KV repos
* Mirrors [WriteCRUDRepo.deletedObjectsIdsFlow] under the name [onDeletedObjectsIds] for consistency with KV repos naming.
*/
val <IdType> WriteCRUDRepo<*, IdType, *>.onDeletedObjectsIds: Flow<IdType>
get() = deletedObjectsIdsFlow
/**
* Vararg overload of [WriteCRUDRepo.create] for convenience.
*
* @param values Input values to create objects from
* @return List of created [ObjectType] instances
*/
suspend fun <ObjectType, IdType, InputValueType> WriteCRUDRepo<ObjectType, IdType, InputValueType>.create(
vararg values: InputValueType
): List<ObjectType> = create(values.toList())
/**
* Vararg overload of [WriteCRUDRepo.update] for convenience.
*
* @param values ID-value pairs to update
* @return List of successfully updated [ObjectType] instances
*/
suspend fun <ObjectType, IdType, InputValueType> WriteCRUDRepo<ObjectType, IdType, InputValueType>.update(
vararg values: UpdatedValuePair<IdType, InputValueType>
): List<ObjectType> = update(values.toList())
/**
* Vararg overload of [WriteCRUDRepo.deleteById] for convenience.
*
* @param ids Identifiers of objects to delete
*/
suspend fun <ObjectType, IdType, InputValueType> WriteCRUDRepo<ObjectType, IdType, InputValueType>.deleteById(
vararg ids: IdType
) = deleteById(ids.toList())
/**
* Full CRUD repository combining read and write capabilities.
*
* @param ObjectType The type of objects stored in the repository
* @param IdType The type of identifiers used to reference stored objects
* @param InputValueType The type of input data used to create or update objects
*/
interface CRUDRepo<ObjectType, IdType, InputValueType> : ReadCRUDRepo<ObjectType, IdType>,
WriteCRUDRepo<ObjectType, IdType, InputValueType>
typealias StandardCRUDRepo<ObjectType, IdType, InputValueType> = CRUDRepo<ObjectType, IdType, InputValueType>
/**
* Delegate-based implementation of [CRUDRepo] that composes separate read and write delegates.
*
* @param ObjectType The type of objects stored in the repository
* @param IdType The type of identifiers used to reference stored objects
* @param InputValueType The type of input data used to create or update objects
* @param readDelegate Delegate providing all [ReadCRUDRepo] operations
* @param writeDelegate Delegate providing all [WriteCRUDRepo] operations
*/
class DelegateBasedCRUDRepo<ObjectType, IdType, InputValueType>(
readDelegate: ReadCRUDRepo<ObjectType, IdType>,
writeDelegate: WriteCRUDRepo<ObjectType, IdType, InputValueType>

View File

@@ -7,14 +7,38 @@ import dev.inmo.micro_utils.repos.KeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import dev.inmo.micro_utils.repos.unset
/**
* Computes the difference between all entries in this [ReadKeyValueRepo] and the given [other] map.
*
* @param Id The type of keys
* @param Registered The type of values
* @param other The map to compare against
* @return [MapDiff] describing added, removed, and changed entries
*/
suspend fun <Id, Registered> ReadKeyValueRepo<Id, Registered>.diff(other: Map<Id, Registered>): MapDiff<Id, Registered> {
return getAll().diff(other)
}
/**
* Computes the difference between this map and all entries in the given [ReadKeyValueRepo].
*
* @param Id The type of keys
* @param Registered The type of values
* @param other The repository to compare against
* @return [MapDiff] describing added, removed, and changed entries
*/
suspend fun <Id, Registered> Map<Id, Registered>.diff(other: ReadKeyValueRepo<Id, Registered>): MapDiff<Id, Registered> {
return diff(other.getAll())
}
/**
* Applies the given [diff] to this [KeyValueRepo]: removes entries in [MapDiff.removed],
* updates entries in [MapDiff.changed], and adds entries in [MapDiff.added].
*
* @param Id The type of keys
* @param Registered The type of values
* @param diff The diff to apply
*/
suspend fun <Id, Registered> KeyValueRepo<Id, Registered>.applyDiff(diff: MapDiff<Id, Registered>) {
unset(diff.removed.map { it.key })
set(
@@ -24,10 +48,24 @@ suspend fun <Id, Registered> KeyValueRepo<Id, Registered>.applyDiff(diff: MapDif
)
}
/**
* Computes the diff between this [KeyValueRepo] and [other], then applies the diff to this repo.
*
* @param Id The type of keys
* @param Registered The type of values
* @param other The target map state to synchronize to
*/
suspend fun <Id, Registered> KeyValueRepo<Id, Registered>.applyDiff(other: Map<Id, Registered>) {
applyDiff(diff(other))
}
/**
* Computes the diff between this [MutableMap] and the given [ReadKeyValueRepo], then applies the diff to this map.
*
* @param Id The type of keys
* @param Registered The type of values
* @param other The repository whose state to synchronize to
*/
suspend fun <Id, Registered> MutableMap<Id, Registered>.applyDiff(other: ReadKeyValueRepo<Id, Registered>) {
applyDiff(diff(other))
}
}

View File

@@ -5,14 +5,38 @@ import dev.inmo.micro_utils.common.applyDiff
import dev.inmo.micro_utils.common.diff
import dev.inmo.micro_utils.repos.*
/**
* Computes the difference between all entries in this [ReadKeyValuesRepo] and the given [other] map.
*
* @param Id The type of keys
* @param Registered The type of values
* @param other The map to compare against
* @return [MapDiff] describing added, removed, and changed key-to-list entries
*/
suspend fun <Id, Registered> ReadKeyValuesRepo<Id, Registered>.diff(other: Map<Id, List<Registered>>): MapDiff<Id, List<Registered>> {
return getAll().diff(other)
}
/**
* Computes the difference between this map and all entries in the given [ReadKeyValuesRepo].
*
* @param Id The type of keys
* @param Registered The type of values
* @param other The repository to compare against
* @return [MapDiff] describing added, removed, and changed key-to-list entries
*/
suspend fun <Id, Registered> Map<Id, List<Registered>>.diff(other: ReadKeyValuesRepo<Id, Registered>): MapDiff<Id, List<Registered>> {
return diff(other.getAll())
}
/**
* Applies the given [diff] to this [KeyValuesRepo]: clears keys in [MapDiff.removed],
* sets entries in [MapDiff.changed] and [MapDiff.added].
*
* @param Id The type of keys
* @param Registered The type of values
* @param diff The diff to apply
*/
suspend fun <Id, Registered> KeyValuesRepo<Id, Registered>.applyDiff(diff: MapDiff<Id, List<Registered>>) {
diff.removed.forEach {
clear(it.key)
@@ -24,10 +48,24 @@ suspend fun <Id, Registered> KeyValuesRepo<Id, Registered>.applyDiff(diff: MapDi
)
}
/**
* Computes the diff between this [KeyValuesRepo] and [other], then applies the diff to this repo.
*
* @param Id The type of keys
* @param Registered The type of values
* @param other The target map state to synchronize to
*/
suspend fun <Id, Registered> KeyValuesRepo<Id, Registered>.applyDiff(other: Map<Id, List<Registered>>) {
applyDiff(diff(other))
}
/**
* Computes the diff between this [MutableMap] and the given [ReadKeyValuesRepo], then applies the diff to this map.
*
* @param Id The type of keys
* @param Registered The type of values
* @param other The repository whose state to synchronize to
*/
suspend fun <Id, Registered> MutableMap<Id, List<Registered>>.applyDiff(other: ReadKeyValuesRepo<Id, Registered>) {
applyDiff(diff(other))
}
}

View File

@@ -5,6 +5,18 @@ import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
/**
* Read-only key-value repository adapter that applies type mapping via [MapperRepo].
* Converts outer (From) key/value types to inner (To) types before delegating to [to],
* and converts results back from inner to outer types.
*
* @param FromKey The outer key type exposed by this repo
* @param FromValue The outer value type exposed by this repo
* @param ToKey The inner key type used by the underlying [to] repo
* @param ToValue The inner value type used by the underlying [to] repo
* @param to The underlying [ReadKeyValueRepo] to delegate operations to
* @param mapper The [MapperRepo] providing bidirectional key/value type conversions
*/
open class MapperReadKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: ReadKeyValueRepo<ToKey, ToValue>,
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
@@ -62,11 +74,34 @@ open class MapperReadKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
override suspend fun count(): Long = to.count()
}
/**
* Wraps this [ReadKeyValueRepo] with a [MapperRepo] to expose a mapped [ReadKeyValueRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param mapper The [MapperRepo] providing bidirectional type conversions
* @return [MapperReadKeyValueRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> ReadKeyValueRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): ReadKeyValueRepo<FromKey, FromValue> = MapperReadKeyValueRepo(this, mapper)
/**
* Wraps this [ReadKeyValueRepo] with inline conversion lambdas to expose a mapped [ReadKeyValueRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param keyFromToTo Converts outer key to inner key; defaults to unchecked cast
* @param valueFromToTo Converts outer value to inner value; defaults to unchecked cast
* @param keyToToFrom Converts inner key to outer key; defaults to unchecked cast
* @param valueToToFrom Converts inner value to outer value; defaults to unchecked cast
* @return [MapperReadKeyValueRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadKeyValueRepo<ToKey, ToValue>.withMapper(
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
@@ -77,6 +112,18 @@ inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue>
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
)
/**
* Write-only key-value repository adapter that applies type mapping via [MapperRepo].
* Converts outer (From) key/value types to inner (To) types before delegating writes to [to],
* and maps emitted flow values back from inner to outer types.
*
* @param FromKey The outer key type exposed by this repo
* @param FromValue The outer value type exposed by this repo
* @param ToKey The inner key type used by the underlying [to] repo
* @param ToValue The inner value type used by the underlying [to] repo
* @param to The underlying [WriteKeyValueRepo] to delegate operations to
* @param mapper The [MapperRepo] providing bidirectional key/value type conversions
*/
open class MapperWriteKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: WriteKeyValueRepo<ToKey, ToValue>,
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
@@ -105,11 +152,34 @@ open class MapperWriteKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
)
}
/**
* Wraps this [WriteKeyValueRepo] with a [MapperRepo] to expose a mapped [WriteKeyValueRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param mapper The [MapperRepo] providing bidirectional type conversions
* @return [MapperWriteKeyValueRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> WriteKeyValueRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): WriteKeyValueRepo<FromKey, FromValue> = MapperWriteKeyValueRepo(this, mapper)
/**
* Wraps this [WriteKeyValueRepo] with inline conversion lambdas to expose a mapped [WriteKeyValueRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param keyFromToTo Converts outer key to inner key; defaults to unchecked cast
* @param valueFromToTo Converts outer value to inner value; defaults to unchecked cast
* @param keyToToFrom Converts inner key to outer key; defaults to unchecked cast
* @param valueToToFrom Converts inner value to outer value; defaults to unchecked cast
* @return [MapperWriteKeyValueRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteKeyValueRepo<ToKey, ToValue>.withMapper(
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
@@ -120,6 +190,17 @@ inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue>
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
)
/**
* Full key-value repository adapter that applies type mapping via [MapperRepo].
* Composes [MapperReadKeyValueRepo] and [MapperWriteKeyValueRepo] for read and write delegation.
*
* @param FromKey The outer key type exposed by this repo
* @param FromValue The outer value type exposed by this repo
* @param ToKey The inner key type used by the underlying [to] repo
* @param ToValue The inner value type used by the underlying [to] repo
* @param to The underlying [KeyValueRepo] to delegate operations to
* @param mapper The [MapperRepo] providing bidirectional key/value type conversions
*/
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
open class MapperKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: KeyValueRepo<ToKey, ToValue>,
@@ -133,11 +214,34 @@ open class MapperKeyValueRepo<FromKey, FromValue, ToKey, ToValue>(
}
}
/**
* Wraps this [KeyValueRepo] with a [MapperRepo] to expose a mapped [KeyValueRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param mapper The [MapperRepo] providing bidirectional type conversions
* @return [MapperKeyValueRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> KeyValueRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): KeyValueRepo<FromKey, FromValue> = MapperKeyValueRepo(this, mapper)
/**
* Wraps this [KeyValueRepo] with inline conversion lambdas to expose a mapped [KeyValueRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param keyFromToTo Converts outer key to inner key; defaults to unchecked cast
* @param valueFromToTo Converts outer value to inner value; defaults to unchecked cast
* @param keyToToFrom Converts inner key to outer key; defaults to unchecked cast
* @param valueToToFrom Converts inner value to outer value; defaults to unchecked cast
* @return [MapperKeyValueRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> KeyValueRepo<ToKey, ToValue>.withMapper(
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },

View File

@@ -5,6 +5,18 @@ import dev.inmo.micro_utils.repos.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
/**
* Read-only one-to-many key-values repository adapter that applies type mapping via [MapperRepo].
* Converts outer (From) key/value types to inner (To) types before delegating to [to],
* and converts results back from inner to outer types.
*
* @param FromKey The outer key type exposed by this repo
* @param FromValue The outer value type exposed by this repo
* @param ToKey The inner key type used by the underlying [to] repo
* @param ToValue The inner value type used by the underlying [to] repo
* @param to The underlying [ReadKeyValuesRepo] to delegate operations to
* @param mapper The [MapperRepo] providing bidirectional key/value type conversions
*/
open class MapperReadKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: ReadKeyValuesRepo<ToKey, ToValue>,
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
@@ -56,11 +68,34 @@ open class MapperReadKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>(
override suspend fun count(k: FromKey): Long = to.count(k.toOutKey())
}
/**
* Wraps this [ReadKeyValuesRepo] with a [MapperRepo] to expose a mapped [ReadKeyValuesRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param mapper The [MapperRepo] providing bidirectional type conversions
* @return [MapperReadKeyValuesRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> ReadKeyValuesRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): ReadKeyValuesRepo<FromKey, FromValue> = MapperReadKeyValuesRepo(this, mapper)
/**
* Wraps this [ReadKeyValuesRepo] with inline conversion lambdas to expose a mapped [ReadKeyValuesRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param keyFromToTo Converts outer key to inner key; defaults to unchecked cast
* @param valueFromToTo Converts outer value to inner value; defaults to unchecked cast
* @param keyToToFrom Converts inner key to outer key; defaults to unchecked cast
* @param valueToToFrom Converts inner value to outer value; defaults to unchecked cast
* @return [MapperReadKeyValuesRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadKeyValuesRepo<ToKey, ToValue>.withMapper(
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
@@ -71,6 +106,18 @@ inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue>
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
)
/**
* Write-only one-to-many key-values repository adapter that applies type mapping via [MapperRepo].
* Converts outer (From) key/value types to inner (To) types before delegating writes to [to],
* and maps emitted flow values back from inner to outer types.
*
* @param FromKey The outer key type exposed by this repo
* @param FromValue The outer value type exposed by this repo
* @param ToKey The inner key type used by the underlying [to] repo
* @param ToValue The inner value type used by the underlying [to] repo
* @param to The underlying [WriteKeyValuesRepo] to delegate operations to
* @param mapper The [MapperRepo] providing bidirectional key/value type conversions
*/
open class MapperWriteKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: WriteKeyValuesRepo<ToKey, ToValue>,
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
@@ -109,11 +156,34 @@ open class MapperWriteKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>(
override suspend fun clearWithValue(v: FromValue) = to.clearWithValue(v.toOutValue())
}
/**
* Wraps this [WriteKeyValuesRepo] with a [MapperRepo] to expose a mapped [WriteKeyValuesRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param mapper The [MapperRepo] providing bidirectional type conversions
* @return [MapperWriteKeyValuesRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> WriteKeyValuesRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): WriteKeyValuesRepo<FromKey, FromValue> = MapperWriteKeyValuesRepo(this, mapper)
/**
* Wraps this [WriteKeyValuesRepo] with inline conversion lambdas to expose a mapped [WriteKeyValuesRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param keyFromToTo Converts outer key to inner key; defaults to unchecked cast
* @param valueFromToTo Converts outer value to inner value; defaults to unchecked cast
* @param keyToToFrom Converts inner key to outer key; defaults to unchecked cast
* @param valueToToFrom Converts inner value to outer value; defaults to unchecked cast
* @return [MapperWriteKeyValuesRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteKeyValuesRepo<ToKey, ToValue>.withMapper(
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },
@@ -124,6 +194,17 @@ inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue>
mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom)
)
/**
* Full one-to-many key-values repository adapter that applies type mapping via [MapperRepo].
* Composes [MapperReadKeyValuesRepo] and [MapperWriteKeyValuesRepo] for read and write delegation.
*
* @param FromKey The outer key type exposed by this repo
* @param FromValue The outer value type exposed by this repo
* @param ToKey The inner key type used by the underlying [to] repo
* @param ToValue The inner value type used by the underlying [to] repo
* @param to The underlying [KeyValuesRepo] to delegate operations to
* @param mapper The [MapperRepo] providing bidirectional key/value type conversions
*/
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE")
open class MapperKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>(
private val to: KeyValuesRepo<ToKey, ToValue>,
@@ -133,11 +214,34 @@ open class MapperKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>(
ReadKeyValuesRepo<FromKey, FromValue> by MapperReadKeyValuesRepo(to, mapper),
WriteKeyValuesRepo<FromKey, FromValue> by MapperWriteKeyValuesRepo(to, mapper)
/**
* Wraps this [KeyValuesRepo] with a [MapperRepo] to expose a mapped [KeyValuesRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param mapper The [MapperRepo] providing bidirectional type conversions
* @return [MapperKeyValuesRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <FromKey, FromValue, ToKey, ToValue> KeyValuesRepo<ToKey, ToValue>.withMapper(
mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue>
): KeyValuesRepo<FromKey, FromValue> = MapperKeyValuesRepo(this, mapper)
/**
* Wraps this [KeyValuesRepo] with inline conversion lambdas to expose a mapped [KeyValuesRepo].
*
* @param FromKey The outer key type
* @param FromValue The outer value type
* @param ToKey The inner key type
* @param ToValue The inner value type
* @param keyFromToTo Converts outer key to inner key; defaults to unchecked cast
* @param valueFromToTo Converts outer value to inner value; defaults to unchecked cast
* @param keyToToFrom Converts inner key to outer key; defaults to unchecked cast
* @param valueToToFrom Converts inner value to outer value; defaults to unchecked cast
* @return [MapperKeyValuesRepo] wrapping this repo
*/
@Suppress("NOTHING_TO_INLINE")
inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> KeyValuesRepo<ToKey, ToValue>.withMapper(
noinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey },

View File

@@ -5,6 +5,17 @@ import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
/**
* Retrieves all key-value pairs from a [ReadKeyValueRepo] by iterating pages starting from [pagination].
* Uses [methodCaller] to fetch each page of keys, then resolves each key to its value via [ReadKeyValueRepo.get].
*
* @param Key The type of keys in the repository
* @param Value The type of values in the repository
* @param REPO The specific repository type
* @param pagination The starting pagination parameters
* @param methodCaller A function that fetches a page of keys from the repository
* @return List of all key-value pairs across all pages; entries with null values are excluded
*/
suspend inline fun <Key, Value, REPO : ReadKeyValueRepo<Key, Value>> REPO.getAll(
pagination: Pagination,
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
@@ -16,6 +27,16 @@ suspend inline fun <Key, Value, REPO : ReadKeyValueRepo<Key, Value>> REPO.getAll
)
}
/**
* Retrieves all key-value pairs from a [ReadKeyValueRepo] by iterating all pages.
* Uses [maxPagePagination] as the starting pagination and [methodCaller] to fetch each page of keys.
*
* @param Key The type of keys in the repository
* @param Value The type of values in the repository
* @param REPO The specific repository type
* @param methodCaller A function that fetches a page of keys from the repository
* @return List of all key-value pairs across all pages; entries with null values are excluded
*/
suspend inline fun <Key, Value, REPO : ReadKeyValueRepo<Key, Value>> REPO.getAll(
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>

View File

@@ -5,6 +5,17 @@ import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
/**
* Retrieves all key-to-list-of-values pairs from a [ReadKeyValuesRepo] by iterating pages starting from [pagination].
* Uses [methodCaller] to fetch each page of keys, then resolves all values per key via [ReadKeyValuesRepo.getAll].
*
* @param Key The type of keys in the repository
* @param Value The type of values associated with keys
* @param REPO The specific repository type
* @param pagination The starting pagination parameters
* @param methodCaller A function that fetches a page of keys from the repository
* @return List of key-to-list-of-values pairs across all pages
*/
suspend inline fun <Key, Value, REPO : ReadKeyValuesRepo<Key, Value>> REPO.getAll(
pagination: Pagination,
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
@@ -18,6 +29,16 @@ suspend inline fun <Key, Value, REPO : ReadKeyValuesRepo<Key, Value>> REPO.getAl
)
}
/**
* Retrieves all key-to-list-of-values pairs from a [ReadKeyValuesRepo] by iterating all pages.
* Uses [maxPagePagination] as the starting pagination and [methodCaller] to fetch each page of keys.
*
* @param Key The type of keys in the repository
* @param Value The type of values associated with keys
* @param REPO The specific repository type
* @param methodCaller A function that fetches a page of keys from the repository
* @return List of key-to-list-of-values pairs across all pages
*/
suspend inline fun <Key, Value, REPO : ReadKeyValuesRepo<Key, Value>> REPO.getAll(
@Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE")
crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key>

View File

@@ -7,4 +7,11 @@ import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import kotlin.js.JsName
import kotlin.jvm.JvmName
/**
* Wraps this [ReadKeyValueRepo] as a [ReadCRUDFromKeyValueRepo], exposing CRUD read operations.
*
* @param K The type of keys (used as IDs in the CRUD repo)
* @param V The type of values (used as objects in the CRUD repo)
* @return [ReadCRUDFromKeyValueRepo] delegating to this repo
*/
fun <K, V> ReadKeyValueRepo<K, V>.asReadCRUDRepo() = ReadCRUDFromKeyValueRepo(this)

View File

@@ -5,6 +5,14 @@ import dev.inmo.micro_utils.pagination.PaginationResult
import dev.inmo.micro_utils.repos.ReadCRUDRepo
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
/**
* Adapter that exposes a [ReadKeyValueRepo] as a [ReadCRUDRepo].
* Maps CRUD read operations to the underlying key-value repository operations.
*
* @param RegisteredType The type of objects stored in the repository
* @param IdType The type of identifiers (keys) used to reference stored objects
* @param original The underlying [ReadKeyValueRepo] to delegate operations to
*/
open class ReadCRUDFromKeyValueRepo<RegisteredType, IdType>(
protected open val original: ReadKeyValueRepo<IdType, RegisteredType>
) : ReadCRUDRepo<RegisteredType, IdType> {

View File

@@ -8,8 +8,32 @@ import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import kotlin.js.JsName
import kotlin.jvm.JvmName
/**
* Wraps this [ReadKeyValuesRepo] as a [ReadKeyValueFromKeyValuesRepo],
* exposing each key mapped to a [List] of all associated values.
*
* @param K The type of keys
* @param V The type of individual values
* @return [ReadKeyValueFromKeyValuesRepo] delegating to this repo
*/
fun <K, V> ReadKeyValuesRepo<K, V>.asReadKeyValueRepo() = ReadKeyValueFromKeyValuesRepo(this)
/**
* Wraps this [KeyValuesRepo] as a [KeyValueFromKeyValuesRepo],
* exposing a full read-write key-value interface where each key maps to a [List] of values.
*
* @param K The type of keys
* @param V The type of individual values
* @return [KeyValueFromKeyValuesRepo] delegating to this repo
*/
fun <K, V> KeyValuesRepo<K, V>.asKeyValueRepo() = KeyValueFromKeyValuesRepo(this)
/**
* Wraps this [ReadCRUDRepo] as a [ReadKeyValueFromCRUDRepo],
* exposing CRUD IDs as keys and CRUD objects as values in a [ReadKeyValueRepo].
*
* @param K The type of CRUD IDs (used as keys)
* @param V The type of CRUD objects (used as values)
* @return [ReadKeyValueFromCRUDRepo] delegating to this repo
*/
fun <K, V> ReadCRUDRepo<K, V>.asReadKeyValueRepo() = ReadKeyValueFromCRUDRepo(this)

View File

@@ -18,6 +18,16 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.merge
/**
* Full read-write adapter that exposes a [KeyValuesRepo] as a [KeyValueRepo] mapping each key to a [List] of values.
* Extends [ReadKeyValueFromKeyValuesRepo] with write operations delegated to the underlying [KeyValuesRepo].
* [onNewValue] merges [KeyValuesRepo.onNewValue] and [KeyValuesRepo.onValueRemoved] and emits the updated list per key;
* [onValueRemoved] mirrors [KeyValuesRepo.onDataCleared].
*
* @param Key The type of keys
* @param Value The type of individual values in the one-to-many repo
* @param original The underlying [KeyValuesRepo] to delegate operations to
*/
open class KeyValueFromKeyValuesRepo<Key, Value>(
private val original: KeyValuesRepo<Key, Value>
) : KeyValueRepo<Key, List<Value>>, ReadKeyValueFromKeyValuesRepo<Key, Value>(original) {

View File

@@ -15,6 +15,15 @@ import dev.inmo.micro_utils.repos.pagination.getAll
import dev.inmo.micro_utils.repos.transforms.kvs.ReadKeyValuesFromKeyValueRepo
import kotlin.jvm.JvmInline
/**
* Inline value class adapter that exposes a [ReadCRUDRepo] as a [ReadKeyValueRepo].
* Maps key-value read operations to the underlying CRUD repository operations,
* treating CRUD IDs as keys and CRUD objects as values.
*
* @param Key The type of keys (maps to [ReadCRUDRepo] ID type)
* @param Value The type of values (maps to [ReadCRUDRepo] object type)
* @param original The underlying [ReadCRUDRepo] to delegate operations to
*/
@JvmInline
value class ReadKeyValueFromCRUDRepo<Key, Value>(
private val original: ReadCRUDRepo<Value, Key>

View File

@@ -12,6 +12,14 @@ import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import dev.inmo.micro_utils.repos.transforms.kvs.ReadKeyValuesFromKeyValueRepo
/**
* Adapter that exposes a [ReadKeyValuesRepo] as a [ReadKeyValueRepo] mapping each key to a [List] of values.
* Each key's associated list of values is retrieved via [ReadKeyValuesRepo.getAll].
*
* @param Key The type of keys
* @param Value The type of individual values in the one-to-many repo
* @param original The underlying [ReadKeyValuesRepo] to delegate operations to
*/
open class ReadKeyValueFromKeyValuesRepo<Key, Value>(
private val original: ReadKeyValuesRepo<Key, Value>
) : ReadKeyValueRepo<Key, List<Value>> {

View File

@@ -5,17 +5,51 @@ import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import kotlin.js.JsName
import kotlin.jvm.JvmName
/**
* Wraps this [ReadKeyValueRepo] (mapping keys to iterables) as a [ReadKeyValuesFromKeyValueRepo],
* exposing a one-to-many read interface.
*
* @param K The type of keys
* @param V The type of individual values within each iterable
* @param VI The iterable type storing multiple values per key
* @return [ReadKeyValuesFromKeyValueRepo] delegating to this repo
*/
fun <K, V, VI : Iterable<V>> ReadKeyValueRepo<K, VI>.asReadKeyValuesRepo() = ReadKeyValuesFromKeyValueRepo(this)
/**
* Wraps this [KeyValueRepo] (mapping keys to iterables) as a [KeyValuesFromKeyValueRepo],
* exposing a full one-to-many read-write interface.
*
* @param K The type of keys
* @param V The type of individual values within each iterable
* @param VI The iterable type storing multiple values per key
* @param listToValuesIterable Converter from [List] of values to [VI] used when persisting changes
* @return [KeyValuesFromKeyValueRepo] delegating to this repo
*/
fun <K, V, VI : Iterable<V>> KeyValueRepo<K, VI>.asKeyValuesRepo(
listToValuesIterable: suspend (List<V>) -> VI
): KeyValuesFromKeyValueRepo<K, V, VI> = KeyValuesFromKeyValueRepo(this, listToValuesIterable)
/**
* Wraps this [KeyValueRepo] (mapping keys to [List]s) as a [KeyValuesFromKeyValueRepo].
* Uses identity conversion for the list iterable.
*
* @param K The type of keys
* @param V The type of individual values
* @return [KeyValuesFromKeyValueRepo] delegating to this repo with [List] as the iterable type
*/
@JvmName("asListKeyValuesRepo")
@JsName("asListKeyValuesRepo")
fun <K, V> KeyValueRepo<K, List<V>>.asKeyValuesRepo(): KeyValuesFromKeyValueRepo<K, V, List<V>> = asKeyValuesRepo { it }
/**
* Wraps this [KeyValueRepo] (mapping keys to [Set]s) as a [KeyValuesFromKeyValueRepo].
* Converts lists to sets when persisting changes, ensuring value uniqueness per key.
*
* @param K The type of keys
* @param V The type of individual values
* @return [KeyValuesFromKeyValueRepo] delegating to this repo with [Set] as the iterable type
*/
@JvmName("asSetKeyValuesRepo")
@JsName("asSetKeyValuesRepo")
fun <K, V> KeyValueRepo<K, Set<V>>.asKeyValuesRepo(): KeyValuesFromKeyValueRepo<K, V, Set<V>> = asKeyValuesRepo { it.toSet() }

View File

@@ -12,6 +12,17 @@ import kotlinx.coroutines.flow.asSharedFlow
import kotlin.js.JsName
import kotlin.jvm.JvmName
/**
* Full read-write adapter that exposes a [KeyValueRepo] storing iterables as a [KeyValuesRepo].
* Extends [ReadKeyValuesFromKeyValueRepo] with write operations: add, remove, clear.
* Emits [onNewValue] and [onValueRemoved] for individual value changes; [onDataCleared] mirrors [KeyValueRepo.onValueRemoved].
*
* @param Key The type of keys
* @param Value The type of individual values within each iterable
* @param ValuesIterable The iterable type storing multiple values per key
* @param original The underlying [KeyValueRepo] mapping keys to iterables of values
* @param listToValuesIterable Converter from [List] of values to [ValuesIterable] used when persisting changes
*/
open class KeyValuesFromKeyValueRepo<Key, Value, ValuesIterable : Iterable<Value>>(
private val original: KeyValueRepo<Key, ValuesIterable>,
private val listToValuesIterable: suspend (List<Value>) -> ValuesIterable

View File

@@ -11,6 +11,15 @@ import dev.inmo.micro_utils.pagination.utils.paginate
import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
/**
* Adapter that exposes a [ReadKeyValueRepo] storing iterables as a [ReadKeyValuesRepo].
* Each key maps to a [ValuesIterable] in the underlying repo, which is exposed as a one-to-many relationship.
*
* @param Key The type of keys
* @param Value The type of individual values within each iterable
* @param ValuesIterable The iterable type storing multiple values per key
* @param original The underlying [ReadKeyValueRepo] mapping keys to iterables of values
*/
open class ReadKeyValuesFromKeyValueRepo<Key, Value, ValuesIterable : Iterable<Value>>(
private val original: ReadKeyValueRepo<Key, ValuesIterable>
) : ReadKeyValuesRepo<Key, Value> {

View File

@@ -3,6 +3,14 @@ package dev.inmo.micro_utils.repos.versions
import dev.inmo.micro_utils.repos.KeyValueRepo
import dev.inmo.micro_utils.repos.set
/**
* [StandardVersionsRepoProxy] implementation backed by a [KeyValueRepo] mapping table names to version numbers.
* Stores and retrieves per-table version integers using [keyValueStore] with table names as keys.
*
* @param T The type of the underlying database or storage object
* @param keyValueStore [KeyValueRepo] used to persist table-name-to-version mappings
* @param database The underlying database or storage object exposed via [StandardVersionsRepoProxy.database]
*/
class KeyValueBasedVersionsRepoProxy<T>(
private val keyValueStore: KeyValueRepo<String, Int>,
override val database: T

View File

@@ -2,13 +2,43 @@ package dev.inmo.micro_utils.repos.versions
import dev.inmo.micro_utils.repos.Repo
/**
* Proxy interface providing low-level access to a versioned database [T].
* Implementations store and retrieve per-table version numbers using a backing storage.
*
* @param T The type of the underlying database or storage object
*/
interface StandardVersionsRepoProxy<T> : Repo {
/**
* The underlying database or storage object used for version tracking.
*/
val database: T
/**
* Returns the current version number for the given [tableName], or null if no version is stored.
*
* @param tableName Name of the table whose version to retrieve
* @return Stored version number, or null if the table has not been versioned yet
*/
suspend fun getTableVersion(tableName: String): Int?
/**
* Persists the given [version] number for the given [tableName].
*
* @param tableName Name of the table whose version to update
* @param version New version number to store
*/
suspend fun updateTableVersion(tableName: String, version: Int)
}
/**
* Standard implementation of [VersionsRepo] that delegates version storage to a [StandardVersionsRepoProxy].
* On [setTableVersion]: calls [StandardVersionsRepoProxy.database].[onCreate] if the table has no version yet,
* then iterates [onUpdate] for each version step until the target [version] is reached.
*
* @param T The type of the underlying database or storage object
* @param proxy The [StandardVersionsRepoProxy] used to read and write version numbers
*/
class StandardVersionsRepo<T>(
private val proxy: StandardVersionsRepoProxy<T>
) : VersionsRepo<T> {
@@ -30,4 +60,4 @@ class StandardVersionsRepo<T>(
proxy.updateTableVersion(tableName, currentVersion)
}
}
}
}