mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-10-30 11:40:25 +00:00 
			
		
		
		
	Compare commits
	
		
			46 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| cd22d76fa7 | |||
| c8759843f7 | |||
| 781bbcc012 | |||
| 6da29c0686 | |||
| fcdb6fc45a | |||
| e785a99bd7 | |||
| 121e513fdd | |||
| 9cf01ab54f | |||
| c655107681 | |||
| 91a5af6a9a | |||
| 86e74c0a6f | |||
| d8f01f21a0 | |||
| 9fb8626d8c | |||
| 1c52e04cdb | |||
| 798128256e | |||
| 72c2df47fd | |||
| c9c6d4c0c1 | |||
| 2f4f9f3003 | |||
| 22e8f8e5d6 | |||
| 04cf8c3d9a | |||
| 52198be543 | |||
| 80fd5a489b | |||
| b187043ee1 | |||
| 8965752055 | |||
| b796620267 | |||
| 62df81bb4e | |||
| 0a8e0f6178 | |||
| f705020aaa | |||
| 78bd3b9853 | |||
| 992b283597 | |||
| 8fc1ff1d59 | |||
| 3bbde61f39 | |||
| 8d955c4b9d | |||
| 18593c530b | |||
| 78903cd4eb | |||
| eaa143f7d7 | |||
| bcb0e42fa2 | |||
| 8eed435302 | |||
| 0e4a63057f | |||
| 1af5faa440 | |||
| 7412217b0c | |||
| 3e749d75b7 | |||
| 846b5c87c9 | |||
| 7b5e84f80b | |||
| 27822a8a66 | |||
| 36f4e7ec37 | 
							
								
								
									
										60
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,5 +1,65 @@ | |||||||
| # Changelog | # Changelog | ||||||
|  |  | ||||||
|  | ## 0.11.6 | ||||||
|  |  | ||||||
|  | * `FSM`: | ||||||
|  |   * `Common` | ||||||
|  |     * Several fixes related to the jobs handling | ||||||
|  |  | ||||||
|  | ## 0.11.5 | ||||||
|  |  | ||||||
|  | * `Coroutines`: | ||||||
|  |   * `Compose`: | ||||||
|  |     * Add extension `StateFlow#asMutableComposeListState` and `StateFlow#asComposeList` | ||||||
|  |     * Add extension `StateFlow#asMutableComposeState`/`StateFlow#asComposeState` | ||||||
|  |  | ||||||
|  | ## 0.11.4 | ||||||
|  |  | ||||||
|  | **THIS VERSION HAS BEEN BROKEN, DO NOT USE IT** | ||||||
|  |  | ||||||
|  | ## 0.11.3 | ||||||
|  |  | ||||||
|  | * `Ktor`: | ||||||
|  |     * Support of `WebSockets` has been improved | ||||||
|  |       * `Client`: | ||||||
|  |         * New extensions: `HttpClient#openBaseWebSocketFlow`, `HttpClient#openWebSocketFlow`, `HttpClient#openSecureWebSocketFlow` | ||||||
|  |  | ||||||
|  | ## 0.11.2 | ||||||
|  |  | ||||||
|  | * `Ktor`: | ||||||
|  |   * Support of `WebSockets` has been improved and added fixes inside of clients | ||||||
|  |  | ||||||
|  | ## 0.11.1 | ||||||
|  |  | ||||||
|  | * `Repos` | ||||||
|  |   * `Ktor` | ||||||
|  |     * In `configureReadKeyValueRepoRoutes` and `configureReadKeyValuesRepoRoutes` configurators fixed requiring of `reversed` property | ||||||
|  |  | ||||||
|  | ## 0.11.0 | ||||||
|  |  | ||||||
|  | * `Versions` | ||||||
|  |     * `UUID`: `0.4.0` -> `0.4.1` | ||||||
|  | * `Ktor` | ||||||
|  |   * `Client`: | ||||||
|  |     * New extension fun `HttpResponse#throwOnUnsuccess` | ||||||
|  |     * All old functions, classes and extensions has been rewritten with new ktor-way with types info and keeping `ContentNegotiation` in mind | ||||||
|  |   * `Server`: | ||||||
|  |       * All old functions, classes and extensions has been rewritten with new ktor-way with types info and keeping `ContentNegotiation` in mind | ||||||
|  | * `Repos` | ||||||
|  |   * `Ktor`: | ||||||
|  |     * Fully rewritten work with all declared repositories | ||||||
|  |     * All old functions, classes and extensions has been rewritten with new ktor-way with types info and keeping `ContentNegotiation` in mind | ||||||
|  |  | ||||||
|  | ## 0.10.8 | ||||||
|  |  | ||||||
|  | * `Common` | ||||||
|  |     * Add `Element.isOverflow*` extension properties | ||||||
|  |  | ||||||
|  | ## 0.10.7 | ||||||
|  |  | ||||||
|  | * `Pagination`: | ||||||
|  |     * Now it is possible to use `doForAll*` and `getForAll` functions in non suspend places | ||||||
|  |  | ||||||
| ## 0.10.6 | ## 0.10.6 | ||||||
|  |  | ||||||
| * `Versions` | * `Versions` | ||||||
|   | |||||||
| @@ -0,0 +1,12 @@ | |||||||
|  | package dev.inmo.micro_utils.common | ||||||
|  |  | ||||||
|  | import org.w3c.dom.Element | ||||||
|  |  | ||||||
|  | inline val Element.isOverflowWidth | ||||||
|  |     get() = scrollWidth > clientWidth | ||||||
|  |  | ||||||
|  | inline val Element.isOverflowHeight | ||||||
|  |     get() = scrollHeight > clientHeight | ||||||
|  |  | ||||||
|  | inline val Element.isOverflow | ||||||
|  |     get() = isOverflowHeight || isOverflowWidth | ||||||
| @@ -0,0 +1,26 @@ | |||||||
|  | package dev.inmo.micro_utils.coroutines.compose | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.* | ||||||
|  | import androidx.compose.runtime.snapshots.SnapshotStateList | ||||||
|  | import dev.inmo.micro_utils.common.applyDiff | ||||||
|  | import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions | ||||||
|  | import kotlinx.coroutines.CoroutineScope | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import kotlinx.coroutines.flow.StateFlow | ||||||
|  |  | ||||||
|  | @Suppress("NOTHING_TO_INLINE") | ||||||
|  | inline fun <reified T> Flow<List<T>>.asMutableComposeListState( | ||||||
|  |     scope: CoroutineScope | ||||||
|  | ): SnapshotStateList<T> { | ||||||
|  |     val state = mutableStateListOf<T>() | ||||||
|  |     subscribeSafelyWithoutExceptions(scope) { | ||||||
|  |         state.applyDiff(it) | ||||||
|  |     } | ||||||
|  |     return state | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Suppress("NOTHING_TO_INLINE") | ||||||
|  | inline fun <reified T> Flow<List<T>>.asComposeList( | ||||||
|  |     scope: CoroutineScope | ||||||
|  | ): List<T> = asMutableComposeListState(scope) | ||||||
|  |  | ||||||
| @@ -0,0 +1,35 @@ | |||||||
|  | package dev.inmo.micro_utils.coroutines.compose | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.* | ||||||
|  | import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions | ||||||
|  | import kotlinx.coroutines.CoroutineScope | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import kotlinx.coroutines.flow.StateFlow | ||||||
|  |  | ||||||
|  | fun <T> Flow<T>.asMutableComposeState( | ||||||
|  |     initial: T, | ||||||
|  |     scope: CoroutineScope | ||||||
|  | ): MutableState<T> { | ||||||
|  |     val state = mutableStateOf(initial) | ||||||
|  |     subscribeSafelyWithoutExceptions(scope) { state.value = it } | ||||||
|  |     return state | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Suppress("NOTHING_TO_INLINE") | ||||||
|  | inline fun <T> StateFlow<T>.asMutableComposeState( | ||||||
|  |     scope: CoroutineScope | ||||||
|  | ): MutableState<T> = asMutableComposeState(value, scope) | ||||||
|  |  | ||||||
|  | fun <T> Flow<T>.asComposeState( | ||||||
|  |     initial: T, | ||||||
|  |     scope: CoroutineScope | ||||||
|  | ): State<T> { | ||||||
|  |     val state = asMutableComposeState(initial, scope) | ||||||
|  |     return derivedStateOf { state.value } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Suppress("NOTHING_TO_INLINE") | ||||||
|  | inline fun <T> StateFlow<T>.asComposeState( | ||||||
|  |     scope: CoroutineScope | ||||||
|  | ): State<T> = asComposeState(value, scope) | ||||||
|  |  | ||||||
| @@ -6,6 +6,7 @@ import dev.inmo.micro_utils.coroutines.* | |||||||
| import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler | import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler | ||||||
| import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler | import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler | ||||||
| import kotlinx.coroutines.* | import kotlinx.coroutines.* | ||||||
|  | import kotlinx.coroutines.flow.asFlow | ||||||
| import kotlinx.coroutines.sync.Mutex | import kotlinx.coroutines.sync.Mutex | ||||||
| import kotlinx.coroutines.sync.withLock | import kotlinx.coroutines.sync.withLock | ||||||
|  |  | ||||||
| @@ -85,10 +86,10 @@ open class DefaultStatesMachine <T: State>( | |||||||
|  |  | ||||||
|     protected open suspend fun performUpdate(state: T) { |     protected open suspend fun performUpdate(state: T) { | ||||||
|         val newState = launchStateHandling(state, handlers) |         val newState = launchStateHandling(state, handlers) | ||||||
|         if (newState != null) { |         if (newState == null) { | ||||||
|             statesManager.update(state, newState) |  | ||||||
|         } else { |  | ||||||
|             statesManager.endChain(state) |             statesManager.endChain(state) | ||||||
|  |         } else { | ||||||
|  |             statesManager.update(state, newState) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -118,7 +119,7 @@ open class DefaultStatesMachine <T: State>( | |||||||
|      * [StatesManager.endChain]. |      * [StatesManager.endChain]. | ||||||
|      */ |      */ | ||||||
|     override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions { |     override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions { | ||||||
|         statesManager.onStartChain.subscribeSafelyWithoutExceptions(this) { |         (statesManager.getActiveStates().asFlow() + statesManager.onStartChain).subscribeSafelyWithoutExceptions(this) { | ||||||
|             launch { performStateUpdate(Optional.absent(), it, scope.LinkedSupervisorScope()) } |             launch { performStateUpdate(Optional.absent(), it, scope.LinkedSupervisorScope()) } | ||||||
|         } |         } | ||||||
|         statesManager.onChainStateUpdated.subscribeSafelyWithoutExceptions(this) { |         statesManager.onChainStateUpdated.subscribeSafelyWithoutExceptions(this) { | ||||||
| @@ -134,10 +135,6 @@ open class DefaultStatesMachine <T: State>( | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         statesManager.getActiveStates().forEach { |  | ||||||
|             launch { performStateUpdate(Optional.absent(), it, scope.LinkedSupervisorScope()) } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -52,6 +52,7 @@ open class DefaultUpdatableStatesMachine<T : State>( | |||||||
|                             statesJobs.remove( |                             statesJobs.remove( | ||||||
|                                 jobsStates[job] ?: return@withLock |                                 jobsStates[job] ?: return@withLock | ||||||
|                             ) |                             ) | ||||||
|  |                             jobsStates.remove(job) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|   | |||||||
| @@ -14,5 +14,5 @@ crypto_js_version=4.1.1 | |||||||
| # Project data | # Project data | ||||||
|  |  | ||||||
| group=dev.inmo | group=dev.inmo | ||||||
| version=0.10.6 | version=0.11.6 | ||||||
| android_code_version=121 | android_code_version=130 | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ jb-exposed = "0.38.2" | |||||||
| jb-dokka = "1.6.21" | jb-dokka = "1.6.21" | ||||||
|  |  | ||||||
| klock = "2.7.0" | klock = "2.7.0" | ||||||
| uuid = "0.4.0" | uuid = "0.4.1" | ||||||
|  |  | ||||||
| ktor = "2.0.2" | ktor = "2.0.2" | ||||||
|  |  | ||||||
| @@ -37,17 +37,24 @@ kt-serialization-cbor = { module = "org.jetbrains.kotlinx:kotlinx-serialization- | |||||||
|  |  | ||||||
| kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kt-coroutines" } | kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kt-coroutines" } | ||||||
| kt-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kt-coroutines" } | kt-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kt-coroutines" } | ||||||
|  | kt-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kt-coroutines" } | ||||||
|  |  | ||||||
|  |  | ||||||
| ktor-io = { module = "io.ktor:ktor-io", version.ref = "ktor" } | ktor-io = { module = "io.ktor:ktor-io", version.ref = "ktor" } | ||||||
|  | ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } | ||||||
| ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } | ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } | ||||||
|  | ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" } | ||||||
| ktor-client-java = { module = "io.ktor:ktor-client-java", version.ref = "ktor" } | ktor-client-java = { module = "io.ktor:ktor-client-java", version.ref = "ktor" } | ||||||
|  | ktor-client-websockets = { module = "io.ktor:ktor-client-websockets", version.ref = "ktor" } | ||||||
|  | ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" } | ||||||
|  | ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } | ||||||
| ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" } | ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" } | ||||||
| ktor-server-cio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor" } | ktor-server-cio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor" } | ||||||
| ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" } | ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" } | ||||||
| ktor-websockets = { module = "io.ktor:ktor-websockets", version.ref = "ktor" } | ktor-websockets = { module = "io.ktor:ktor-websockets", version.ref = "ktor" } | ||||||
| ktor-server-websockets = { module = "io.ktor:ktor-server-websockets", version.ref = "ktor" } | ktor-server-websockets = { module = "io.ktor:ktor-server-websockets", version.ref = "ktor" } | ||||||
| ktor-server-statusPages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" } | ktor-server-statusPages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" } | ||||||
|  | ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negotiation", version.ref = "ktor" } | ||||||
|  |  | ||||||
|  |  | ||||||
| klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" } | klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" } | ||||||
|   | |||||||
| @@ -0,0 +1,15 @@ | |||||||
|  | package dev.inmo.micro_utils.ktor.client | ||||||
|  |  | ||||||
|  | import io.ktor.client.plugins.ClientRequestException | ||||||
|  | import io.ktor.client.statement.HttpResponse | ||||||
|  | import io.ktor.http.isSuccess | ||||||
|  |  | ||||||
|  | inline fun HttpResponse.throwOnUnsuccess( | ||||||
|  |     unsuccessMessage: () -> String | ||||||
|  | ) { | ||||||
|  |     if (status.isSuccess()) { | ||||||
|  |         return | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     throw ClientRequestException(this, unsuccessMessage()) | ||||||
|  | } | ||||||
| @@ -0,0 +1,103 @@ | |||||||
|  | package dev.inmo.micro_utils.ktor.client | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.common.Warning | ||||||
|  | import dev.inmo.micro_utils.coroutines.runCatchingSafely | ||||||
|  | import dev.inmo.micro_utils.coroutines.safely | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.client.plugins.pluginOrNull | ||||||
|  | import io.ktor.client.plugins.websocket.* | ||||||
|  | import io.ktor.client.request.HttpRequestBuilder | ||||||
|  | import io.ktor.http.URLProtocol | ||||||
|  | import kotlinx.coroutines.channels.SendChannel | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import kotlinx.coroutines.flow.channelFlow | ||||||
|  | import kotlinx.coroutines.isActive | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish | ||||||
|  |  * connection. Must return true in case if must be reconnected. By default always reconnecting | ||||||
|  |  */ | ||||||
|  | @Warning("This feature is internal and should not be used directly. It is can be changed without any notification and warranty on compile-time or other guaranties") | ||||||
|  | inline fun <reified T : Any> openBaseWebSocketFlow( | ||||||
|  |     noinline checkReconnection: suspend (Throwable?) -> Boolean = { true }, | ||||||
|  |     noinline webSocketSessionRequest: suspend SendChannel<T>.() -> Unit | ||||||
|  | ): Flow<T> { | ||||||
|  |     return channelFlow { | ||||||
|  |         do { | ||||||
|  |             val reconnect = runCatchingSafely { | ||||||
|  |                 webSocketSessionRequest() | ||||||
|  |                 checkReconnection(null) | ||||||
|  |             }.getOrElse { e -> | ||||||
|  |                 checkReconnection(e).also { | ||||||
|  |                     if (!it) { | ||||||
|  |                         close(e) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } while (reconnect && isActive) | ||||||
|  |  | ||||||
|  |         if (isActive) { | ||||||
|  |             safely { | ||||||
|  |                 close() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish | ||||||
|  |  * connection. Must return true in case if must be reconnected. By default always reconnecting | ||||||
|  |  */ | ||||||
|  | inline fun <reified T : Any> HttpClient.openWebSocketFlow( | ||||||
|  |     url: String, | ||||||
|  |     useSecureConnection: Boolean, | ||||||
|  |     noinline checkReconnection: suspend (Throwable?) -> Boolean = { true }, | ||||||
|  |     noinline requestBuilder: HttpRequestBuilder.() -> Unit = {} | ||||||
|  | ): Flow<T> { | ||||||
|  |     pluginOrNull(WebSockets) ?: error("Plugin $WebSockets must be installed for using createStandardWebsocketFlow") | ||||||
|  |  | ||||||
|  |     return openBaseWebSocketFlow<T>(checkReconnection) { | ||||||
|  |         val block: suspend DefaultClientWebSocketSession.() -> Unit = { | ||||||
|  |             while (isActive) { | ||||||
|  |                 send(receiveDeserialized<T>()) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (useSecureConnection) { | ||||||
|  |             wss(url, requestBuilder, block) | ||||||
|  |         } else { | ||||||
|  |             ws(url, requestBuilder, block) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish | ||||||
|  |  * connection. Must return true in case if must be reconnected. By default always reconnecting | ||||||
|  |  */ | ||||||
|  | inline fun <reified T : Any> HttpClient.openWebSocketFlow( | ||||||
|  |     url: String, | ||||||
|  |     noinline checkReconnection: suspend (Throwable?) -> Boolean = { true }, | ||||||
|  |     noinline requestBuilder: HttpRequestBuilder.() -> Unit = {} | ||||||
|  | ): Flow<T> = openWebSocketFlow(url, false, checkReconnection, requestBuilder) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish | ||||||
|  |  * connection. Must return true in case if must be reconnected. By default always reconnecting | ||||||
|  |  */ | ||||||
|  | inline fun <reified T : Any> HttpClient.openSecureWebSocketFlow( | ||||||
|  |     url: String, | ||||||
|  |     noinline checkReconnection: suspend (Throwable?) -> Boolean = { true }, | ||||||
|  |     noinline requestBuilder: HttpRequestBuilder.() -> Unit = {} | ||||||
|  | ): Flow<T> = openWebSocketFlow(url, true, checkReconnection, requestBuilder) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish | ||||||
|  |  * connection. Must return true in case if must be reconnected. By default always reconnecting | ||||||
|  |  */ | ||||||
|  | inline fun <reified T : Any> HttpClient.createStandardWebsocketFlow( | ||||||
|  |     url: String, | ||||||
|  |     noinline checkReconnection: suspend (Throwable?) -> Boolean = { true }, | ||||||
|  |     noinline requestBuilder: HttpRequestBuilder.() -> Unit = {} | ||||||
|  | ): Flow<T> = openWebSocketFlow(url, checkReconnection, requestBuilder) | ||||||
| @@ -4,7 +4,10 @@ import dev.inmo.micro_utils.common.MPPFile | |||||||
| import dev.inmo.micro_utils.ktor.common.TemporalFileId | import dev.inmo.micro_utils.ktor.common.TemporalFileId | ||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import kotlinx.coroutines.* | import kotlinx.coroutines.* | ||||||
|  | import org.w3c.dom.mediasource.ENDED | ||||||
|  | import org.w3c.dom.mediasource.ReadyState | ||||||
| import org.w3c.xhr.* | import org.w3c.xhr.* | ||||||
|  | import org.w3c.xhr.XMLHttpRequest.Companion.DONE | ||||||
|  |  | ||||||
| suspend fun tempUpload( | suspend fun tempUpload( | ||||||
|     fullTempUploadDraftPath: String, |     fullTempUploadDraftPath: String, | ||||||
| @@ -12,7 +15,7 @@ suspend fun tempUpload( | |||||||
|     onUpload: (Long, Long) -> Unit |     onUpload: (Long, Long) -> Unit | ||||||
| ): TemporalFileId { | ): TemporalFileId { | ||||||
|     val formData = FormData() |     val formData = FormData() | ||||||
|     val answer = CompletableDeferred<TemporalFileId>() |     val answer = CompletableDeferred<TemporalFileId>(currentCoroutineContext().job) | ||||||
|  |  | ||||||
|     formData.append( |     formData.append( | ||||||
|         "data", |         "data", | ||||||
| @@ -37,17 +40,15 @@ suspend fun tempUpload( | |||||||
|     request.open("POST", fullTempUploadDraftPath, true) |     request.open("POST", fullTempUploadDraftPath, true) | ||||||
|     request.send(formData) |     request.send(formData) | ||||||
|  |  | ||||||
|     val handle = currentCoroutineContext().job.invokeOnCompletion { |     answer.invokeOnCompletion { | ||||||
|         runCatching { |         runCatching { | ||||||
|  |             if (request.readyState != DONE) { | ||||||
|                 request.abort() |                 request.abort() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return runCatching { |     return answer.await() | ||||||
|         answer.await() |  | ||||||
|     }.also { |  | ||||||
|         handle.dispose() |  | ||||||
|     }.getOrThrow() |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,15 @@ | |||||||
|  | package dev.inmo.micro_utils.ktor.server | ||||||
|  |  | ||||||
|  | import io.ktor.server.application.ApplicationCall | ||||||
|  | import io.ktor.server.response.responseType | ||||||
|  | import io.ktor.util.InternalAPI | ||||||
|  | import io.ktor.util.reflect.TypeInfo | ||||||
|  |  | ||||||
|  | @InternalAPI | ||||||
|  | suspend fun <T : Any> ApplicationCall.respond( | ||||||
|  |     message: T, | ||||||
|  |     typeInfo: TypeInfo | ||||||
|  | ) { | ||||||
|  |     response.responseType = typeInfo | ||||||
|  |     response.pipeline.execute(this, message as Any) | ||||||
|  | } | ||||||
| @@ -12,6 +12,7 @@ import io.ktor.websocket.send | |||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.serialization.SerializationStrategy | import kotlinx.serialization.SerializationStrategy | ||||||
|  |  | ||||||
|  | @Deprecated("This method will be removed soon") | ||||||
| fun <T> Route.includeWebsocketHandling( | fun <T> Route.includeWebsocketHandling( | ||||||
|     suburl: String, |     suburl: String, | ||||||
|     flow: Flow<T>, |     flow: Flow<T>, | ||||||
|   | |||||||
| @@ -0,0 +1,31 @@ | |||||||
|  | package dev.inmo.micro_utils.ktor.server | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.coroutines.safely | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import io.ktor.http.URLProtocol | ||||||
|  | import io.ktor.server.application.install | ||||||
|  | import io.ktor.server.application.pluginOrNull | ||||||
|  | import io.ktor.server.routing.Route | ||||||
|  | import io.ktor.server.routing.application | ||||||
|  | import io.ktor.server.websocket.* | ||||||
|  | import io.ktor.websocket.send | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  | import kotlinx.serialization.SerializationStrategy | ||||||
|  |  | ||||||
|  | inline fun <reified T : Any> Route.includeWebsocketHandling( | ||||||
|  |     suburl: String, | ||||||
|  |     flow: Flow<T>, | ||||||
|  |     protocol: URLProtocol? = null, | ||||||
|  |     noinline dataMapper: suspend WebSocketServerSession.(T) -> T? = { it } | ||||||
|  | ) { | ||||||
|  |     application.apply { | ||||||
|  |         pluginOrNull(WebSockets) ?: install(WebSockets) | ||||||
|  |     } | ||||||
|  |     webSocket(suburl, protocol ?.name) { | ||||||
|  |         safely { | ||||||
|  |             flow.collect { | ||||||
|  |                 sendSerialized(dataMapper(it) ?: return@collect) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -13,6 +13,7 @@ import io.ktor.http.content.streamProvider | |||||||
| import io.ktor.server.application.call | import io.ktor.server.application.call | ||||||
| import io.ktor.server.request.receiveMultipart | import io.ktor.server.request.receiveMultipart | ||||||
| import io.ktor.server.response.respond | import io.ktor.server.response.respond | ||||||
|  | import io.ktor.server.response.respondText | ||||||
| import io.ktor.server.routing.Route | import io.ktor.server.routing.Route | ||||||
| import io.ktor.server.routing.post | import io.ktor.server.routing.post | ||||||
| import kotlinx.coroutines.* | import kotlinx.coroutines.* | ||||||
| @@ -111,7 +112,7 @@ class TemporalFilesRoutingConfigurator( | |||||||
|                     temporalFilesMutex.withLock { |                     temporalFilesMutex.withLock { | ||||||
|                         temporalFilesMap[fileId] = file |                         temporalFilesMap[fileId] = file | ||||||
|                     } |                     } | ||||||
|                     call.respond(fileId.string) |                     call.respondText(fileId.string) | ||||||
|                     launchSafelyWithoutExceptions { filesFlow.emit(fileId) } |                     launchSafelyWithoutExceptions { filesFlow.emit(fileId) } | ||||||
|                 } ?: call.respond(HttpStatusCode.BadRequest) |                 } ?: call.respond(HttpStatusCode.BadRequest) | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -2,19 +2,19 @@ package dev.inmo.micro_utils.pagination.utils | |||||||
|  |  | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
|  |  | ||||||
| suspend fun <T> doForAll( | inline fun <T> doForAll( | ||||||
|     initialPagination: Pagination = FirstPagePagination(), |     initialPagination: Pagination = FirstPagePagination(), | ||||||
|     paginationMapper: (PaginationResult<T>) -> Pagination?, |     paginationMapper: (PaginationResult<T>) -> Pagination?, | ||||||
|     block: suspend (Pagination) -> PaginationResult<T> |     block: (Pagination) -> PaginationResult<T> | ||||||
| ) { | ) { | ||||||
|     doWithPagination(initialPagination) { |     doWithPagination(initialPagination) { | ||||||
|         block(it).let(paginationMapper) |         block(it).let(paginationMapper) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| suspend fun <T> doForAllWithNextPaging( | inline fun <T> doForAllWithNextPaging( | ||||||
|     initialPagination: Pagination = FirstPagePagination(), |     initialPagination: Pagination = FirstPagePagination(), | ||||||
|     block: suspend (Pagination) -> PaginationResult<T> |     block: (Pagination) -> PaginationResult<T> | ||||||
| ) { | ) { | ||||||
|     doForAll( |     doForAll( | ||||||
|         initialPagination, |         initialPagination, | ||||||
| @@ -23,9 +23,9 @@ suspend fun <T> doForAllWithNextPaging( | |||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
| suspend fun <T> doAllWithCurrentPaging( | inline fun <T> doAllWithCurrentPaging( | ||||||
|     initialPagination: Pagination = FirstPagePagination(), |     initialPagination: Pagination = FirstPagePagination(), | ||||||
|     block: suspend (Pagination) -> PaginationResult<T> |     block: (Pagination) -> PaginationResult<T> | ||||||
| ) { | ) { | ||||||
|     doForAll( |     doForAll( | ||||||
|         initialPagination, |         initialPagination, | ||||||
| @@ -34,7 +34,7 @@ suspend fun <T> doAllWithCurrentPaging( | |||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
| suspend fun <T> doForAllWithCurrentPaging( | inline fun <T> doForAllWithCurrentPaging( | ||||||
|     initialPagination: Pagination = FirstPagePagination(), |     initialPagination: Pagination = FirstPagePagination(), | ||||||
|     block: suspend (Pagination) -> PaginationResult<T> |     block: (Pagination) -> PaginationResult<T> | ||||||
| ) = doAllWithCurrentPaging(initialPagination, block) | ) = doAllWithCurrentPaging(initialPagination, block) | ||||||
|   | |||||||
| @@ -2,10 +2,10 @@ package dev.inmo.micro_utils.pagination.utils | |||||||
|  |  | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
|  |  | ||||||
| suspend fun <T> getAll( | inline fun <T> getAll( | ||||||
|     initialPagination: Pagination = FirstPagePagination(), |     initialPagination: Pagination = FirstPagePagination(), | ||||||
|     paginationMapper: (PaginationResult<T>) -> Pagination?, |     paginationMapper: (PaginationResult<T>) -> Pagination?, | ||||||
|     block: suspend (Pagination) -> PaginationResult<T> |     block: (Pagination) -> PaginationResult<T> | ||||||
| ): List<T> { | ): List<T> { | ||||||
|     val results = mutableListOf<T>() |     val results = mutableListOf<T>() | ||||||
|     doForAll(initialPagination, paginationMapper) { |     doForAll(initialPagination, paginationMapper) { | ||||||
| @@ -16,46 +16,45 @@ suspend fun <T> getAll( | |||||||
|     return results.toList() |     return results.toList() | ||||||
| } | } | ||||||
|  |  | ||||||
| suspend fun <T, R> R.getAllBy( | inline fun <T, R> R.getAllBy( | ||||||
|     initialPagination: Pagination = FirstPagePagination(), |     initialPagination: Pagination = FirstPagePagination(), | ||||||
|     paginationMapper: R.(PaginationResult<T>) -> Pagination?, |     paginationMapper: R.(PaginationResult<T>) -> Pagination?, | ||||||
|     block: suspend R.(Pagination) -> PaginationResult<T> |     block: R.(Pagination) -> PaginationResult<T> | ||||||
| ): List<T> = getAll( | ): List<T> = getAll( | ||||||
|     initialPagination, |     initialPagination, | ||||||
|     { paginationMapper(it) }, |     { paginationMapper(it) }, | ||||||
|     { block(it) } |     { block(it) } | ||||||
| ) | ) | ||||||
|  |  | ||||||
| suspend fun <T> getAllWithNextPaging( | inline fun <T> getAllWithNextPaging( | ||||||
|     initialPagination: Pagination = FirstPagePagination(), |     initialPagination: Pagination = FirstPagePagination(), | ||||||
|     block: suspend (Pagination) -> PaginationResult<T> |     block: (Pagination) -> PaginationResult<T> | ||||||
| ): List<T> = getAll( | ): List<T> = getAll( | ||||||
|     initialPagination, |     initialPagination, | ||||||
|     { it.nextPageIfNotEmpty() }, |     { it.nextPageIfNotEmpty() }, | ||||||
|     block |     block | ||||||
| ) | ) | ||||||
|  |  | ||||||
| suspend fun <T, R> R.getAllByWithNextPaging( | inline fun <T, R> R.getAllByWithNextPaging( | ||||||
|     initialPagination: Pagination = FirstPagePagination(), |     initialPagination: Pagination = FirstPagePagination(), | ||||||
|     block: suspend R.(Pagination) -> PaginationResult<T> |     block: R.(Pagination) -> PaginationResult<T> | ||||||
| ): List<T> = getAllWithNextPaging( | ): List<T> = getAllWithNextPaging( | ||||||
|     initialPagination, |     initialPagination, | ||||||
|     { block(it) } |     { block(it) } | ||||||
| ) | ) | ||||||
|  |  | ||||||
| suspend fun <T> getAllWithCurrentPaging( | inline fun <T> getAllWithCurrentPaging( | ||||||
|     initialPagination: Pagination = FirstPagePagination(), |     initialPagination: Pagination = FirstPagePagination(), | ||||||
|     block: suspend (Pagination) -> PaginationResult<T> |     block: (Pagination) -> PaginationResult<T> | ||||||
| ): List<T> = getAll( | ): List<T> = getAll( | ||||||
|     initialPagination, |     initialPagination, | ||||||
|     { it.currentPageIfNotEmpty() }, |     { it.currentPageIfNotEmpty() }, | ||||||
|     block |     block | ||||||
| ) | ) | ||||||
|  |  | ||||||
| suspend fun <T, R> R.getAllByWithCurrentPaging( | inline fun <T, R> R.getAllByWithCurrentPaging( | ||||||
|     initialPagination: Pagination = FirstPagePagination(), |     initialPagination: Pagination = FirstPagePagination(), | ||||||
|     block: suspend R.(Pagination) -> PaginationResult<T> |     block: R.(Pagination) -> PaginationResult<T> | ||||||
| ): List<T> = getAllWithCurrentPaging( | ): List<T> = getAllWithCurrentPaging( | ||||||
|     initialPagination, |     initialPagination | ||||||
|     { block(it) } | ) { block(it) } | ||||||
| ) |  | ||||||
|   | |||||||
| @@ -4,8 +4,6 @@ import dev.inmo.micro_utils.repos.* | |||||||
| import kotlinx.coroutines.CoroutineScope | import kotlinx.coroutines.CoroutineScope | ||||||
| import kotlinx.coroutines.Dispatchers | import kotlinx.coroutines.Dispatchers | ||||||
| import kotlinx.coroutines.flow.* | import kotlinx.coroutines.flow.* | ||||||
| import kotlinx.coroutines.sync.Mutex |  | ||||||
| import kotlinx.coroutines.sync.withLock |  | ||||||
|  |  | ||||||
| open class ReadKeyValueCacheRepo<Key,Value>( | open class ReadKeyValueCacheRepo<Key,Value>( | ||||||
|     protected val parentRepo: ReadKeyValueRepo<Key, Value>, |     protected val parentRepo: ReadKeyValueRepo<Key, Value>, | ||||||
|   | |||||||
| @@ -8,8 +8,6 @@ import dev.inmo.micro_utils.repos.* | |||||||
| import kotlinx.coroutines.CoroutineScope | import kotlinx.coroutines.CoroutineScope | ||||||
| import kotlinx.coroutines.Dispatchers | import kotlinx.coroutines.Dispatchers | ||||||
| import kotlinx.coroutines.flow.* | import kotlinx.coroutines.flow.* | ||||||
| import kotlinx.coroutines.sync.Mutex |  | ||||||
| import kotlinx.coroutines.sync.withLock |  | ||||||
|  |  | ||||||
| open class ReadKeyValuesCacheRepo<Key,Value>( | open class ReadKeyValuesCacheRepo<Key,Value>( | ||||||
|     protected val parentRepo: ReadKeyValuesRepo<Key, Value>, |     protected val parentRepo: ReadKeyValuesRepo<Key, Value>, | ||||||
|   | |||||||
| @@ -1,11 +1,10 @@ | |||||||
| package dev.inmo.micro_utils.repos | package dev.inmo.micro_utils.repos | ||||||
| 
 | 
 | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.pagination.utils.doForAllWithCurrentPaging |  | ||||||
| import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| 
 | 
 | ||||||
| interface ReadOneToManyKeyValueRepo<Key, Value> : Repo { | interface ReadKeyValuesRepo<Key, Value> : Repo { | ||||||
|     suspend fun get(k: Key, pagination: Pagination, reversed: Boolean = false): PaginationResult<Value> |     suspend fun get(k: Key, pagination: Pagination, reversed: Boolean = false): PaginationResult<Value> | ||||||
|     suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key> |     suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key> | ||||||
|     suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean = false): PaginationResult<Key> |     suspend fun keys(v: Value, pagination: Pagination, reversed: Boolean = false): PaginationResult<Key> | ||||||
| @@ -36,9 +35,9 @@ interface ReadOneToManyKeyValueRepo<Key, Value> : Repo { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| typealias ReadKeyValuesRepo<Key,Value> = ReadOneToManyKeyValueRepo<Key, Value> | typealias ReadOneToManyKeyValueRepo<Key,Value> = ReadKeyValuesRepo<Key, Value> | ||||||
| 
 | 
 | ||||||
| interface WriteOneToManyKeyValueRepo<Key, Value> : Repo { | interface WriteKeyValuesRepo<Key, Value> : Repo { | ||||||
|     val onNewValue: Flow<Pair<Key, Value>> |     val onNewValue: Flow<Pair<Key, Value>> | ||||||
|     val onValueRemoved: Flow<Pair<Key, Value>> |     val onValueRemoved: Flow<Pair<Key, Value>> | ||||||
|     val onDataCleared: Flow<Key> |     val onDataCleared: Flow<Key> | ||||||
| @@ -55,41 +54,41 @@ interface WriteOneToManyKeyValueRepo<Key, Value> : Repo { | |||||||
|         add(toSet) |         add(toSet) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| typealias WriteKeyValuesRepo<Key,Value> = WriteOneToManyKeyValueRepo<Key, Value> | typealias WriteOneToManyKeyValueRepo<Key,Value> = WriteKeyValuesRepo<Key, Value> | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add( | suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.add( | ||||||
|     keysAndValues: List<Pair<Key, List<Value>>> |     keysAndValues: List<Pair<Key, List<Value>>> | ||||||
| ) = add(keysAndValues.toMap()) | ) = add(keysAndValues.toMap()) | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.add( | suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.add( | ||||||
|     vararg keysAndValues: Pair<Key, List<Value>> |     vararg keysAndValues: Pair<Key, List<Value>> | ||||||
| ) = add(keysAndValues.toMap()) | ) = add(keysAndValues.toMap()) | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.add( | suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.add( | ||||||
|     k: Key, v: List<Value> |     k: Key, v: List<Value> | ||||||
| ) = add(mapOf(k to v)) | ) = add(mapOf(k to v)) | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.add( | suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.add( | ||||||
|     k: Key, vararg v: Value |     k: Key, vararg v: Value | ||||||
| ) = add(k, v.toList()) | ) = add(k, v.toList()) | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.set( | suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.set( | ||||||
|     keysAndValues: List<Pair<Key, List<Value>>> |     keysAndValues: List<Pair<Key, List<Value>>> | ||||||
| ) = set(keysAndValues.toMap()) | ) = set(keysAndValues.toMap()) | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value, REPO : WriteOneToManyKeyValueRepo<Key, Value>> REPO.set( | suspend inline fun <Key, Value, REPO : WriteKeyValuesRepo<Key, Value>> REPO.set( | ||||||
|     vararg keysAndValues: Pair<Key, List<Value>> |     vararg keysAndValues: Pair<Key, List<Value>> | ||||||
| ) = set(keysAndValues.toMap()) | ) = set(keysAndValues.toMap()) | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.set( | suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.set( | ||||||
|     k: Key, v: List<Value> |     k: Key, v: List<Value> | ||||||
| ) = set(mapOf(k to v)) | ) = set(mapOf(k to v)) | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.set( | suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.set( | ||||||
|     k: Key, vararg v: Value |     k: Key, vararg v: Value | ||||||
| ) = set(k, v.toList()) | ) = set(k, v.toList()) | ||||||
| 
 | 
 | ||||||
| interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Value>, WriteOneToManyKeyValueRepo<Key, Value> { | interface KeyValuesRepo<Key, Value> : ReadKeyValuesRepo<Key, Value>, WriteKeyValuesRepo<Key, Value> { | ||||||
|     override suspend fun clearWithValue(v: Value) { |     override suspend fun clearWithValue(v: Value) { | ||||||
|         doWithPagination { |         doWithPagination { | ||||||
|             val keysResult = keys(v, it) |             val keysResult = keys(v, it) | ||||||
| @@ -102,22 +101,29 @@ interface OneToManyKeyValueRepo<Key, Value> : ReadOneToManyKeyValueRepo<Key, Val | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| typealias KeyValuesRepo<Key,Value> = OneToManyKeyValueRepo<Key, Value> | typealias OneToManyKeyValueRepo<Key,Value> = KeyValuesRepo<Key, Value> | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove( | class DelegateBasedKeyValuesRepo<Key, Value>( | ||||||
|  |     readDelegate: ReadKeyValuesRepo<Key, Value>, | ||||||
|  |     writeDelegate: WriteKeyValuesRepo<Key, Value> | ||||||
|  | ) : KeyValuesRepo<Key, Value>, | ||||||
|  |     ReadKeyValuesRepo<Key, Value> by readDelegate, | ||||||
|  |     WriteKeyValuesRepo<Key, Value> by writeDelegate | ||||||
|  | 
 | ||||||
|  | suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove( | ||||||
|     keysAndValues: List<Pair<Key, List<Value>>> |     keysAndValues: List<Pair<Key, List<Value>>> | ||||||
| ) = remove(keysAndValues.toMap()) | ) = remove(keysAndValues.toMap()) | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove( | suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove( | ||||||
|     vararg keysAndValues: Pair<Key, List<Value>> |     vararg keysAndValues: Pair<Key, List<Value>> | ||||||
| ) = remove(keysAndValues.toMap()) | ) = remove(keysAndValues.toMap()) | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove( | suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove( | ||||||
|     k: Key, |     k: Key, | ||||||
|     v: List<Value> |     v: List<Value> | ||||||
| ) = remove(mapOf(k to v)) | ) = remove(mapOf(k to v)) | ||||||
| 
 | 
 | ||||||
| suspend inline fun <Key, Value> WriteOneToManyKeyValueRepo<Key, Value>.remove( | suspend inline fun <Key, Value> WriteKeyValuesRepo<Key, Value>.remove( | ||||||
|     k: Key, |     k: Key, | ||||||
|     vararg v: Value |     vararg v: Value | ||||||
| ) = remove(k, v.toList()) | ) = remove(k, v.toList()) | ||||||
| @@ -4,13 +4,13 @@ import dev.inmo.micro_utils.pagination.Pagination | |||||||
| import dev.inmo.micro_utils.pagination.PaginationResult | import dev.inmo.micro_utils.pagination.PaginationResult | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
|  |  | ||||||
| interface ReadStandardCRUDRepo<ObjectType, IdType> : Repo { | interface ReadCRUDRepo<ObjectType, IdType> : Repo { | ||||||
|     suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> |     suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> | ||||||
|     suspend fun getById(id: IdType): ObjectType? |     suspend fun getById(id: IdType): ObjectType? | ||||||
|     suspend fun contains(id: IdType): Boolean |     suspend fun contains(id: IdType): Boolean | ||||||
|     suspend fun count(): Long |     suspend fun count(): Long | ||||||
| } | } | ||||||
| typealias ReadCRUDRepo<ObjectType, IdType> = ReadStandardCRUDRepo<ObjectType, IdType> | typealias ReadStandardCRUDRepo<ObjectType, IdType> = ReadCRUDRepo<ObjectType, IdType> | ||||||
|  |  | ||||||
| typealias UpdatedValuePair<IdType, ValueType> = Pair<IdType, ValueType> | typealias UpdatedValuePair<IdType, ValueType> = Pair<IdType, ValueType> | ||||||
| val <IdType> UpdatedValuePair<IdType, *>.id | val <IdType> UpdatedValuePair<IdType, *>.id | ||||||
| @@ -18,7 +18,7 @@ val <IdType> UpdatedValuePair<IdType, *>.id | |||||||
| val <ValueType> UpdatedValuePair<*, ValueType>.value | val <ValueType> UpdatedValuePair<*, ValueType>.value | ||||||
|     get() = second |     get() = second | ||||||
|  |  | ||||||
| interface WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> : Repo { | interface WriteCRUDRepo<ObjectType, IdType, InputValueType> : Repo { | ||||||
|     val newObjectsFlow: Flow<ObjectType> |     val newObjectsFlow: Flow<ObjectType> | ||||||
|     val updatedObjectsFlow: Flow<ObjectType> |     val updatedObjectsFlow: Flow<ObjectType> | ||||||
|     val deletedObjectsIdsFlow: Flow<IdType> |     val deletedObjectsIdsFlow: Flow<IdType> | ||||||
| @@ -28,18 +28,25 @@ interface WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> : Repo { | |||||||
|     suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> |     suspend fun update(values: List<UpdatedValuePair<IdType, InputValueType>>): List<ObjectType> | ||||||
|     suspend fun deleteById(ids: List<IdType>) |     suspend fun deleteById(ids: List<IdType>) | ||||||
| } | } | ||||||
| typealias WriteCRUDRepo<ObjectType, IdType, InputValueType> = WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> | typealias WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> = WriteCRUDRepo<ObjectType, IdType, InputValueType> | ||||||
|  |  | ||||||
| suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.create( | suspend fun <ObjectType, IdType, InputValueType> WriteCRUDRepo<ObjectType, IdType, InputValueType>.create( | ||||||
|     vararg values: InputValueType |     vararg values: InputValueType | ||||||
| ): List<ObjectType> = create(values.toList()) | ): List<ObjectType> = create(values.toList()) | ||||||
| suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.update( | suspend fun <ObjectType, IdType, InputValueType> WriteCRUDRepo<ObjectType, IdType, InputValueType>.update( | ||||||
|     vararg values: UpdatedValuePair<IdType, InputValueType> |     vararg values: UpdatedValuePair<IdType, InputValueType> | ||||||
| ): List<ObjectType> = update(values.toList()) | ): List<ObjectType> = update(values.toList()) | ||||||
| suspend fun <ObjectType, IdType, InputValueType> WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>.deleteById( | suspend fun <ObjectType, IdType, InputValueType> WriteCRUDRepo<ObjectType, IdType, InputValueType>.deleteById( | ||||||
|     vararg ids: IdType |     vararg ids: IdType | ||||||
| ) = deleteById(ids.toList()) | ) = deleteById(ids.toList()) | ||||||
|  |  | ||||||
| interface StandardCRUDRepo<ObjectType, IdType, InputValueType> : ReadStandardCRUDRepo<ObjectType, IdType>, | interface CRUDRepo<ObjectType, IdType, InputValueType> : ReadCRUDRepo<ObjectType, IdType>, | ||||||
|     WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> |     WriteCRUDRepo<ObjectType, IdType, InputValueType> | ||||||
| typealias CRUDRepo<ObjectType, IdType, InputValueType> = StandardCRUDRepo<ObjectType, IdType, InputValueType> | typealias StandardCRUDRepo<ObjectType, IdType, InputValueType> = CRUDRepo<ObjectType, IdType, InputValueType> | ||||||
|  |  | ||||||
|  | class DelegateBasedCRUDRepo<ObjectType, IdType, InputValueType>( | ||||||
|  |     readDelegate: ReadCRUDRepo<ObjectType, IdType>, | ||||||
|  |     writeDelegate: WriteCRUDRepo<ObjectType, IdType, InputValueType> | ||||||
|  | ) : CRUDRepo<ObjectType, IdType, InputValueType>, | ||||||
|  |     ReadCRUDRepo<ObjectType, IdType> by readDelegate, | ||||||
|  |     WriteCRUDRepo<ObjectType, IdType, InputValueType> by writeDelegate | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import dev.inmo.micro_utils.pagination.* | |||||||
| import dev.inmo.micro_utils.pagination.utils.doAllWithCurrentPaging | import dev.inmo.micro_utils.pagination.utils.doAllWithCurrentPaging | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
|  |  | ||||||
| interface ReadStandardKeyValueRepo<Key, Value> : Repo { | interface ReadKeyValueRepo<Key, Value> : Repo { | ||||||
|     suspend fun get(k: Key): Value? |     suspend fun get(k: Key): Value? | ||||||
|     suspend fun values(pagination: Pagination, reversed: Boolean = false): PaginationResult<Value> |     suspend fun values(pagination: Pagination, reversed: Boolean = false): PaginationResult<Value> | ||||||
|     suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key> |     suspend fun keys(pagination: Pagination, reversed: Boolean = false): PaginationResult<Key> | ||||||
| @@ -12,9 +12,9 @@ interface ReadStandardKeyValueRepo<Key, Value> : Repo { | |||||||
|     suspend fun contains(key: Key): Boolean |     suspend fun contains(key: Key): Boolean | ||||||
|     suspend fun count(): Long |     suspend fun count(): Long | ||||||
| } | } | ||||||
| typealias ReadKeyValueRepo<Key,Value> = ReadStandardKeyValueRepo<Key, Value> | typealias ReadStandardKeyValueRepo<Key,Value> = ReadKeyValueRepo<Key, Value> | ||||||
|  |  | ||||||
| interface WriteStandardKeyValueRepo<Key, Value> : Repo { | interface WriteKeyValueRepo<Key, Value> : Repo { | ||||||
|     val onNewValue: Flow<Pair<Key, Value>> |     val onNewValue: Flow<Pair<Key, Value>> | ||||||
|     val onValueRemoved: Flow<Key> |     val onValueRemoved: Flow<Key> | ||||||
|  |  | ||||||
| @@ -22,25 +22,25 @@ interface WriteStandardKeyValueRepo<Key, Value> : Repo { | |||||||
|     suspend fun unset(toUnset: List<Key>) |     suspend fun unset(toUnset: List<Key>) | ||||||
|     suspend fun unsetWithValues(toUnset: List<Value>) |     suspend fun unsetWithValues(toUnset: List<Value>) | ||||||
| } | } | ||||||
| typealias WriteKeyValueRepo<Key,Value> = WriteStandardKeyValueRepo<Key, Value> | typealias WriteStandardKeyValueRepo<Key,Value> = WriteKeyValueRepo<Key, Value> | ||||||
|  |  | ||||||
| suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.set( | suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set( | ||||||
|     vararg toSet: Pair<Key, Value> |     vararg toSet: Pair<Key, Value> | ||||||
| ) = set(toSet.toMap()) | ) = set(toSet.toMap()) | ||||||
|  |  | ||||||
| suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.set( | suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.set( | ||||||
|     k: Key, v: Value |     k: Key, v: Value | ||||||
| ) = set(k to v) | ) = set(k to v) | ||||||
|  |  | ||||||
| suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.unset( | suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unset( | ||||||
|     vararg k: Key |     vararg k: Key | ||||||
| ) = unset(k.toList()) | ) = unset(k.toList()) | ||||||
|  |  | ||||||
| suspend inline fun <Key, Value> WriteStandardKeyValueRepo<Key, Value>.unsetWithValues( | suspend inline fun <Key, Value> WriteKeyValueRepo<Key, Value>.unsetWithValues( | ||||||
|     vararg v: Value |     vararg v: Value | ||||||
| ) = unsetWithValues(v.toList()) | ) = unsetWithValues(v.toList()) | ||||||
|  |  | ||||||
| interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value>, WriteStandardKeyValueRepo<Key, Value> { | interface KeyValueRepo<Key, Value> : ReadKeyValueRepo<Key, Value>, WriteKeyValueRepo<Key, Value> { | ||||||
|     override suspend fun unsetWithValues(toUnset: List<Value>) = toUnset.forEach { v -> |     override suspend fun unsetWithValues(toUnset: List<Value>) = toUnset.forEach { v -> | ||||||
|         doAllWithCurrentPaging { |         doAllWithCurrentPaging { | ||||||
|             keys(v, it).also { |             keys(v, it).also { | ||||||
| @@ -49,4 +49,11 @@ interface StandardKeyValueRepo<Key, Value> : ReadStandardKeyValueRepo<Key, Value | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| typealias KeyValueRepo<Key,Value> = StandardKeyValueRepo<Key, Value> | 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 | ||||||
|   | |||||||
| @@ -6,10 +6,12 @@ import dev.inmo.micro_utils.repos.* | |||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.coroutines.flow.map | import kotlinx.coroutines.flow.map | ||||||
|  |  | ||||||
| open class MapperReadStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | @Deprecated("Renamed", ReplaceWith("MapperReadKeyValueRepo", "dev.inmo.micro_utils.repos.mappers.MapperReadKeyValueRepo")) | ||||||
|     private val to: ReadStandardKeyValueRepo<ToKey, ToValue>, | typealias MapperReadStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperReadKeyValueRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
|  | open class MapperReadKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | ||||||
|  |     private val to: ReadKeyValueRepo<ToKey, ToValue>, | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ) : ReadStandardKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper { | ) : ReadKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper { | ||||||
|     override suspend fun get(k: FromKey): FromValue? = to.get( |     override suspend fun get(k: FromKey): FromValue? = to.get( | ||||||
|         k.toOutKey() |         k.toOutKey() | ||||||
|     ) ?.toInnerValue() |     ) ?.toInnerValue() | ||||||
| @@ -69,24 +71,26 @@ open class MapperReadStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | |||||||
| } | } | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <FromKey, FromValue, ToKey, ToValue> ReadStandardKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <FromKey, FromValue, ToKey, ToValue> ReadKeyValueRepo<ToKey, ToValue>.withMapper( | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ): ReadStandardKeyValueRepo<FromKey, FromValue> = MapperReadStandardKeyValueRepo(this, mapper) | ): ReadKeyValueRepo<FromKey, FromValue> = MapperReadKeyValueRepo(this, mapper) | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadStandardKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadKeyValueRepo<ToKey, ToValue>.withMapper( | ||||||
|     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, |     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, | ||||||
|     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, |     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, | ||||||
|     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, |     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, | ||||||
|     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, |     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, | ||||||
| ): ReadStandardKeyValueRepo<FromKey, FromValue> = withMapper( | ): ReadKeyValueRepo<FromKey, FromValue> = withMapper( | ||||||
|     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) |     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) | ||||||
| ) | ) | ||||||
|  |  | ||||||
| open class MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | @Deprecated("Renamed", ReplaceWith("MapperWriteKeyValueRepo", "dev.inmo.micro_utils.repos.mappers.MapperWriteKeyValueRepo")) | ||||||
|     private val to: WriteStandardKeyValueRepo<ToKey, ToValue>, | typealias MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperWriteKeyValueRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
|  | open class MapperWriteKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | ||||||
|  |     private val to: WriteKeyValueRepo<ToKey, ToValue>, | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ) : WriteStandardKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper { | ) : WriteKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper { | ||||||
|     override val onNewValue: Flow<Pair<FromKey, FromValue>> = to.onNewValue.map { (k, v) -> |     override val onNewValue: Flow<Pair<FromKey, FromValue>> = to.onNewValue.map { (k, v) -> | ||||||
|         k.toInnerKey() to v.toInnerValue() |         k.toInnerKey() to v.toInnerValue() | ||||||
|     } |     } | ||||||
| @@ -112,40 +116,42 @@ open class MapperWriteStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | |||||||
| } | } | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <FromKey, FromValue, ToKey, ToValue> WriteStandardKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <FromKey, FromValue, ToKey, ToValue> WriteKeyValueRepo<ToKey, ToValue>.withMapper( | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ): WriteStandardKeyValueRepo<FromKey, FromValue> = MapperWriteStandardKeyValueRepo(this, mapper) | ): WriteKeyValueRepo<FromKey, FromValue> = MapperWriteKeyValueRepo(this, mapper) | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteStandardKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteKeyValueRepo<ToKey, ToValue>.withMapper( | ||||||
|     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, |     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, | ||||||
|     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, |     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, | ||||||
|     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, |     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, | ||||||
|     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, |     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, | ||||||
| ): WriteStandardKeyValueRepo<FromKey, FromValue> = withMapper( | ): WriteKeyValueRepo<FromKey, FromValue> = withMapper( | ||||||
|     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) |     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | @Deprecated("Renamed", ReplaceWith("MapperKeyValueRepo", "dev.inmo.micro_utils.repos.mappers.MapperKeyValueRepo")) | ||||||
|  | typealias MapperStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperKeyValueRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") | @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") | ||||||
| open class MapperStandardKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | open class MapperKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | ||||||
|     private val to: StandardKeyValueRepo<ToKey, ToValue>, |     private val to: KeyValueRepo<ToKey, ToValue>, | ||||||
|     private val mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     private val mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ) : StandardKeyValueRepo<FromKey, FromValue>, | ) : KeyValueRepo<FromKey, FromValue>, | ||||||
|     MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper, |     MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper, | ||||||
|     ReadStandardKeyValueRepo<FromKey, FromValue> by MapperReadStandardKeyValueRepo(to, mapper), |     ReadKeyValueRepo<FromKey, FromValue> by MapperReadKeyValueRepo(to, mapper), | ||||||
|     WriteStandardKeyValueRepo<FromKey, FromValue> by MapperWriteStandardKeyValueRepo(to, mapper) |     WriteKeyValueRepo<FromKey, FromValue> by MapperWriteKeyValueRepo(to, mapper) | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <FromKey, FromValue, ToKey, ToValue> StandardKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <FromKey, FromValue, ToKey, ToValue> KeyValueRepo<ToKey, ToValue>.withMapper( | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ): StandardKeyValueRepo<FromKey, FromValue> = MapperStandardKeyValueRepo(this, mapper) | ): KeyValueRepo<FromKey, FromValue> = MapperKeyValueRepo(this, mapper) | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> StandardKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> KeyValueRepo<ToKey, ToValue>.withMapper( | ||||||
|     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, |     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, | ||||||
|     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, |     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, | ||||||
|     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, |     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, | ||||||
|     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, |     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, | ||||||
| ): StandardKeyValueRepo<FromKey, FromValue> = withMapper( | ): KeyValueRepo<FromKey, FromValue> = withMapper( | ||||||
|     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) |     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -6,10 +6,12 @@ import dev.inmo.micro_utils.repos.* | |||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.coroutines.flow.map | import kotlinx.coroutines.flow.map | ||||||
|  |  | ||||||
| open class MapperReadOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | @Deprecated("Renamed", ReplaceWith("MapperReadKeyValuesRepo", "dev.inmo.micro_utils.repos.mappers.MapperReadKeyValuesRepo")) | ||||||
|     private val to: ReadOneToManyKeyValueRepo<ToKey, ToValue>, | typealias MapperReadOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperReadKeyValuesRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
|  | open class MapperReadKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>( | ||||||
|  |     private val to: ReadKeyValuesRepo<ToKey, ToValue>, | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ) : ReadOneToManyKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper { | ) : ReadKeyValuesRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper { | ||||||
|     override suspend fun get( |     override suspend fun get( | ||||||
|         k: FromKey, |         k: FromKey, | ||||||
|         pagination: Pagination, |         pagination: Pagination, | ||||||
| @@ -67,24 +69,26 @@ open class MapperReadOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | |||||||
| } | } | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <FromKey, FromValue, ToKey, ToValue> ReadOneToManyKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <FromKey, FromValue, ToKey, ToValue> ReadKeyValuesRepo<ToKey, ToValue>.withMapper( | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ): ReadOneToManyKeyValueRepo<FromKey, FromValue> = MapperReadOneToManyKeyValueRepo(this, mapper) | ): ReadKeyValuesRepo<FromKey, FromValue> = MapperReadKeyValuesRepo(this, mapper) | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadOneToManyKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> ReadKeyValuesRepo<ToKey, ToValue>.withMapper( | ||||||
|     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, |     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, | ||||||
|     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, |     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, | ||||||
|     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, |     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, | ||||||
|     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, |     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, | ||||||
| ): ReadOneToManyKeyValueRepo<FromKey, FromValue> = withMapper( | ): ReadKeyValuesRepo<FromKey, FromValue> = withMapper( | ||||||
|     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) |     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) | ||||||
| ) | ) | ||||||
|  |  | ||||||
| open class MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | @Deprecated("Renamed", ReplaceWith("MapperWriteKeyValuesRepo", "dev.inmo.micro_utils.repos.mappers.MapperWriteKeyValuesRepo")) | ||||||
|     private val to: WriteOneToManyKeyValueRepo<ToKey, ToValue>, | typealias MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperWriteKeyValuesRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
|  | open class MapperWriteKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>( | ||||||
|  |     private val to: WriteKeyValuesRepo<ToKey, ToValue>, | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ) : WriteOneToManyKeyValueRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper { | ) : WriteKeyValuesRepo<FromKey, FromValue>, MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper { | ||||||
|     override val onNewValue: Flow<Pair<FromKey, FromValue>> = to.onNewValue.map { (k, v) -> |     override val onNewValue: Flow<Pair<FromKey, FromValue>> = to.onNewValue.map { (k, v) -> | ||||||
|         k.toInnerKey() to v.toInnerValue() |         k.toInnerKey() to v.toInnerValue() | ||||||
|     } |     } | ||||||
| @@ -118,40 +122,42 @@ open class MapperWriteOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | |||||||
| } | } | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <FromKey, FromValue, ToKey, ToValue> WriteOneToManyKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <FromKey, FromValue, ToKey, ToValue> WriteKeyValuesRepo<ToKey, ToValue>.withMapper( | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ): WriteOneToManyKeyValueRepo<FromKey, FromValue> = MapperWriteOneToManyKeyValueRepo(this, mapper) | ): WriteKeyValuesRepo<FromKey, FromValue> = MapperWriteKeyValuesRepo(this, mapper) | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteOneToManyKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> WriteKeyValuesRepo<ToKey, ToValue>.withMapper( | ||||||
|     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, |     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, | ||||||
|     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, |     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, | ||||||
|     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, |     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, | ||||||
|     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, |     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, | ||||||
| ): WriteOneToManyKeyValueRepo<FromKey, FromValue> = withMapper( | ): WriteKeyValuesRepo<FromKey, FromValue> = withMapper( | ||||||
|     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) |     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | @Deprecated("Renamed", ReplaceWith("MapperKeyValuesRepo", "dev.inmo.micro_utils.repos.mappers.MapperKeyValuesRepo")) | ||||||
|  | typealias MapperOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue> = MapperKeyValuesRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") | @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") | ||||||
| open class MapperOneToManyKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | open class MapperKeyValuesRepo<FromKey, FromValue, ToKey, ToValue>( | ||||||
|     private val to: OneToManyKeyValueRepo<ToKey, ToValue>, |     private val to: KeyValuesRepo<ToKey, ToValue>, | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ) : OneToManyKeyValueRepo<FromKey, FromValue>, | ) : KeyValuesRepo<FromKey, FromValue>, | ||||||
|     MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper, |     MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper, | ||||||
|     ReadOneToManyKeyValueRepo<FromKey, FromValue> by MapperReadOneToManyKeyValueRepo(to, mapper), |     ReadKeyValuesRepo<FromKey, FromValue> by MapperReadKeyValuesRepo(to, mapper), | ||||||
|     WriteOneToManyKeyValueRepo<FromKey, FromValue> by MapperWriteOneToManyKeyValueRepo(to, mapper) |     WriteKeyValuesRepo<FromKey, FromValue> by MapperWriteKeyValuesRepo(to, mapper) | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <FromKey, FromValue, ToKey, ToValue> OneToManyKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <FromKey, FromValue, ToKey, ToValue> KeyValuesRepo<ToKey, ToValue>.withMapper( | ||||||
|     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> |     mapper: MapperRepo<FromKey, FromValue, ToKey, ToValue> | ||||||
| ): OneToManyKeyValueRepo<FromKey, FromValue> = MapperOneToManyKeyValueRepo(this, mapper) | ): KeyValuesRepo<FromKey, FromValue> = MapperKeyValuesRepo(this, mapper) | ||||||
|  |  | ||||||
| @Suppress("NOTHING_TO_INLINE") | @Suppress("NOTHING_TO_INLINE") | ||||||
| inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> OneToManyKeyValueRepo<ToKey, ToValue>.withMapper( | inline fun <reified FromKey, reified FromValue, reified ToKey, reified ToValue> KeyValuesRepo<ToKey, ToValue>.withMapper( | ||||||
|     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, |     crossinline keyFromToTo: suspend FromKey.() -> ToKey = { this as ToKey }, | ||||||
|     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, |     crossinline valueFromToTo: suspend FromValue.() -> ToValue = { this as ToValue }, | ||||||
|     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, |     crossinline keyToToFrom: suspend ToKey.() -> FromKey = { this as FromKey }, | ||||||
|     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, |     crossinline valueToToFrom: suspend ToValue.() -> FromValue = { this as FromValue }, | ||||||
| ): OneToManyKeyValueRepo<FromKey, FromValue> = withMapper( | ): KeyValuesRepo<FromKey, FromValue> = withMapper( | ||||||
|     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) |     mapper(keyFromToTo, valueFromToTo, keyToToFrom, valueToToFrom) | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -1,11 +1,10 @@ | |||||||
| package dev.inmo.micro_utils.repos.pagination | package dev.inmo.micro_utils.repos.pagination | ||||||
|  |  | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.pagination.utils.doForAllWithNextPaging |  | ||||||
| import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | ||||||
| import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo | import dev.inmo.micro_utils.repos.ReadCRUDRepo | ||||||
|  |  | ||||||
| suspend inline fun <T, ID, REPO : ReadStandardCRUDRepo<T, ID>> REPO.getAll( | suspend inline fun <T, ID, REPO : ReadCRUDRepo<T, ID>> REPO.getAll( | ||||||
|     @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE") |     @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE") | ||||||
|     crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<T> |     crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<T> | ||||||
| ): List<T> = getAllWithNextPaging { | ): List<T> = getAllWithNextPaging { | ||||||
|   | |||||||
| @@ -2,9 +2,9 @@ package dev.inmo.micro_utils.repos.pagination | |||||||
|  |  | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | ||||||
| import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo | import dev.inmo.micro_utils.repos.ReadKeyValueRepo | ||||||
|  |  | ||||||
| suspend inline fun <Key, Value, REPO : ReadStandardKeyValueRepo<Key, Value>> REPO.getAll( | suspend inline fun <Key, Value, REPO : ReadKeyValueRepo<Key, Value>> REPO.getAll( | ||||||
|     @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE") |     @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE") | ||||||
|     crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key> |     crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key> | ||||||
| ): List<Pair<Key, Value>> = getAllWithNextPaging { | ): List<Pair<Key, Value>> = getAllWithNextPaging { | ||||||
|   | |||||||
| @@ -2,9 +2,9 @@ package dev.inmo.micro_utils.repos.pagination | |||||||
|  |  | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | ||||||
| import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo | import dev.inmo.micro_utils.repos.ReadKeyValuesRepo | ||||||
|  |  | ||||||
| suspend inline fun <Key, Value, REPO : ReadOneToManyKeyValueRepo<Key, Value>> REPO.getAll( | suspend inline fun <Key, Value, REPO : ReadKeyValuesRepo<Key, Value>> REPO.getAll( | ||||||
|     @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE") |     @Suppress("REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE") | ||||||
|     crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key> |     crossinline methodCaller: suspend REPO.(Pagination) -> PaginationResult<Key> | ||||||
| ): List<Pair<Key, List<Value>>> = getAllWithNextPaging { | ): List<Pair<Key, List<Value>>> = getAllWithNextPaging { | ||||||
|   | |||||||
| @@ -1,10 +1,10 @@ | |||||||
| package dev.inmo.micro_utils.repos.versions | package dev.inmo.micro_utils.repos.versions | ||||||
|  |  | ||||||
| import dev.inmo.micro_utils.repos.StandardKeyValueRepo | import dev.inmo.micro_utils.repos.KeyValueRepo | ||||||
| import dev.inmo.micro_utils.repos.set | import dev.inmo.micro_utils.repos.set | ||||||
|  |  | ||||||
| class KeyValueBasedVersionsRepoProxy<T>( | class KeyValueBasedVersionsRepoProxy<T>( | ||||||
|     private val keyValueStore: StandardKeyValueRepo<String, Int>, |     private val keyValueStore: KeyValueRepo<String, Int>, | ||||||
|     override val database: T |     override val database: T | ||||||
| ) : StandardVersionsRepoProxy<T> { | ) : StandardVersionsRepoProxy<T> { | ||||||
|     override suspend fun getTableVersion(tableName: String): Int? = keyValueStore.get(tableName) |     override suspend fun getTableVersion(tableName: String): Int? = keyValueStore.get(tableName) | ||||||
|   | |||||||
| @@ -13,9 +13,12 @@ import java.nio.file.StandardWatchEventKinds.* | |||||||
| private inline val String.isAbsolute | private inline val String.isAbsolute | ||||||
|     get() = startsWith(File.separator) |     get() = startsWith(File.separator) | ||||||
| 
 | 
 | ||||||
| class FileReadStandardKeyValueRepo( | @Deprecated("Renamed", ReplaceWith("FileReadKeyValueRepo", "dev.inmo.micro_utils.repos.FileReadKeyValueRepo")) | ||||||
|  | typealias FileReadStandardKeyValueRepo = FileReadKeyValueRepo | ||||||
|  | 
 | ||||||
|  | class FileReadKeyValueRepo( | ||||||
|     private val folder: File |     private val folder: File | ||||||
| ) : ReadStandardKeyValueRepo<String, File> { | ) : ReadKeyValueRepo<String, File> { | ||||||
|     init { |     init { | ||||||
|         folder.mkdirs() |         folder.mkdirs() | ||||||
|     } |     } | ||||||
| @@ -79,14 +82,17 @@ class FileReadStandardKeyValueRepo( | |||||||
|     override suspend fun count(): Long = folder.list() ?.size ?.toLong() ?: 0L |     override suspend fun count(): Long = folder.list() ?.size ?.toLong() ?: 0L | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Deprecated("Renamed", ReplaceWith("FileWriteKeyValueRepo", "dev.inmo.micro_utils.repos.FileWriteKeyValueRepo")) | ||||||
|  | typealias FileWriteStandardKeyValueRepo = FileWriteKeyValueRepo | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Files watching will not correctly works on Android with version of API lower than API 26 |  * Files watching will not correctly works on Android with version of API lower than API 26 | ||||||
|  */ |  */ | ||||||
| @Warning("Files watching will not correctly works on Android Platform with version of API lower than API 26") | @Warning("Files watching will not correctly works on Android Platform with version of API lower than API 26") | ||||||
| class FileWriteStandardKeyValueRepo( | class FileWriteKeyValueRepo( | ||||||
|     private val folder: File, |     private val folder: File, | ||||||
|     filesChangedProcessingScope: CoroutineScope? = null |     filesChangedProcessingScope: CoroutineScope? = null | ||||||
| ) : WriteStandardKeyValueRepo<String, File> { | ) : WriteKeyValueRepo<String, File> { | ||||||
|     private val _onNewValue = MutableSharedFlow<Pair<String, File>>() |     private val _onNewValue = MutableSharedFlow<Pair<String, File>>() | ||||||
|     override val onNewValue: Flow<Pair<String, File>> = _onNewValue.asSharedFlow() |     override val onNewValue: Flow<Pair<String, File>> = _onNewValue.asSharedFlow() | ||||||
|     private val _onValueRemoved = MutableSharedFlow<String>() |     private val _onValueRemoved = MutableSharedFlow<String>() | ||||||
| @@ -174,12 +180,15 @@ class FileWriteStandardKeyValueRepo( | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Deprecated("Renamed", ReplaceWith("FileKeyValueRepo", "dev.inmo.micro_utils.repos.FileKeyValueRepo")) | ||||||
|  | typealias FileStandardKeyValueRepo = FileKeyValueRepo | ||||||
|  | 
 | ||||||
| @Warning("Files watching will not correctly works on Android Platform with version of API lower than API 26") | @Warning("Files watching will not correctly works on Android Platform with version of API lower than API 26") | ||||||
| @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") | @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") | ||||||
| class FileStandardKeyValueRepo( | class FileKeyValueRepo( | ||||||
|     folder: File, |     folder: File, | ||||||
|     filesChangedProcessingScope: CoroutineScope? = null |     filesChangedProcessingScope: CoroutineScope? = null | ||||||
| ) : StandardKeyValueRepo<String, File>, | ) : KeyValueRepo<String, File>, | ||||||
|     WriteStandardKeyValueRepo<String, File> by FileWriteStandardKeyValueRepo(folder, filesChangedProcessingScope), |     WriteKeyValueRepo<String, File> by FileWriteKeyValueRepo(folder, filesChangedProcessingScope), | ||||||
|     ReadStandardKeyValueRepo<String, File> by FileReadStandardKeyValueRepo(folder) { |     ReadKeyValueRepo<String, File> by FileReadKeyValueRepo(folder) { | ||||||
| } | } | ||||||
| @@ -12,7 +12,7 @@ val <T> T.asId: String | |||||||
|  |  | ||||||
| abstract class AbstractAndroidCRUDRepo<ObjectType, IdType>( | abstract class AbstractAndroidCRUDRepo<ObjectType, IdType>( | ||||||
|     protected val helper: StandardSQLHelper |     protected val helper: StandardSQLHelper | ||||||
| ) : ReadStandardCRUDRepo<ObjectType, IdType> { | ) : ReadCRUDRepo<ObjectType, IdType> { | ||||||
|     protected abstract val tableName: String |     protected abstract val tableName: String | ||||||
|     protected abstract val idColumnName: String |     protected abstract val idColumnName: String | ||||||
|     protected abstract suspend fun Cursor.toObject(): ObjectType |     protected abstract suspend fun Cursor.toObject(): ObjectType | ||||||
|   | |||||||
| @@ -9,9 +9,9 @@ abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType | |||||||
|     helper: StandardSQLHelper, |     helper: StandardSQLHelper, | ||||||
|     replyInFlows: Int = 0, |     replyInFlows: Int = 0, | ||||||
|     extraBufferCapacityInFlows: Int = 64 |     extraBufferCapacityInFlows: Int = 64 | ||||||
| ) : WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>, | ) : WriteCRUDRepo<ObjectType, IdType, InputValueType>, | ||||||
|     AbstractAndroidCRUDRepo<ObjectType, IdType>(helper), |     AbstractAndroidCRUDRepo<ObjectType, IdType>(helper), | ||||||
|     StandardCRUDRepo<ObjectType, IdType, InputValueType> { |     CRUDRepo<ObjectType, IdType, InputValueType> { | ||||||
|     protected val newObjectsChannel = MutableSharedFlow<ObjectType>(replyInFlows, extraBufferCapacityInFlows) |     protected val newObjectsChannel = MutableSharedFlow<ObjectType>(replyInFlows, extraBufferCapacityInFlows) | ||||||
|     protected val updateObjectsChannel = MutableSharedFlow<ObjectType>(replyInFlows, extraBufferCapacityInFlows) |     protected val updateObjectsChannel = MutableSharedFlow<ObjectType>(replyInFlows, extraBufferCapacityInFlows) | ||||||
|     protected val deleteObjectsIdsChannel = MutableSharedFlow<IdType>(replyInFlows, extraBufferCapacityInFlows) |     protected val deleteObjectsIdsChannel = MutableSharedFlow<IdType>(replyInFlows, extraBufferCapacityInFlows) | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ import dev.inmo.micro_utils.pagination.Pagination | |||||||
| import dev.inmo.micro_utils.pagination.PaginationResult | import dev.inmo.micro_utils.pagination.PaginationResult | ||||||
| import dev.inmo.micro_utils.pagination.utils.paginate | import dev.inmo.micro_utils.pagination.utils.paginate | ||||||
| import dev.inmo.micro_utils.pagination.utils.reverse | import dev.inmo.micro_utils.pagination.utils.reverse | ||||||
| import dev.inmo.micro_utils.repos.StandardKeyValueRepo | import dev.inmo.micro_utils.repos.KeyValueRepo | ||||||
| import kotlinx.coroutines.flow.* | import kotlinx.coroutines.flow.* | ||||||
|  |  | ||||||
| private val cache = HashMap<String, KeyValueStore<*>>() | private val cache = HashMap<String, KeyValueStore<*>>() | ||||||
| @@ -15,7 +15,7 @@ private val cache = HashMap<String, KeyValueStore<*>>() | |||||||
| fun <T : Any> Context.keyValueStore( | fun <T : Any> Context.keyValueStore( | ||||||
|     name: String = "default", |     name: String = "default", | ||||||
|     cacheValues: Boolean = false |     cacheValues: Boolean = false | ||||||
| ): StandardKeyValueRepo<String, T> { | ): KeyValueRepo<String, T> { | ||||||
|     @Suppress("UNCHECKED_CAST") |     @Suppress("UNCHECKED_CAST") | ||||||
|     return cache.getOrPut(name) { |     return cache.getOrPut(name) { | ||||||
|         KeyValueStore<T>(this, name, cacheValues) |         KeyValueStore<T>(this, name, cacheValues) | ||||||
| @@ -26,7 +26,7 @@ class KeyValueStore<T : Any> internal constructor ( | |||||||
|     c: Context, |     c: Context, | ||||||
|     preferencesName: String, |     preferencesName: String, | ||||||
|     useCache: Boolean = false |     useCache: Boolean = false | ||||||
| ) : SharedPreferences.OnSharedPreferenceChangeListener, StandardKeyValueRepo<String, T> { | ) : SharedPreferences.OnSharedPreferenceChangeListener, KeyValueRepo<String, T> { | ||||||
|     private val sharedPreferences = c.getSharedPreferences(preferencesName, Context.MODE_PRIVATE) |     private val sharedPreferences = c.getSharedPreferences(preferencesName, Context.MODE_PRIVATE) | ||||||
|  |  | ||||||
|     private val cachedData = if (useCache) { |     private val cachedData = if (useCache) { | ||||||
|   | |||||||
| @@ -9,7 +9,6 @@ import dev.inmo.micro_utils.repos.* | |||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.coroutines.flow.MutableSharedFlow | import kotlinx.coroutines.flow.MutableSharedFlow | ||||||
| import kotlinx.coroutines.flow.asSharedFlow | import kotlinx.coroutines.flow.asSharedFlow | ||||||
| import kotlinx.coroutines.runBlocking |  | ||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
| import kotlinx.serialization.json.Json | import kotlinx.serialization.json.Json | ||||||
|  |  | ||||||
| @@ -26,7 +25,7 @@ class OneToManyAndroidRepo<Key, Value>( | |||||||
|     private val keyFromString: String.() -> Key, |     private val keyFromString: String.() -> Key, | ||||||
|     private val valueFromString: String.() -> Value, |     private val valueFromString: String.() -> Value, | ||||||
|     private val helper: SQLiteOpenHelper |     private val helper: SQLiteOpenHelper | ||||||
| ) : OneToManyKeyValueRepo<Key, Value> { | ) : KeyValuesRepo<Key, Value> { | ||||||
|     private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow() |     private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow() | ||||||
|     override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow() |     override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow() | ||||||
|     private val _onValueRemoved: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow() |     private val _onValueRemoved: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow() | ||||||
|   | |||||||
| @@ -4,13 +4,11 @@ package dev.inmo.micro_utils.repos.versions | |||||||
|  |  | ||||||
| import android.content.Context | import android.content.Context | ||||||
| import android.database.sqlite.SQLiteOpenHelper | import android.database.sqlite.SQLiteOpenHelper | ||||||
| import androidx.core.content.contentValuesOf |  | ||||||
| import dev.inmo.micro_utils.repos.* | import dev.inmo.micro_utils.repos.* | ||||||
| import dev.inmo.micro_utils.repos.keyvalue.keyValueStore | import dev.inmo.micro_utils.repos.keyvalue.keyValueStore | ||||||
| import kotlinx.coroutines.runBlocking |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Will create [VersionsRepo] based on [T], but versions will be stored in [StandardKeyValueRepo] |  * Will create [VersionsRepo] based on [T], but versions will be stored in [KeyValueRepo] | ||||||
|  * |  * | ||||||
|  * @receiver Will be used to create [KeyValueBasedVersionsRepoProxy] via [keyValueStore] and pass it to [StandardVersionsRepo] |  * @receiver Will be used to create [KeyValueBasedVersionsRepoProxy] via [keyValueStore] and pass it to [StandardVersionsRepo] | ||||||
|  * |  * | ||||||
| @@ -26,9 +24,9 @@ inline fun <T> Context.versionsKeyValueRepo( | |||||||
|     ) |     ) | ||||||
| ) | ) | ||||||
| /** | /** | ||||||
|  * Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [StandardKeyValueRepo] |  * Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [KeyValueRepo] | ||||||
|  * |  * | ||||||
|  * @receiver Will be used to create [StandardKeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo] |  * @receiver Will be used to create [KeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo] | ||||||
|  * |  * | ||||||
|  * @see [keyValueStore] |  * @see [keyValueStore] | ||||||
|  */ |  */ | ||||||
| @@ -37,9 +35,9 @@ inline fun Context.versionsKeyValueRepoForSQL( | |||||||
| ) = versionsKeyValueRepo(database) | ) = versionsKeyValueRepo(database) | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [StandardKeyValueRepo] |  * Will create [VersionsRepo] based on [SQLiteOpenHelper], but versions will be stored in [KeyValueRepo] | ||||||
|  * |  * | ||||||
|  * @param context Will be used to create [StandardKeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo] |  * @param context Will be used to create [KeyValueRepo] via [keyValueStore] and pass it to [StandardVersionsRepo] | ||||||
|  * |  * | ||||||
|  * @see [keyValueStore] |  * @see [keyValueStore] | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package dev.inmo.micro_utils.repos.exposed | package dev.inmo.micro_utils.repos.exposed | ||||||
|  |  | ||||||
| import dev.inmo.micro_utils.repos.StandardCRUDRepo | import dev.inmo.micro_utils.repos.CRUDRepo | ||||||
|  |  | ||||||
| abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>( | abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>( | ||||||
|     flowsChannelsSize: Int = 0, |     flowsChannelsSize: Int = 0, | ||||||
| @@ -11,4 +11,4 @@ abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>( | |||||||
|         tableName |         tableName | ||||||
|     ), |     ), | ||||||
|     ExposedCRUDRepo<ObjectType, IdType>, |     ExposedCRUDRepo<ObjectType, IdType>, | ||||||
|     StandardCRUDRepo<ObjectType, IdType, InputValueType> |     CRUDRepo<ObjectType, IdType, InputValueType> | ||||||
|   | |||||||
| @@ -1,14 +1,14 @@ | |||||||
| package dev.inmo.micro_utils.repos.exposed | package dev.inmo.micro_utils.repos.exposed | ||||||
|  |  | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo | import dev.inmo.micro_utils.repos.ReadCRUDRepo | ||||||
| import org.jetbrains.exposed.sql.* | import org.jetbrains.exposed.sql.* | ||||||
| import org.jetbrains.exposed.sql.transactions.transaction | import org.jetbrains.exposed.sql.transactions.transaction | ||||||
|  |  | ||||||
| abstract class AbstractExposedReadCRUDRepo<ObjectType, IdType>( | abstract class AbstractExposedReadCRUDRepo<ObjectType, IdType>( | ||||||
|     tableName: String |     tableName: String | ||||||
| ) : | ) : | ||||||
|     ReadStandardCRUDRepo<ObjectType, IdType>, |     ReadCRUDRepo<ObjectType, IdType>, | ||||||
|     ExposedCRUDRepo<ObjectType, IdType>, |     ExposedCRUDRepo<ObjectType, IdType>, | ||||||
|     Table(tableName) |     Table(tableName) | ||||||
| { | { | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package dev.inmo.micro_utils.repos.exposed | package dev.inmo.micro_utils.repos.exposed | ||||||
|  |  | ||||||
| import dev.inmo.micro_utils.repos.UpdatedValuePair | import dev.inmo.micro_utils.repos.UpdatedValuePair | ||||||
| import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo | import dev.inmo.micro_utils.repos.WriteCRUDRepo | ||||||
| import kotlinx.coroutines.flow.* | import kotlinx.coroutines.flow.* | ||||||
| import org.jetbrains.exposed.sql.* | import org.jetbrains.exposed.sql.* | ||||||
| import org.jetbrains.exposed.sql.statements.InsertStatement | import org.jetbrains.exposed.sql.statements.InsertStatement | ||||||
| @@ -15,7 +15,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>( | |||||||
| ) : | ) : | ||||||
|     AbstractExposedReadCRUDRepo<ObjectType, IdType>(tableName), |     AbstractExposedReadCRUDRepo<ObjectType, IdType>(tableName), | ||||||
|     ExposedCRUDRepo<ObjectType, IdType>, |     ExposedCRUDRepo<ObjectType, IdType>, | ||||||
|     WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> |     WriteCRUDRepo<ObjectType, IdType, InputValueType> | ||||||
| { | { | ||||||
|     protected val _newObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize) |     protected val _newObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize) | ||||||
|     protected val _updatedObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize) |     protected val _updatedObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize) | ||||||
|   | |||||||
| @@ -1,9 +1,7 @@ | |||||||
| package dev.inmo.micro_utils.repos.exposed.keyvalue | package dev.inmo.micro_utils.repos.exposed.keyvalue | ||||||
|  |  | ||||||
| import dev.inmo.micro_utils.repos.StandardKeyValueRepo | import dev.inmo.micro_utils.repos.KeyValueRepo | ||||||
| import dev.inmo.micro_utils.repos.exposed.ColumnAllocator | import dev.inmo.micro_utils.repos.exposed.ColumnAllocator | ||||||
| import dev.inmo.micro_utils.repos.exposed.initTable |  | ||||||
| import kotlinx.coroutines.channels.Channel |  | ||||||
| import kotlinx.coroutines.flow.* | import kotlinx.coroutines.flow.* | ||||||
| import org.jetbrains.exposed.sql.* | import org.jetbrains.exposed.sql.* | ||||||
| import org.jetbrains.exposed.sql.transactions.transaction | import org.jetbrains.exposed.sql.transactions.transaction | ||||||
| @@ -13,7 +11,7 @@ open class ExposedKeyValueRepo<Key, Value>( | |||||||
|     keyColumnAllocator: ColumnAllocator<Key>, |     keyColumnAllocator: ColumnAllocator<Key>, | ||||||
|     valueColumnAllocator: ColumnAllocator<Value>, |     valueColumnAllocator: ColumnAllocator<Value>, | ||||||
|     tableName: String? = null |     tableName: String? = null | ||||||
| ) : StandardKeyValueRepo<Key, Value>, ExposedReadKeyValueRepo<Key, Value>( | ) : KeyValueRepo<Key, Value>, ExposedReadKeyValueRepo<Key, Value>( | ||||||
|     database, |     database, | ||||||
|     keyColumnAllocator, |     keyColumnAllocator, | ||||||
|     valueColumnAllocator, |     valueColumnAllocator, | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package dev.inmo.micro_utils.repos.exposed.keyvalue | package dev.inmo.micro_utils.repos.exposed.keyvalue | ||||||
|  |  | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo | import dev.inmo.micro_utils.repos.ReadKeyValueRepo | ||||||
| import dev.inmo.micro_utils.repos.exposed.* | import dev.inmo.micro_utils.repos.exposed.* | ||||||
| import org.jetbrains.exposed.sql.* | import org.jetbrains.exposed.sql.* | ||||||
| import org.jetbrains.exposed.sql.transactions.transaction | import org.jetbrains.exposed.sql.transactions.transaction | ||||||
| @@ -11,7 +11,7 @@ open class ExposedReadKeyValueRepo<Key, Value>( | |||||||
|     keyColumnAllocator: ColumnAllocator<Key>, |     keyColumnAllocator: ColumnAllocator<Key>, | ||||||
|     valueColumnAllocator: ColumnAllocator<Value>, |     valueColumnAllocator: ColumnAllocator<Value>, | ||||||
|     tableName: String? = null |     tableName: String? = null | ||||||
| ) : ReadStandardKeyValueRepo<Key, Value>, ExposedRepo, Table(tableName ?: "") { | ) : ReadKeyValueRepo<Key, Value>, ExposedRepo, Table(tableName ?: "") { | ||||||
|     val keyColumn: Column<Key> = keyColumnAllocator() |     val keyColumn: Column<Key> = keyColumnAllocator() | ||||||
|     val valueColumn: Column<Value> = valueColumnAllocator() |     val valueColumn: Column<Value> = valueColumnAllocator() | ||||||
|     override val primaryKey: PrimaryKey = PrimaryKey(keyColumn, valueColumn) |     override val primaryKey: PrimaryKey = PrimaryKey(keyColumn, valueColumn) | ||||||
|   | |||||||
| @@ -1,18 +1,18 @@ | |||||||
| package dev.inmo.micro_utils.repos.exposed.onetomany | package dev.inmo.micro_utils.repos.exposed.onetomany | ||||||
| 
 | 
 | ||||||
| import dev.inmo.micro_utils.repos.OneToManyKeyValueRepo | import dev.inmo.micro_utils.repos.KeyValuesRepo | ||||||
| import dev.inmo.micro_utils.repos.exposed.ColumnAllocator | import dev.inmo.micro_utils.repos.exposed.ColumnAllocator | ||||||
| import kotlinx.coroutines.flow.* | import kotlinx.coroutines.flow.* | ||||||
| import org.jetbrains.exposed.sql.* | import org.jetbrains.exposed.sql.* | ||||||
| import org.jetbrains.exposed.sql.transactions.transaction | import org.jetbrains.exposed.sql.transactions.transaction | ||||||
| 
 | 
 | ||||||
| typealias ExposedKeyValuesRepo<Key, Value> = ExposedOneToManyKeyValueRepo<Key, Value> | typealias ExposedOneToManyKeyValueRepo1<Key, Value> = ExposedKeyValuesRepo<Key, Value> | ||||||
| open class ExposedOneToManyKeyValueRepo<Key, Value>( | open class ExposedKeyValuesRepo<Key, Value>( | ||||||
|     database: Database, |     database: Database, | ||||||
|     keyColumnAllocator: ColumnAllocator<Key>, |     keyColumnAllocator: ColumnAllocator<Key>, | ||||||
|     valueColumnAllocator: ColumnAllocator<Value>, |     valueColumnAllocator: ColumnAllocator<Value>, | ||||||
|     tableName: String? = null |     tableName: String? = null | ||||||
| ) : OneToManyKeyValueRepo<Key, Value>, ExposedReadOneToManyKeyValueRepo<Key, Value>( | ) : KeyValuesRepo<Key, Value>, ExposedReadKeyValuesRepo<Key, Value>( | ||||||
|     database, |     database, | ||||||
|     keyColumnAllocator, |     keyColumnAllocator, | ||||||
|     valueColumnAllocator, |     valueColumnAllocator, | ||||||
| @@ -1,20 +1,19 @@ | |||||||
| package dev.inmo.micro_utils.repos.exposed.onetomany | package dev.inmo.micro_utils.repos.exposed.onetomany | ||||||
| 
 | 
 | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo | import dev.inmo.micro_utils.repos.ReadKeyValuesRepo | ||||||
| import dev.inmo.micro_utils.repos.exposed.* | import dev.inmo.micro_utils.repos.exposed.* | ||||||
| import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedReadKeyValueRepo |  | ||||||
| import org.jetbrains.exposed.sql.* | import org.jetbrains.exposed.sql.* | ||||||
| import org.jetbrains.exposed.sql.transactions.transaction | import org.jetbrains.exposed.sql.transactions.transaction | ||||||
| 
 | 
 | ||||||
| typealias ExposedReadKeyValuesRepo<Key, Value> = ExposedReadOneToManyKeyValueRepo<Key, Value> | typealias ExposedReadOneToManyKeyValueRepo<Key, Value> = ExposedReadKeyValuesRepo<Key, Value> | ||||||
| 
 | 
 | ||||||
| open class ExposedReadOneToManyKeyValueRepo<Key, Value>( | open class ExposedReadKeyValuesRepo<Key, Value>( | ||||||
|     override val database: Database, |     override val database: Database, | ||||||
|     keyColumnAllocator: ColumnAllocator<Key>, |     keyColumnAllocator: ColumnAllocator<Key>, | ||||||
|     valueColumnAllocator: ColumnAllocator<Value>, |     valueColumnAllocator: ColumnAllocator<Value>, | ||||||
|     tableName: String? = null |     tableName: String? = null | ||||||
| ) : ReadOneToManyKeyValueRepo<Key, Value>, ExposedRepo, Table(tableName ?: "") { | ) : ReadKeyValuesRepo<Key, Value>, ExposedRepo, Table(tableName ?: "") { | ||||||
|     val keyColumn: Column<Key> = keyColumnAllocator() |     val keyColumn: Column<Key> = keyColumnAllocator() | ||||||
|     val valueColumn: Column<Value> = valueColumnAllocator() |     val valueColumn: Column<Value> = valueColumnAllocator() | ||||||
| 
 | 
 | ||||||
| @@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.* | |||||||
|  |  | ||||||
| class ReadMapCRUDRepo<ObjectType, IdType>( | class ReadMapCRUDRepo<ObjectType, IdType>( | ||||||
|     private val map: Map<IdType, ObjectType> = emptyMap() |     private val map: Map<IdType, ObjectType> = emptyMap() | ||||||
| ) : ReadStandardCRUDRepo<ObjectType, IdType> { | ) : ReadCRUDRepo<ObjectType, IdType> { | ||||||
|     override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> { |     override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> { | ||||||
|         return map.keys.drop(pagination.firstIndex).take(pagination.size).mapNotNull { |         return map.keys.drop(pagination.firstIndex).take(pagination.size).mapNotNull { | ||||||
|             map[it] |             map[it] | ||||||
| @@ -24,7 +24,7 @@ class ReadMapCRUDRepo<ObjectType, IdType>( | |||||||
|  |  | ||||||
| abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>( | abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>( | ||||||
|     protected val map: MutableMap<IdType, ObjectType> = mutableMapOf() |     protected val map: MutableMap<IdType, ObjectType> = mutableMapOf() | ||||||
| ) : WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> { | ) : WriteCRUDRepo<ObjectType, IdType, InputValueType> { | ||||||
|     protected val _newObjectsFlow: MutableSharedFlow<ObjectType> = MutableSharedFlow() |     protected val _newObjectsFlow: MutableSharedFlow<ObjectType> = MutableSharedFlow() | ||||||
|     override val newObjectsFlow: Flow<ObjectType> = _newObjectsFlow.asSharedFlow() |     override val newObjectsFlow: Flow<ObjectType> = _newObjectsFlow.asSharedFlow() | ||||||
|     protected val _updatedObjectsFlow: MutableSharedFlow<ObjectType> = MutableSharedFlow() |     protected val _updatedObjectsFlow: MutableSharedFlow<ObjectType> = MutableSharedFlow() | ||||||
| @@ -68,25 +68,30 @@ abstract class WriteMapCRUDRepo<ObjectType, IdType, InputValueType>( | |||||||
|  |  | ||||||
| abstract class MapCRUDRepo<ObjectType, IdType, InputValueType>( | abstract class MapCRUDRepo<ObjectType, IdType, InputValueType>( | ||||||
|     map: MutableMap<IdType, ObjectType> |     map: MutableMap<IdType, ObjectType> | ||||||
| ) : StandardCRUDRepo<ObjectType, IdType, InputValueType>, | ) : CRUDRepo<ObjectType, IdType, InputValueType>, | ||||||
|     ReadStandardCRUDRepo<ObjectType, IdType> by ReadMapCRUDRepo(map), |     ReadCRUDRepo<ObjectType, IdType> by ReadMapCRUDRepo(map), | ||||||
|     WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(map) |     WriteMapCRUDRepo<ObjectType, IdType, InputValueType>(map) | ||||||
|  |  | ||||||
| fun <ObjectType, IdType, InputValueType> MapCRUDRepo( | fun <ObjectType, IdType, InputValueType> MapCRUDRepo( | ||||||
|     map: MutableMap<IdType, ObjectType>, |     map: MutableMap<IdType, ObjectType>, | ||||||
|     updateCallback: suspend (newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType, |     updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType, | ||||||
|     createCallback: suspend (newValue: InputValueType) -> Pair<IdType, ObjectType> |     createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType> | ||||||
| ) = object : MapCRUDRepo<ObjectType, IdType, InputValueType>(map) { | ) = object : MapCRUDRepo<ObjectType, IdType, InputValueType>(map) { | ||||||
|     override suspend fun updateObject( |     override suspend fun updateObject( | ||||||
|         newValue: InputValueType, |         newValue: InputValueType, | ||||||
|         id: IdType, |         id: IdType, | ||||||
|         old: ObjectType |         old: ObjectType | ||||||
|     ): ObjectType = updateCallback(newValue, id, old) |     ): ObjectType = map.updateCallback(newValue, id, old) | ||||||
|  |  | ||||||
|     override suspend fun createObject(newValue: InputValueType): Pair<IdType, ObjectType> = createCallback(newValue) |     override suspend fun createObject(newValue: InputValueType): Pair<IdType, ObjectType> = map.createCallback(newValue) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | fun <ObjectType, IdType, InputValueType> MapCRUDRepo( | ||||||
|  |     updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType, | ||||||
|  |     createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType> | ||||||
|  | ) = MapCRUDRepo(mutableMapOf(), updateCallback, createCallback) | ||||||
|  |  | ||||||
| fun <ObjectType, IdType, InputValueType> MutableMap<IdType, ObjectType>.asCrudRepo( | fun <ObjectType, IdType, InputValueType> MutableMap<IdType, ObjectType>.asCrudRepo( | ||||||
|     updateCallback: suspend (newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType, |     updateCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType, id: IdType, old: ObjectType) -> ObjectType, | ||||||
|     createCallback: suspend (newValue: InputValueType) -> Pair<IdType, ObjectType> |     createCallback: suspend MutableMap<IdType, ObjectType>.(newValue: InputValueType) -> Pair<IdType, ObjectType> | ||||||
| ) = MapCRUDRepo(this, updateCallback, createCallback) | ) = MapCRUDRepo(this, updateCallback, createCallback) | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow | |||||||
|  |  | ||||||
| class ReadMapKeyValueRepo<Key, Value>( | class ReadMapKeyValueRepo<Key, Value>( | ||||||
|     protected val map: Map<Key, Value> = emptyMap() |     protected val map: Map<Key, Value> = emptyMap() | ||||||
| ) : ReadStandardKeyValueRepo<Key, Value> { | ) : ReadKeyValueRepo<Key, Value> { | ||||||
|     override suspend fun get(k: Key): Value? = map[k] |     override suspend fun get(k: Key): Value? = map[k] | ||||||
|  |  | ||||||
|     override suspend fun values( |     override suspend fun values( | ||||||
| @@ -58,7 +58,7 @@ class ReadMapKeyValueRepo<Key, Value>( | |||||||
|  |  | ||||||
| class WriteMapKeyValueRepo<Key, Value>( | class WriteMapKeyValueRepo<Key, Value>( | ||||||
|     private val map: MutableMap<Key, Value> = mutableMapOf() |     private val map: MutableMap<Key, Value> = mutableMapOf() | ||||||
| ) : WriteStandardKeyValueRepo<Key, Value> { | ) : WriteKeyValueRepo<Key, Value> { | ||||||
|     private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow() |     private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow() | ||||||
|     override val onNewValue: Flow<Pair<Key, Value>> |     override val onNewValue: Flow<Pair<Key, Value>> | ||||||
|         get() = _onNewValue |         get() = _onNewValue | ||||||
| @@ -78,19 +78,19 @@ class WriteMapKeyValueRepo<Key, Value>( | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     override suspend fun unsetWithValues(toUnset: List<Value>) { |     override suspend fun unsetWithValues(toUnset: List<Value>) { | ||||||
|         map.forEach { |         map.mapNotNull { (k, v) -> | ||||||
|             if (it.value in toUnset) { |             k.takeIf { v in toUnset } | ||||||
|                 map.remove(it.key) |         }.forEach { | ||||||
|                 _onValueRemoved.emit(it.key) |             map.remove(it) | ||||||
|             } |             _onValueRemoved.emit(it) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| class MapKeyValueRepo<Key, Value>( | class MapKeyValueRepo<Key, Value>( | ||||||
|     private val map: MutableMap<Key, Value> = mutableMapOf() |     private val map: MutableMap<Key, Value> = mutableMapOf() | ||||||
| ) : StandardKeyValueRepo<Key, Value>, | ) : KeyValueRepo<Key, Value>, | ||||||
|     ReadStandardKeyValueRepo<Key, Value> by ReadMapKeyValueRepo(map), |     ReadKeyValueRepo<Key, Value> by ReadMapKeyValueRepo(map), | ||||||
|     WriteStandardKeyValueRepo<Key, Value> by WriteMapKeyValueRepo(map) |     WriteKeyValueRepo<Key, Value> by WriteMapKeyValueRepo(map) | ||||||
|  |  | ||||||
| fun <K, V> MutableMap<K, V>.asKeyValueRepo(): StandardKeyValueRepo<K, V> = MapKeyValueRepo(this) | fun <K, V> MutableMap<K, V>.asKeyValueRepo(): KeyValueRepo<K, V> = MapKeyValueRepo(this) | ||||||
|   | |||||||
| @@ -5,9 +5,11 @@ import dev.inmo.micro_utils.pagination.utils.paginate | |||||||
| import dev.inmo.micro_utils.pagination.utils.reverse | import dev.inmo.micro_utils.pagination.utils.reverse | ||||||
| import kotlinx.coroutines.flow.* | import kotlinx.coroutines.flow.* | ||||||
| 
 | 
 | ||||||
| class MapReadOneToManyKeyValueRepo<Key, Value>( | @Deprecated("Renamed", ReplaceWith("MapReadKeyValuesRepo", "dev.inmo.micro_utils.repos.MapReadKeyValuesRepo")) | ||||||
|  | typealias MapReadOneToManyKeyValueRepo<Key, Value> = MapReadKeyValuesRepo<Key, Value> | ||||||
|  | class MapReadKeyValuesRepo<Key, Value>( | ||||||
|     private val map: Map<Key, List<Value>> = emptyMap() |     private val map: Map<Key, List<Value>> = emptyMap() | ||||||
| ) : ReadOneToManyKeyValueRepo<Key, Value> { | ) : ReadKeyValuesRepo<Key, Value> { | ||||||
|     override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> { |     override suspend fun get(k: Key, pagination: Pagination, reversed: Boolean): PaginationResult<Value> { | ||||||
|         val list = map[k] ?: return emptyPaginationResult() |         val list = map[k] ?: return emptyPaginationResult() | ||||||
| 
 | 
 | ||||||
| @@ -53,9 +55,11 @@ class MapReadOneToManyKeyValueRepo<Key, Value>( | |||||||
|     override suspend fun count(): Long = map.size.toLong() |     override suspend fun count(): Long = map.size.toLong() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class MapWriteOneToManyKeyValueRepo<Key, Value>( | @Deprecated("Renamed", ReplaceWith("MapWriteKeyValuesRepo", "dev.inmo.micro_utils.repos.MapWriteKeyValuesRepo")) | ||||||
|  | typealias MapWriteOneToManyKeyValueRepo<Key, Value> = MapWriteKeyValuesRepo<Key, Value> | ||||||
|  | class MapWriteKeyValuesRepo<Key, Value>( | ||||||
|     private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf() |     private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf() | ||||||
| ) : WriteOneToManyKeyValueRepo<Key, Value> { | ) : WriteKeyValuesRepo<Key, Value> { | ||||||
|     private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow() |     private val _onNewValue: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow() | ||||||
|     override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow() |     override val onNewValue: Flow<Pair<Key, Value>> = _onNewValue.asSharedFlow() | ||||||
|     private val _onValueRemoved: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow() |     private val _onValueRemoved: MutableSharedFlow<Pair<Key, Value>> = MutableSharedFlow() | ||||||
| @@ -80,6 +84,10 @@ class MapWriteOneToManyKeyValueRepo<Key, Value>( | |||||||
|                     _onValueRemoved.emit(k to v) |                     _onValueRemoved.emit(k to v) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             if (map[k] ?.isEmpty() == true) { | ||||||
|  |                 map.remove(k) | ||||||
|  |                 _onDataCleared.emit(k) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -94,12 +102,17 @@ class MapWriteOneToManyKeyValueRepo<Key, Value>( | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class MapOneToManyKeyValueRepo<Key, Value>( | @Deprecated("Renamed", ReplaceWith("MapKeyValuesRepo", "dev.inmo.micro_utils.repos.MapKeyValuesRepo")) | ||||||
|  | typealias MapOneToManyKeyValueRepo1<Key, Value> = MapKeyValuesRepo<Key, Value> | ||||||
|  | class MapKeyValuesRepo<Key, Value>( | ||||||
|     private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf() |     private val map: MutableMap<Key, MutableList<Value>> = mutableMapOf() | ||||||
| ) : OneToManyKeyValueRepo<Key, Value>, | ) : KeyValuesRepo<Key, Value>, | ||||||
|     ReadOneToManyKeyValueRepo<Key, Value> by MapReadOneToManyKeyValueRepo(map), |     ReadKeyValuesRepo<Key, Value> by MapReadKeyValuesRepo(map), | ||||||
|     WriteOneToManyKeyValueRepo<Key, Value> by MapWriteOneToManyKeyValueRepo(map) |     WriteKeyValuesRepo<Key, Value> by MapWriteKeyValuesRepo(map) | ||||||
| 
 | 
 | ||||||
| fun <K, V> MutableMap<K, List<V>>.asOneToManyKeyValueRepo(): OneToManyKeyValueRepo<K, V> = MapOneToManyKeyValueRepo( | fun <K, V> MutableMap<K, List<V>>.asKeyValuesRepo(): KeyValuesRepo<K, V> = MapKeyValuesRepo( | ||||||
|     map { (k, v) -> k to v.toMutableList() }.toMap().toMutableMap() |     map { (k, v) -> k to v.toMutableList() }.toMap().toMutableMap() | ||||||
| ) | ) | ||||||
|  | 
 | ||||||
|  | @Deprecated("Renamed", ReplaceWith("asKeyValuesRepo", "dev.inmo.micro_utils.repos.asKeyValuesRepo")) | ||||||
|  | fun <K, V> MutableMap<K, List<V>>.asOneToManyKeyValueRepo(): KeyValuesRepo<K, V> = asKeyValuesRepo() | ||||||
| @@ -0,0 +1,106 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.client.crud | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.pagination.PaginationResult | ||||||
|  | import dev.inmo.micro_utils.repos.* | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.http.ContentType | ||||||
|  | import io.ktor.util.reflect.TypeInfo | ||||||
|  | import io.ktor.util.reflect.typeInfo | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | class KtorCRUDRepoClient<ObjectType, IdType, InputValue> ( | ||||||
|  |     readDelegate: ReadCRUDRepo<ObjectType, IdType>, | ||||||
|  |     writeDelegate: WriteCRUDRepo<ObjectType, IdType, InputValue> | ||||||
|  | ) : CRUDRepo<ObjectType, IdType, InputValue> by DelegateBasedCRUDRepo( | ||||||
|  |     readDelegate, | ||||||
|  |     writeDelegate | ||||||
|  | ) { | ||||||
|  |     companion object { | ||||||
|  |         inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke( | ||||||
|  |             baseUrl: String, | ||||||
|  |             httpClient: HttpClient, | ||||||
|  |             contentType: ContentType, | ||||||
|  |             noinline idSerializer: suspend (IdType) -> String | ||||||
|  |         ) = KtorCRUDRepoClient( | ||||||
|  |             KtorReadCRUDRepoClient( | ||||||
|  |                 baseUrl, | ||||||
|  |                 httpClient, | ||||||
|  |                 typeInfo<ObjectType>(), | ||||||
|  |                 typeInfo<PaginationResult<ObjectType>>(), | ||||||
|  |                 contentType, | ||||||
|  |                 idSerializer | ||||||
|  |             ), | ||||||
|  |             KtorWriteCrudRepoClient<ObjectType, IdType, InputValue>( | ||||||
|  |                 baseUrl, | ||||||
|  |                 httpClient, | ||||||
|  |                 contentType | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke( | ||||||
|  |             baseUrl: String, | ||||||
|  |             subpart: String, | ||||||
|  |             httpClient: HttpClient, | ||||||
|  |             contentType: ContentType, | ||||||
|  |             noinline idSerializer: suspend (IdType) -> String | ||||||
|  |         ) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>( | ||||||
|  |             buildStandardUrl(baseUrl, subpart), | ||||||
|  |             httpClient, | ||||||
|  |             contentType, | ||||||
|  |             idSerializer | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     idsSerializer: KSerializer<IdType>, | ||||||
|  |     serialFormat: StringFormat, | ||||||
|  |     contentType: ContentType, | ||||||
|  | ) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(baseUrl, httpClient, contentType) { | ||||||
|  |     serialFormat.encodeToString(idsSerializer, it) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     idsSerializer: KSerializer<IdType>, | ||||||
|  |     serialFormat: BinaryFormat, | ||||||
|  |     contentType: ContentType, | ||||||
|  | ) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(baseUrl, httpClient, contentType) { | ||||||
|  |     serialFormat.encodeHex(idsSerializer, it) | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     subpart: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     contentType: ContentType, | ||||||
|  |     noinline idSerializer: suspend (IdType) -> String | ||||||
|  | ) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>( | ||||||
|  |     buildStandardUrl(baseUrl, subpart), | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     idSerializer | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     subpart: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     idsSerializer: KSerializer<IdType>, | ||||||
|  |     serialFormat: StringFormat, | ||||||
|  |     contentType: ContentType, | ||||||
|  | ) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat, contentType) | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, reified IdType, reified InputValue> KtorCRUDRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     subpart: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     idsSerializer: KSerializer<IdType>, | ||||||
|  |     serialFormat: BinaryFormat, | ||||||
|  |     contentType: ContentType, | ||||||
|  | ) = KtorCRUDRepoClient<ObjectType, IdType, InputValue>(buildStandardUrl(baseUrl, subpart), httpClient, idsSerializer, serialFormat, contentType) | ||||||
| @@ -0,0 +1,97 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.client.crud | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.pagination.* | ||||||
|  | import dev.inmo.micro_utils.repos.ReadCRUDRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.countRouting | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.crud.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.idParameterName | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.client.call.body | ||||||
|  | import io.ktor.client.request.get | ||||||
|  | import io.ktor.http.* | ||||||
|  | import io.ktor.util.reflect.TypeInfo | ||||||
|  | import io.ktor.util.reflect.typeInfo | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | class KtorReadCRUDRepoClient<ObjectType, IdType> ( | ||||||
|  |     private val baseUrl: String, | ||||||
|  |     private val httpClient: HttpClient, | ||||||
|  |     private val objectType: TypeInfo, | ||||||
|  |     private val paginationObjectType: TypeInfo, | ||||||
|  |     private val contentType: ContentType, | ||||||
|  |     private val idSerializer: suspend (IdType) -> String | ||||||
|  | ) : ReadCRUDRepo<ObjectType, IdType> { | ||||||
|  |     override suspend fun getByPagination(pagination: Pagination): PaginationResult<ObjectType> = httpClient.get( | ||||||
|  |         buildStandardUrl(baseUrl, getByPaginationRouting, pagination.asUrlQueryParts) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body(paginationObjectType) | ||||||
|  |  | ||||||
|  |     override suspend fun getById(id: IdType): ObjectType? = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             getByIdRouting, | ||||||
|  |             mapOf( | ||||||
|  |                 idParameterName to idSerializer(id) | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.takeIf { it.status != HttpStatusCode.NoContent } ?.body<ObjectType>(objectType) | ||||||
|  |  | ||||||
|  |     override suspend fun contains(id: IdType): Boolean = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             containsRouting, | ||||||
|  |             mapOf( | ||||||
|  |                 idParameterName to idSerializer(id) | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body() | ||||||
|  |  | ||||||
|  |     override suspend fun count(): Long = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             countRouting | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, IdType> KtorReadCRUDRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     contentType: ContentType, | ||||||
|  |     noinline idSerializer: suspend (IdType) -> String | ||||||
|  | ) = KtorReadCRUDRepoClient<ObjectType, IdType>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     typeInfo<ObjectType>(), | ||||||
|  |     typeInfo<PaginationResult<ObjectType>>(), | ||||||
|  |     contentType, | ||||||
|  |     idSerializer | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, IdType> KtorReadCRUDRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     idsSerializer: KSerializer<IdType>, | ||||||
|  |     serialFormat: StringFormat, | ||||||
|  |     contentType: ContentType, | ||||||
|  | ) = KtorReadCRUDRepoClient<ObjectType, IdType>(baseUrl, httpClient, contentType) { | ||||||
|  |     serialFormat.encodeToString(idsSerializer, it) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, IdType> KtorReadCRUDRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     idsSerializer: KSerializer<IdType>, | ||||||
|  |     serialFormat: BinaryFormat, | ||||||
|  |     contentType: ContentType, | ||||||
|  | ) = KtorReadCRUDRepoClient<ObjectType, IdType>(baseUrl, httpClient, contentType) { | ||||||
|  |     serialFormat.encodeHex(idsSerializer, it) | ||||||
|  | } | ||||||
| @@ -3,19 +3,22 @@ package dev.inmo.micro_utils.repos.ktor.client.crud | |||||||
| import dev.inmo.micro_utils.ktor.client.* | import dev.inmo.micro_utils.ktor.client.* | ||||||
| import dev.inmo.micro_utils.ktor.common.* | import dev.inmo.micro_utils.ktor.common.* | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo | import dev.inmo.micro_utils.repos.ReadCRUDRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.countRouting | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.crud.* | import dev.inmo.micro_utils.repos.ktor.common.crud.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.idParameterName | ||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
| import kotlinx.serialization.builtins.serializer | import kotlinx.serialization.builtins.serializer | ||||||
|  |  | ||||||
|  | @Deprecated("Use KtorReadCRUDRepoClient instead") | ||||||
| class KtorReadStandardCrudRepo<ObjectType, IdType> ( | class KtorReadStandardCrudRepo<ObjectType, IdType> ( | ||||||
|     private val baseUrl: String, |     private val baseUrl: String, | ||||||
|     private val unifiedRequester: UnifiedRequester, |     private val unifiedRequester: UnifiedRequester, | ||||||
|     private val objectsSerializer: KSerializer<ObjectType>, |     private val objectsSerializer: KSerializer<ObjectType>, | ||||||
|     private val objectsSerializerNullable: KSerializer<ObjectType?>, |     private val objectsSerializerNullable: KSerializer<ObjectType?>, | ||||||
|     private val idsSerializer: KSerializer<IdType> |     private val idsSerializer: KSerializer<IdType> | ||||||
| ) : ReadStandardCRUDRepo<ObjectType, IdType> { | ) : ReadCRUDRepo<ObjectType, IdType> { | ||||||
|     private val paginationResultSerializer = PaginationResult.serializer(objectsSerializer) |     private val paginationResultSerializer = PaginationResult.serializer(objectsSerializer) | ||||||
|  |  | ||||||
|     constructor( |     constructor( | ||||||
| @@ -38,9 +41,7 @@ class KtorReadStandardCrudRepo<ObjectType, IdType> ( | |||||||
|         buildStandardUrl( |         buildStandardUrl( | ||||||
|             baseUrl, |             baseUrl, | ||||||
|             getByIdRouting, |             getByIdRouting, | ||||||
|             mapOf( |             idParameterName to unifiedRequester.encodeUrlQueryValue(idsSerializer, id) | ||||||
|                 "id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id) |  | ||||||
|             ) |  | ||||||
|         ), |         ), | ||||||
|         objectsSerializerNullable |         objectsSerializerNullable | ||||||
|     ) |     ) | ||||||
| @@ -49,9 +50,7 @@ class KtorReadStandardCrudRepo<ObjectType, IdType> ( | |||||||
|         buildStandardUrl( |         buildStandardUrl( | ||||||
|             baseUrl, |             baseUrl, | ||||||
|             containsRouting, |             containsRouting, | ||||||
|             mapOf( |             idParameterName to unifiedRequester.encodeUrlQueryValue(idsSerializer, id) | ||||||
|                 "id" to unifiedRequester.encodeUrlQueryValue(idsSerializer, id) |  | ||||||
|             ) |  | ||||||
|         ), |         ), | ||||||
|         Boolean.serializer() |         Boolean.serializer() | ||||||
|     ) |     ) | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import dev.inmo.micro_utils.repos.* | |||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
|  |  | ||||||
|  | @Deprecated("Use KtorCRUDRepoClient instead") | ||||||
| class KtorStandardCrudRepo<ObjectType, IdType, InputValue> ( | class KtorStandardCrudRepo<ObjectType, IdType, InputValue> ( | ||||||
|     baseUrl: String, |     baseUrl: String, | ||||||
|     baseSubpart: String, |     baseSubpart: String, | ||||||
| @@ -15,15 +16,15 @@ class KtorStandardCrudRepo<ObjectType, IdType, InputValue> ( | |||||||
|     objectsNullableSerializer: KSerializer<ObjectType?>, |     objectsNullableSerializer: KSerializer<ObjectType?>, | ||||||
|     inputsSerializer: KSerializer<InputValue>, |     inputsSerializer: KSerializer<InputValue>, | ||||||
|     idsSerializer: KSerializer<IdType> |     idsSerializer: KSerializer<IdType> | ||||||
| ) : StandardCRUDRepo<ObjectType, IdType, InputValue>, | ) : CRUDRepo<ObjectType, IdType, InputValue>, | ||||||
|     ReadStandardCRUDRepo<ObjectType, IdType> by KtorReadStandardCrudRepo( |     ReadCRUDRepo<ObjectType, IdType> by KtorReadStandardCrudRepo( | ||||||
|         "$baseUrl/$baseSubpart", |         "$baseUrl/$baseSubpart", | ||||||
|         unifiedRequester, |         unifiedRequester, | ||||||
|         objectsSerializer, |         objectsSerializer, | ||||||
|         objectsNullableSerializer, |         objectsNullableSerializer, | ||||||
|         idsSerializer |         idsSerializer | ||||||
|     ), |     ), | ||||||
|     WriteStandardCRUDRepo<ObjectType, IdType, InputValue> by KtorWriteStandardCrudRepo( |     WriteCRUDRepo<ObjectType, IdType, InputValue> by KtorWriteStandardCrudRepo( | ||||||
|         "$baseUrl/$baseSubpart", |         "$baseUrl/$baseSubpart", | ||||||
|         unifiedRequester, |         unifiedRequester, | ||||||
|         objectsSerializer, |         objectsSerializer, | ||||||
|   | |||||||
| @@ -0,0 +1,85 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.client.crud | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.client.* | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.UpdatedValuePair | ||||||
|  | import dev.inmo.micro_utils.repos.WriteCRUDRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.crud.* | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.client.call.body | ||||||
|  | import io.ktor.client.request.* | ||||||
|  | import io.ktor.client.statement.HttpResponse | ||||||
|  | import io.ktor.http.ContentType | ||||||
|  | import io.ktor.http.contentType | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  |  | ||||||
|  | class KtorWriteCrudRepoClient<ObjectType, IdType, InputValue> ( | ||||||
|  |     private val baseUrl: String, | ||||||
|  |     private val httpClient: HttpClient, | ||||||
|  |     override val newObjectsFlow: Flow<ObjectType>, | ||||||
|  |     override val updatedObjectsFlow: Flow<ObjectType>, | ||||||
|  |     override val deletedObjectsIdsFlow: Flow<IdType>, | ||||||
|  |     private val createSetup: suspend HttpRequestBuilder.(List<InputValue>) -> Unit, | ||||||
|  |     private val updateSetup: suspend HttpRequestBuilder.(List<UpdatedValuePair<IdType, InputValue>>) -> Unit, | ||||||
|  |     private val deleteByIdSetup: suspend HttpRequestBuilder.(List<IdType>) -> Unit, | ||||||
|  |     private val createBodyGetter: suspend HttpResponse.() -> List<ObjectType>, | ||||||
|  |     private val updateBodyGetter: suspend HttpResponse.() -> List<ObjectType> | ||||||
|  | ) : WriteCRUDRepo<ObjectType, IdType, InputValue> { | ||||||
|  |     override suspend fun create(values: List<InputValue>): List<ObjectType> = httpClient.post( | ||||||
|  |         buildStandardUrl(baseUrl, createRouting) | ||||||
|  |     ) { | ||||||
|  |         createSetup(values) | ||||||
|  |     }.createBodyGetter() | ||||||
|  |  | ||||||
|  |     override suspend fun update( | ||||||
|  |         values: List<UpdatedValuePair<IdType, InputValue>> | ||||||
|  |     ): List<ObjectType> = httpClient.post( | ||||||
|  |         buildStandardUrl(baseUrl, updateRouting) | ||||||
|  |     ) { | ||||||
|  |         updateSetup(values) | ||||||
|  |     }.updateBodyGetter() | ||||||
|  |  | ||||||
|  |     override suspend fun update(id: IdType, value: InputValue): ObjectType? = update(listOf(id to value)).firstOrNull() | ||||||
|  |  | ||||||
|  |     override suspend fun deleteById(ids: List<IdType>) { | ||||||
|  |         httpClient.post( | ||||||
|  |             buildStandardUrl(baseUrl, deleteByIdRouting) | ||||||
|  |         ) { | ||||||
|  |             deleteByIdSetup(ids) | ||||||
|  |         }.throwOnUnsuccess { "Unable to delete $ids" } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     companion object { | ||||||
|  |         inline operator fun <reified ObjectType, reified IdType, reified InputValue> invoke( | ||||||
|  |             baseUrl: String, | ||||||
|  |             httpClient: HttpClient, | ||||||
|  |             contentType: ContentType | ||||||
|  |         ) = KtorWriteCrudRepoClient<ObjectType, IdType, InputValue>( | ||||||
|  |             baseUrl, | ||||||
|  |             httpClient, | ||||||
|  |             httpClient.createStandardWebsocketFlow( | ||||||
|  |                 buildStandardUrl(baseUrl, newObjectsFlowRouting), | ||||||
|  |             ), | ||||||
|  |             httpClient.createStandardWebsocketFlow( | ||||||
|  |                 buildStandardUrl(baseUrl, updatedObjectsFlowRouting), | ||||||
|  |             ), | ||||||
|  |             httpClient.createStandardWebsocketFlow( | ||||||
|  |                 buildStandardUrl(baseUrl, deletedObjectsIdsFlowRouting), | ||||||
|  |             ), | ||||||
|  |             { | ||||||
|  |                 contentType(contentType) | ||||||
|  |                 setBody(it) | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 contentType(contentType) | ||||||
|  |                 setBody(it) | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 contentType(contentType) | ||||||
|  |                 setBody(it) | ||||||
|  |             }, | ||||||
|  |             { body() }, | ||||||
|  |             { body() } | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -3,13 +3,14 @@ package dev.inmo.micro_utils.repos.ktor.client.crud | |||||||
| import dev.inmo.micro_utils.ktor.client.* | import dev.inmo.micro_utils.ktor.client.* | ||||||
| import dev.inmo.micro_utils.ktor.common.* | import dev.inmo.micro_utils.ktor.common.* | ||||||
| import dev.inmo.micro_utils.repos.UpdatedValuePair | import dev.inmo.micro_utils.repos.UpdatedValuePair | ||||||
| import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo | import dev.inmo.micro_utils.repos.WriteCRUDRepo | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.crud.* | import dev.inmo.micro_utils.repos.ktor.common.crud.* | ||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
| import kotlinx.serialization.builtins.* | import kotlinx.serialization.builtins.* | ||||||
|  |  | ||||||
|  | @Deprecated("Use KtorWriteCRUDRepoClient instead") | ||||||
| class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> ( | class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> ( | ||||||
|     private val baseUrl: String, |     private val baseUrl: String, | ||||||
|     private val unifiedRequester: UnifiedRequester, |     private val unifiedRequester: UnifiedRequester, | ||||||
| @@ -17,7 +18,7 @@ class KtorWriteStandardCrudRepo<ObjectType, IdType, InputValue> ( | |||||||
|     private val objectsNullableSerializer: KSerializer<ObjectType?>, |     private val objectsNullableSerializer: KSerializer<ObjectType?>, | ||||||
|     private val inputsSerializer: KSerializer<InputValue>, |     private val inputsSerializer: KSerializer<InputValue>, | ||||||
|     private val idsSerializer: KSerializer<IdType> |     private val idsSerializer: KSerializer<IdType> | ||||||
| ) : WriteStandardCRUDRepo<ObjectType, IdType, InputValue> { | ) : WriteCRUDRepo<ObjectType, IdType, InputValue> { | ||||||
|     private val listObjectsSerializer = ListSerializer(objectsSerializer) |     private val listObjectsSerializer = ListSerializer(objectsSerializer) | ||||||
|     private val listInputSerializer = ListSerializer(inputsSerializer) |     private val listInputSerializer = ListSerializer(inputsSerializer) | ||||||
|     private val listIdsSerializer = ListSerializer(idsSerializer) |     private val listIdsSerializer = ListSerializer(idsSerializer) | ||||||
|   | |||||||
| @@ -0,0 +1,85 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.client.key.value | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.* | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.http.ContentType | ||||||
|  | import io.ktor.http.encodeURLQueryComponent | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | class KtorKeyValueRepoClient<Key, Value> ( | ||||||
|  |     readDelegate: ReadKeyValueRepo<Key, Value>, | ||||||
|  |     writeDelegate: WriteKeyValueRepo<Key, Value> | ||||||
|  | ) : KeyValueRepo<Key, Value> by DelegateBasedKeyValueRepo( | ||||||
|  |     readDelegate, | ||||||
|  |     writeDelegate | ||||||
|  | ) { | ||||||
|  |     companion object { | ||||||
|  |         inline operator fun <reified Key, reified Value> invoke( | ||||||
|  |             baseUrl: String, | ||||||
|  |             httpClient: HttpClient, | ||||||
|  |             contentType: ContentType, | ||||||
|  |             noinline idSerializer: suspend (Key) -> String, | ||||||
|  |             noinline valueSerializer: suspend (Value) -> String | ||||||
|  |         ) = KtorKeyValueRepoClient( | ||||||
|  |             KtorReadKeyValueRepoClient( | ||||||
|  |                 baseUrl, httpClient, contentType, idSerializer, valueSerializer | ||||||
|  |             ), | ||||||
|  |             KtorWriteKeyValueRepoClient( | ||||||
|  |                 baseUrl, | ||||||
|  |                 httpClient, | ||||||
|  |                 contentType | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         inline operator fun <reified Key, reified Value> invoke( | ||||||
|  |             baseUrl: String, | ||||||
|  |             subpart: String, | ||||||
|  |             httpClient: HttpClient, | ||||||
|  |             contentType: ContentType, | ||||||
|  |             noinline idSerializer: suspend (Key) -> String, | ||||||
|  |             noinline valueSerializer: suspend (Value) -> String | ||||||
|  |         ) = KtorKeyValueRepoClient( | ||||||
|  |             buildStandardUrl(baseUrl, subpart), | ||||||
|  |             httpClient, | ||||||
|  |             contentType, | ||||||
|  |             idSerializer, | ||||||
|  |             valueSerializer | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> KtorKeyValueRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     contentType: ContentType, | ||||||
|  |     idSerializer: SerializationStrategy<Key>, | ||||||
|  |     valueSerializer: SerializationStrategy<Value>, | ||||||
|  |     serialFormat: StringFormat, | ||||||
|  | ) = KtorKeyValueRepoClient<Key, Value>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     { | ||||||
|  |         serialFormat.encodeToString(idSerializer, it).encodeURLQueryComponent() | ||||||
|  |     } | ||||||
|  | ) { | ||||||
|  |     serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> KtorKeyValueRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     contentType: ContentType, | ||||||
|  |     idSerializer: SerializationStrategy<Key>, | ||||||
|  |     valueSerializer: SerializationStrategy<Value>, | ||||||
|  |     serialFormat: BinaryFormat, | ||||||
|  | ) = KtorKeyValueRepoClient<Key, Value>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     { | ||||||
|  |         serialFormat.encodeHex(idSerializer, it) | ||||||
|  |     } | ||||||
|  | ) { | ||||||
|  |     serialFormat.encodeHex(valueSerializer, it) | ||||||
|  | } | ||||||
| @@ -0,0 +1,144 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.client.key.value | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.pagination.* | ||||||
|  | import dev.inmo.micro_utils.repos.ReadKeyValueRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.containsRoute | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.keyParameterName | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.key_value.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.client.call.body | ||||||
|  | import io.ktor.client.request.get | ||||||
|  | import io.ktor.http.* | ||||||
|  | import io.ktor.util.reflect.TypeInfo | ||||||
|  | import io.ktor.util.reflect.typeInfo | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | class KtorReadKeyValueRepoClient<Key, Value>( | ||||||
|  |     private val baseUrl: String, | ||||||
|  |     private val httpClient: HttpClient, | ||||||
|  |     private val contentType: ContentType, | ||||||
|  |     private val objectType: TypeInfo, | ||||||
|  |     private val paginationResultObjectsTypeInfo: TypeInfo, | ||||||
|  |     private val paginationResultIdsTypeInfo: TypeInfo, | ||||||
|  |     private val idSerializer: suspend (Key) -> String, | ||||||
|  |     private val valueSerializer: suspend (Value) -> String | ||||||
|  | ) : ReadKeyValueRepo<Key, Value> { | ||||||
|  |     override suspend fun get(k: Key): Value? = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             getRoute, | ||||||
|  |             mapOf( | ||||||
|  |                 keyParameterName to idSerializer(k) | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.takeIf { it.status != HttpStatusCode.NoContent } ?.body<Value>(objectType) | ||||||
|  |  | ||||||
|  |     override suspend fun contains(key: Key): Boolean = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             containsRoute, | ||||||
|  |             keyParameterName to idSerializer(key) | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body() | ||||||
|  |  | ||||||
|  |     override suspend fun values( | ||||||
|  |         pagination: Pagination, | ||||||
|  |         reversed: Boolean | ||||||
|  |     ): PaginationResult<Value> = httpClient.get( | ||||||
|  |         buildStandardUrl(baseUrl, valuesRoute, pagination.asUrlQueryParts + (reversedParameterName to reversed.toString())) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body(paginationResultObjectsTypeInfo) | ||||||
|  |  | ||||||
|  |     override suspend fun keys( | ||||||
|  |         pagination: Pagination, | ||||||
|  |         reversed: Boolean | ||||||
|  |     ): PaginationResult<Key> = httpClient.get( | ||||||
|  |         buildStandardUrl(baseUrl, keysRoute, pagination.asUrlQueryParts + (reversedParameterName to reversed.toString())) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body(paginationResultIdsTypeInfo) | ||||||
|  |  | ||||||
|  |     override suspend fun keys( | ||||||
|  |         v: Value, | ||||||
|  |         pagination: Pagination, | ||||||
|  |         reversed: Boolean | ||||||
|  |     ): PaginationResult<Key> = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             keysRoute, | ||||||
|  |             pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (valueParameterName to valueSerializer(v)) | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body(paginationResultIdsTypeInfo) | ||||||
|  |  | ||||||
|  |     override suspend fun count(): Long = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             dev.inmo.micro_utils.repos.ktor.common.countRoute | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> KtorReadKeyValueRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     contentType: ContentType, | ||||||
|  |     noinline idSerializer: suspend (Key) -> String, | ||||||
|  |     noinline valueSerializer: suspend (Value) -> String | ||||||
|  | ) = KtorReadKeyValueRepoClient<Key, Value>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     typeInfo<Value>(), | ||||||
|  |     typeInfo<PaginationResult<Value>>(), | ||||||
|  |     typeInfo<PaginationResult<Key>>(), | ||||||
|  |     idSerializer, | ||||||
|  |     valueSerializer | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> KtorReadKeyValueRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     idsSerializer: KSerializer<Key>, | ||||||
|  |     valueSerializer: KSerializer<Value>, | ||||||
|  |     serialFormat: StringFormat, | ||||||
|  |     contentType: ContentType, | ||||||
|  | ) = KtorReadKeyValueRepoClient<Key, Value>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     { | ||||||
|  |         serialFormat.encodeToString(idsSerializer, it).encodeURLQueryComponent() | ||||||
|  |     } | ||||||
|  | ) { | ||||||
|  |     serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> KtorReadKeyValueRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     idsSerializer: KSerializer<Key>, | ||||||
|  |     valuesSerializer: KSerializer<Value>, | ||||||
|  |     serialFormat: BinaryFormat, | ||||||
|  |     contentType: ContentType, | ||||||
|  | ) = KtorReadKeyValueRepoClient<Key, Value>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     { | ||||||
|  |         serialFormat.encodeHex(idsSerializer, it) | ||||||
|  |     } | ||||||
|  | ) { | ||||||
|  |     serialFormat.encodeHex(valuesSerializer, it) | ||||||
|  | } | ||||||
| @@ -0,0 +1,79 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.client.key.value | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow | ||||||
|  | import dev.inmo.micro_utils.ktor.client.throwOnUnsuccess | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.WriteKeyValueRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.key_value.* | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.client.request.post | ||||||
|  | import io.ktor.http.* | ||||||
|  | import io.ktor.util.InternalAPI | ||||||
|  | import io.ktor.util.reflect.TypeInfo | ||||||
|  | import io.ktor.util.reflect.typeInfo | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  |  | ||||||
|  | class KtorWriteKeyValueRepoClient<Key, Value>( | ||||||
|  |     private val baseUrl: String, | ||||||
|  |     private val httpClient: HttpClient, | ||||||
|  |     private val contentType: ContentType, | ||||||
|  |     override val onNewValue: Flow<Pair<Key, Value>>, | ||||||
|  |     override val onValueRemoved: Flow<Key>, | ||||||
|  |     private val idsListTypeInfo: TypeInfo, | ||||||
|  |     private val objectsListTypeInfo: TypeInfo, | ||||||
|  |     private val idsToObjectsMapTypeInfo: TypeInfo | ||||||
|  | ) : WriteKeyValueRepo<Key, Value> { | ||||||
|  |     @OptIn(InternalAPI::class) | ||||||
|  |     override suspend fun unsetWithValues(toUnset: List<Value>) { | ||||||
|  |         httpClient.post( | ||||||
|  |             buildStandardUrl(baseUrl, unsetWithValuesRoute) | ||||||
|  |         ) { | ||||||
|  |             body = toUnset | ||||||
|  |             bodyType = objectsListTypeInfo | ||||||
|  |             contentType(contentType) | ||||||
|  |         }.throwOnUnsuccess { "Unable to unset data with values $toUnset" } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @OptIn(InternalAPI::class) | ||||||
|  |     override suspend fun unset(toUnset: List<Key>) { | ||||||
|  |         httpClient.post( | ||||||
|  |             buildStandardUrl(baseUrl, unsetRoute) | ||||||
|  |         ) { | ||||||
|  |             body = toUnset | ||||||
|  |             bodyType = idsListTypeInfo | ||||||
|  |             contentType(contentType) | ||||||
|  |         }.throwOnUnsuccess { "Unable to unset $toUnset" } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @OptIn(InternalAPI::class) | ||||||
|  |     override suspend fun set(toSet: Map<Key, Value>) { | ||||||
|  |         httpClient.post( | ||||||
|  |             buildStandardUrl(baseUrl, setRoute) | ||||||
|  |         ) { | ||||||
|  |             body = toSet | ||||||
|  |             bodyType = idsToObjectsMapTypeInfo | ||||||
|  |             contentType(contentType) | ||||||
|  |         }.throwOnUnsuccess { "Unable to set $toSet" } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     companion object { | ||||||
|  |         inline operator fun <reified Key, reified Value> invoke( | ||||||
|  |             baseUrl: String, | ||||||
|  |             httpClient: HttpClient, | ||||||
|  |             contentType: ContentType | ||||||
|  |         ) = KtorWriteKeyValueRepoClient<Key, Value>( | ||||||
|  |             baseUrl, | ||||||
|  |             httpClient, | ||||||
|  |             contentType, | ||||||
|  |             httpClient.createStandardWebsocketFlow( | ||||||
|  |                 buildStandardUrl(baseUrl, onNewValueRoute), | ||||||
|  |             ), | ||||||
|  |             httpClient.createStandardWebsocketFlow( | ||||||
|  |                 buildStandardUrl(baseUrl, onValueRemovedRoute), | ||||||
|  |             ), | ||||||
|  |             typeInfo<List<Key>>(), | ||||||
|  |             typeInfo<List<Value>>(), | ||||||
|  |             typeInfo<Map<Key, Value>>() | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,89 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.client.key.values | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.* | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.http.ContentType | ||||||
|  | import io.ktor.http.encodeURLQueryComponent | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | class KtorKeyValuesRepoClient<Key, Value> ( | ||||||
|  |     readDelegate: ReadKeyValuesRepo<Key, Value>, | ||||||
|  |     writeDelegate: WriteKeyValuesRepo<Key, Value> | ||||||
|  | ) : KeyValuesRepo<Key, Value> by DelegateBasedKeyValuesRepo( | ||||||
|  |     readDelegate, | ||||||
|  |     writeDelegate | ||||||
|  | ) { | ||||||
|  |     companion object { | ||||||
|  |         inline operator fun <reified Key : Any, reified Value : Any> invoke( | ||||||
|  |             baseUrl: String, | ||||||
|  |             httpClient: HttpClient, | ||||||
|  |             contentType: ContentType, | ||||||
|  |             noinline keySerializer: suspend (Key) -> String, | ||||||
|  |             noinline valueSerializer: suspend (Value) -> String | ||||||
|  |         ) = KtorKeyValuesRepoClient( | ||||||
|  |             KtorReadKeyValuesRepoClient( | ||||||
|  |                 baseUrl, | ||||||
|  |                 httpClient, | ||||||
|  |                 contentType, | ||||||
|  |                 keySerializer, | ||||||
|  |                 valueSerializer | ||||||
|  |             ), | ||||||
|  |             KtorWriteKeyValuesRepoClient( | ||||||
|  |                 baseUrl, | ||||||
|  |                 httpClient, | ||||||
|  |                 contentType | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         inline operator fun <reified Key : Any, reified Value : Any> invoke( | ||||||
|  |             baseUrl: String, | ||||||
|  |             subpart: String, | ||||||
|  |             httpClient: HttpClient, | ||||||
|  |             contentType: ContentType, | ||||||
|  |             noinline keySerializer: suspend (Key) -> String, | ||||||
|  |             noinline valueSerializer: suspend (Value) -> String | ||||||
|  |         ) = KtorKeyValuesRepoClient( | ||||||
|  |             buildStandardUrl(baseUrl, subpart), | ||||||
|  |             httpClient, | ||||||
|  |             contentType, | ||||||
|  |             keySerializer, | ||||||
|  |             valueSerializer | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key : Any, reified Value : Any> KtorKeyValuesRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     contentType: ContentType, | ||||||
|  |     keySerializer: SerializationStrategy<Key>, | ||||||
|  |     valueSerializer: SerializationStrategy<Value>, | ||||||
|  |     serialFormat: StringFormat, | ||||||
|  | ) = KtorKeyValuesRepoClient<Key, Value>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     { | ||||||
|  |         serialFormat.encodeToString(keySerializer, it).encodeURLQueryComponent() | ||||||
|  |     } | ||||||
|  | ) { | ||||||
|  |     serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key : Any, reified Value : Any> KtorKeyValuesRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     contentType: ContentType, | ||||||
|  |     keySerializer: SerializationStrategy<Key>, | ||||||
|  |     valueSerializer: SerializationStrategy<Value>, | ||||||
|  |     serialFormat: BinaryFormat, | ||||||
|  | ) = KtorKeyValuesRepoClient<Key, Value>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     { | ||||||
|  |         serialFormat.encodeHex(keySerializer, it) | ||||||
|  |     } | ||||||
|  | ) { | ||||||
|  |     serialFormat.encodeHex(valueSerializer, it) | ||||||
|  | } | ||||||
| @@ -0,0 +1,158 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.client.key.values | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.pagination.* | ||||||
|  | import dev.inmo.micro_utils.repos.ReadKeyValuesRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.client.call.body | ||||||
|  | import io.ktor.client.request.get | ||||||
|  | import io.ktor.http.* | ||||||
|  | import io.ktor.util.reflect.TypeInfo | ||||||
|  | import io.ktor.util.reflect.typeInfo | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | class KtorReadKeyValuesRepoClient<Key, Value>( | ||||||
|  |     private val baseUrl: String, | ||||||
|  |     private val httpClient: HttpClient, | ||||||
|  |     private val contentType: ContentType, | ||||||
|  |     private val paginationResultValuesTypeInfo: TypeInfo, | ||||||
|  |     private val paginationResultKeysTypeInfo: TypeInfo, | ||||||
|  |     private val keySerializer: suspend (Key) -> String, | ||||||
|  |     private val valueSerializer: suspend (Value) -> String | ||||||
|  | ) : ReadKeyValuesRepo<Key, Value> { | ||||||
|  |     override suspend fun get( | ||||||
|  |         k: Key, | ||||||
|  |         pagination: Pagination, | ||||||
|  |         reversed: Boolean | ||||||
|  |     ): PaginationResult<Value> = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             getRoute, | ||||||
|  |             pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (keyParameterName to keySerializer(k)) | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body(paginationResultValuesTypeInfo) | ||||||
|  |  | ||||||
|  |     override suspend fun keys( | ||||||
|  |         pagination: Pagination, | ||||||
|  |         reversed: Boolean | ||||||
|  |     ): PaginationResult<Key> = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             keysRoute, | ||||||
|  |             pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body(paginationResultKeysTypeInfo) | ||||||
|  |  | ||||||
|  |     override suspend fun keys( | ||||||
|  |         v: Value, | ||||||
|  |         pagination: Pagination, | ||||||
|  |         reversed: Boolean | ||||||
|  |     ): PaginationResult<Key> = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             keysRoute, | ||||||
|  |             pagination.asUrlQueryParts + (reversedParameterName to reversed.toString()) + (valueParameterName to valueSerializer(v)) | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body(paginationResultKeysTypeInfo) | ||||||
|  |  | ||||||
|  |     override suspend fun contains(k: Key): Boolean = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             containsRoute, | ||||||
|  |             keyParameterName to keySerializer(k) | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body() | ||||||
|  |  | ||||||
|  |     override suspend fun contains(k: Key, v: Value): Boolean = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             containsRoute, | ||||||
|  |             keyParameterName to keySerializer(k), | ||||||
|  |             valueParameterName to valueSerializer(v) | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body() | ||||||
|  |  | ||||||
|  |     override suspend fun count(): Long = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             countRouting | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body() | ||||||
|  |  | ||||||
|  |     override suspend fun count(k: Key): Long = httpClient.get( | ||||||
|  |         buildStandardUrl( | ||||||
|  |             baseUrl, | ||||||
|  |             countRouting, | ||||||
|  |             keyParameterName to keySerializer(k), | ||||||
|  |         ) | ||||||
|  |     ) { | ||||||
|  |         contentType(contentType) | ||||||
|  |     }.body() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> KtorReadKeyValuesRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     contentType: ContentType, | ||||||
|  |     noinline keySerializer: suspend (Key) -> String, | ||||||
|  |     noinline valueSerializer: suspend (Value) -> String | ||||||
|  | ) = KtorReadKeyValuesRepoClient<Key, Value>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     typeInfo<PaginationResult<Value>>(), | ||||||
|  |     typeInfo<PaginationResult<Key>>(), | ||||||
|  |     keySerializer, | ||||||
|  |     valueSerializer | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> KtorReadKeyValuesRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     idsSerializer: KSerializer<Key>, | ||||||
|  |     valueSerializer: KSerializer<Value>, | ||||||
|  |     serialFormat: StringFormat, | ||||||
|  |     contentType: ContentType, | ||||||
|  | ) = KtorReadKeyValuesRepoClient<Key, Value>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     { | ||||||
|  |         serialFormat.encodeToString(idsSerializer, it).encodeURLQueryComponent() | ||||||
|  |     } | ||||||
|  | ) { | ||||||
|  |     serialFormat.encodeToString(valueSerializer, it).encodeURLQueryComponent() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> KtorReadKeyValuesRepoClient( | ||||||
|  |     baseUrl: String, | ||||||
|  |     httpClient: HttpClient, | ||||||
|  |     idsSerializer: KSerializer<Key>, | ||||||
|  |     valuesSerializer: KSerializer<Value>, | ||||||
|  |     serialFormat: BinaryFormat, | ||||||
|  |     contentType: ContentType, | ||||||
|  | ) = KtorReadKeyValuesRepoClient<Key, Value>( | ||||||
|  |     baseUrl, | ||||||
|  |     httpClient, | ||||||
|  |     contentType, | ||||||
|  |     { | ||||||
|  |         serialFormat.encodeHex(idsSerializer, it) | ||||||
|  |     } | ||||||
|  | ) { | ||||||
|  |     serialFormat.encodeHex(valuesSerializer, it) | ||||||
|  | } | ||||||
| @@ -0,0 +1,106 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.client.key.values | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow | ||||||
|  | import dev.inmo.micro_utils.ktor.client.throwOnUnsuccess | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.WriteKeyValuesRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.client.request.post | ||||||
|  | import io.ktor.http.* | ||||||
|  | import io.ktor.util.InternalAPI | ||||||
|  | import io.ktor.util.reflect.TypeInfo | ||||||
|  | import io.ktor.util.reflect.typeInfo | ||||||
|  | import kotlinx.coroutines.flow.Flow | ||||||
|  |  | ||||||
|  | class KtorWriteKeyValuesRepoClient<Key : Any, Value : Any>( | ||||||
|  |     private val baseUrl: String, | ||||||
|  |     private val httpClient: HttpClient, | ||||||
|  |     private val contentType: ContentType, | ||||||
|  |     override val onNewValue: Flow<Pair<Key, Value>>, | ||||||
|  |     override val onValueRemoved: Flow<Pair<Key, Value>>, | ||||||
|  |     override val onDataCleared: Flow<Key>, | ||||||
|  |     private val keyTypeInfo: TypeInfo, | ||||||
|  |     private val valueTypeInfo: TypeInfo, | ||||||
|  |     private val keyToValuesMapTypeInfo: TypeInfo | ||||||
|  | ) : WriteKeyValuesRepo<Key, Value> { | ||||||
|  |  | ||||||
|  |     @OptIn(InternalAPI::class) | ||||||
|  |     override suspend fun add(toAdd: Map<Key, List<Value>>) { | ||||||
|  |         httpClient.post( | ||||||
|  |             buildStandardUrl(baseUrl, addRoute) | ||||||
|  |         ) { | ||||||
|  |             body = toAdd | ||||||
|  |             bodyType = keyToValuesMapTypeInfo | ||||||
|  |             contentType(contentType) | ||||||
|  |         }.throwOnUnsuccess { "Unable to add $toAdd" } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @OptIn(InternalAPI::class) | ||||||
|  |     override suspend fun remove(toRemove: Map<Key, List<Value>>) { | ||||||
|  |         httpClient.post( | ||||||
|  |             buildStandardUrl(baseUrl, removeRoute) | ||||||
|  |         ) { | ||||||
|  |             body = toRemove | ||||||
|  |             bodyType = keyToValuesMapTypeInfo | ||||||
|  |             contentType(contentType) | ||||||
|  |         }.throwOnUnsuccess { "Unable to remove $toRemove" } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @OptIn(InternalAPI::class) | ||||||
|  |     override suspend fun clear(k: Key) { | ||||||
|  |         httpClient.post( | ||||||
|  |             buildStandardUrl(baseUrl, clearRoute) | ||||||
|  |         ) { | ||||||
|  |             body = k | ||||||
|  |             bodyType = keyTypeInfo | ||||||
|  |             contentType(contentType) | ||||||
|  |         }.throwOnUnsuccess { "Unable to clear data with key $k" } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @OptIn(InternalAPI::class) | ||||||
|  |     override suspend fun clearWithValue(v: Value) { | ||||||
|  |         httpClient.post( | ||||||
|  |             buildStandardUrl(baseUrl, clearWithValueRoute) | ||||||
|  |         ) { | ||||||
|  |             body = v | ||||||
|  |             bodyType = valueTypeInfo | ||||||
|  |             contentType(contentType) | ||||||
|  |         }.throwOnUnsuccess { "Unable to clear data with value $v" } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @OptIn(InternalAPI::class) | ||||||
|  |     override suspend fun set(toSet: Map<Key, List<Value>>) { | ||||||
|  |         httpClient.post( | ||||||
|  |             buildStandardUrl(baseUrl, setRoute) | ||||||
|  |         ) { | ||||||
|  |             body = toSet | ||||||
|  |             bodyType = keyToValuesMapTypeInfo | ||||||
|  |             contentType(contentType) | ||||||
|  |         }.throwOnUnsuccess { "Unable to set data $toSet" } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     companion object { | ||||||
|  |         inline operator fun <reified Key : Any, reified Value : Any> invoke( | ||||||
|  |             baseUrl: String, | ||||||
|  |             httpClient: HttpClient, | ||||||
|  |             contentType: ContentType | ||||||
|  |         ) = KtorWriteKeyValuesRepoClient<Key, Value>( | ||||||
|  |             baseUrl, | ||||||
|  |             httpClient, | ||||||
|  |             contentType, | ||||||
|  |             httpClient.createStandardWebsocketFlow( | ||||||
|  |                 buildStandardUrl(baseUrl, onNewValueRoute), | ||||||
|  |             ), | ||||||
|  |             httpClient.createStandardWebsocketFlow( | ||||||
|  |                 buildStandardUrl(baseUrl, onValueRemovedRoute), | ||||||
|  |             ), | ||||||
|  |             httpClient.createStandardWebsocketFlow( | ||||||
|  |                 buildStandardUrl(baseUrl, onDataClearedRoute), | ||||||
|  |             ), | ||||||
|  |             typeInfo<Key>(), | ||||||
|  |             typeInfo<Value>(), | ||||||
|  |             typeInfo<Map<Key, List<Value>>>() | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -3,20 +3,25 @@ package dev.inmo.micro_utils.repos.ktor.client.key_value | |||||||
| import dev.inmo.micro_utils.ktor.client.* | import dev.inmo.micro_utils.ktor.client.* | ||||||
| import dev.inmo.micro_utils.ktor.common.* | import dev.inmo.micro_utils.ktor.common.* | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo | import dev.inmo.micro_utils.repos.ReadKeyValueRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.containsRoute | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.countRoute | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.key_value.* | import dev.inmo.micro_utils.repos.ktor.common.key_value.* | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.valueParameterName | import dev.inmo.micro_utils.repos.ktor.common.key_value.keyParameterName | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.key_value.reversedParameterName | ||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import kotlinx.serialization.* | import kotlinx.serialization.* | ||||||
| import kotlinx.serialization.builtins.serializer | import kotlinx.serialization.builtins.serializer | ||||||
|  |  | ||||||
|  | @Deprecated("Replaced with KtorReadKeyValueRepoClient") | ||||||
| class KtorReadStandardKeyValueRepo<Key, Value> ( | class KtorReadStandardKeyValueRepo<Key, Value> ( | ||||||
|     private val baseUrl: String, |     private val baseUrl: String, | ||||||
|     private val unifiedRequester: UnifiedRequester, |     private val unifiedRequester: UnifiedRequester, | ||||||
|     private val keySerializer: KSerializer<Key>, |     private val keySerializer: KSerializer<Key>, | ||||||
|     private val valueSerializer: KSerializer<Value>, |     private val valueSerializer: KSerializer<Value>, | ||||||
|     private val valueNullableSerializer: KSerializer<Value?> |     private val valueNullableSerializer: KSerializer<Value?> | ||||||
| ) : ReadStandardKeyValueRepo<Key, Value> { | ) : ReadKeyValueRepo<Key, Value> { | ||||||
|     constructor( |     constructor( | ||||||
|         baseUrl: String, |         baseUrl: String, | ||||||
|         client: HttpClient, |         client: HttpClient, | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import dev.inmo.micro_utils.repos.* | |||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import kotlinx.serialization.* | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | @Deprecated("Replaced with KtorKeyValueRepoClient") | ||||||
| @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") | @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") | ||||||
| class KtorStandartKeyValueRepo<K, V> ( | class KtorStandartKeyValueRepo<K, V> ( | ||||||
|     baseUrl: String, |     baseUrl: String, | ||||||
| @@ -15,15 +16,15 @@ class KtorStandartKeyValueRepo<K, V> ( | |||||||
|     keySerializer: KSerializer<K>, |     keySerializer: KSerializer<K>, | ||||||
|     valueSerializer: KSerializer<V>, |     valueSerializer: KSerializer<V>, | ||||||
|     valueNullableSerializer: KSerializer<V?> |     valueNullableSerializer: KSerializer<V?> | ||||||
| ) : StandardKeyValueRepo<K, V>, | ) : KeyValueRepo<K, V>, | ||||||
|     ReadStandardKeyValueRepo<K, V> by KtorReadStandardKeyValueRepo( |     ReadKeyValueRepo<K, V> by KtorReadStandardKeyValueRepo( | ||||||
|         "$baseUrl/$baseSubpart", |         "$baseUrl/$baseSubpart", | ||||||
|         unifiedRequester, |         unifiedRequester, | ||||||
|         keySerializer, |         keySerializer, | ||||||
|         valueSerializer, |         valueSerializer, | ||||||
|         valueNullableSerializer |         valueNullableSerializer | ||||||
|     ), |     ), | ||||||
|     WriteStandardKeyValueRepo<K, V> by KtorWriteStandardKeyValueRepo( |     WriteKeyValueRepo<K, V> by KtorWriteStandardKeyValueRepo( | ||||||
|         "$baseUrl/$baseSubpart", |         "$baseUrl/$baseSubpart", | ||||||
|         unifiedRequester, |         unifiedRequester, | ||||||
|         keySerializer, |         keySerializer, | ||||||
|   | |||||||
| @@ -2,19 +2,20 @@ package dev.inmo.micro_utils.repos.ktor.client.key_value | |||||||
|  |  | ||||||
| import dev.inmo.micro_utils.ktor.client.* | import dev.inmo.micro_utils.ktor.client.* | ||||||
| import dev.inmo.micro_utils.ktor.common.* | import dev.inmo.micro_utils.ktor.common.* | ||||||
| import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo | import dev.inmo.micro_utils.repos.WriteKeyValueRepo | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.key_value.* | import dev.inmo.micro_utils.repos.ktor.common.key_value.* | ||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
| import kotlinx.serialization.builtins.* | import kotlinx.serialization.builtins.* | ||||||
|  |  | ||||||
|  | @Deprecated("Replaced with KtorWriteKeyValueRepoClient") | ||||||
| class KtorWriteStandardKeyValueRepo<K, V> ( | class KtorWriteStandardKeyValueRepo<K, V> ( | ||||||
|     private var baseUrl: String, |     private var baseUrl: String, | ||||||
|     private var unifiedRequester: UnifiedRequester, |     private var unifiedRequester: UnifiedRequester, | ||||||
|     private var keySerializer: KSerializer<K>, |     private var keySerializer: KSerializer<K>, | ||||||
|     private var valueSerializer: KSerializer<V>, |     private var valueSerializer: KSerializer<V>, | ||||||
| ) : WriteStandardKeyValueRepo<K, V> { | ) : WriteKeyValueRepo<K, V> { | ||||||
|     private val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer) |     private val keyValueMapSerializer = MapSerializer(keySerializer, valueSerializer) | ||||||
|     private val keysListSerializer = ListSerializer(keySerializer) |     private val keysListSerializer = ListSerializer(keySerializer) | ||||||
|     private val valuesListSerializer = ListSerializer(valueSerializer) |     private val valuesListSerializer = ListSerializer(valueSerializer) | ||||||
|   | |||||||
| @@ -7,20 +7,21 @@ import dev.inmo.micro_utils.repos.* | |||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
|  |  | ||||||
|  | @Deprecated("Should be replaced with KtorKeyValuesRepoClient") | ||||||
| class KtorOneToManyKeyValueRepo<Key, Value>( | class KtorOneToManyKeyValueRepo<Key, Value>( | ||||||
|     baseUrl: String, |     baseUrl: String, | ||||||
|     baseSubpart: String, |     baseSubpart: String, | ||||||
|     unifiedRequester: UnifiedRequester, |     unifiedRequester: UnifiedRequester, | ||||||
|     keySerializer: KSerializer<Key>, |     keySerializer: KSerializer<Key>, | ||||||
|     valueSerializer: KSerializer<Value>, |     valueSerializer: KSerializer<Value>, | ||||||
| ) : OneToManyKeyValueRepo<Key, Value>, | ) : KeyValuesRepo<Key, Value>, | ||||||
|     ReadOneToManyKeyValueRepo<Key, Value> by KtorReadOneToManyKeyValueRepo<Key, Value> ( |     ReadKeyValuesRepo<Key, Value> by KtorReadOneToManyKeyValueRepo<Key, Value> ( | ||||||
|         "$baseUrl/$baseSubpart", |         "$baseUrl/$baseSubpart", | ||||||
|         unifiedRequester, |         unifiedRequester, | ||||||
|         keySerializer, |         keySerializer, | ||||||
|         valueSerializer, |         valueSerializer, | ||||||
|     ), |     ), | ||||||
|     WriteOneToManyKeyValueRepo<Key, Value> by KtorWriteOneToManyKeyValueRepo<Key, Value> ( |     WriteKeyValuesRepo<Key, Value> by KtorWriteOneToManyKeyValueRepo<Key, Value> ( | ||||||
|         "$baseUrl/$baseSubpart", |         "$baseUrl/$baseSubpart", | ||||||
|         unifiedRequester, |         unifiedRequester, | ||||||
|         keySerializer, |         keySerializer, | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.client.one_to_many | |||||||
| import dev.inmo.micro_utils.ktor.client.* | import dev.inmo.micro_utils.ktor.client.* | ||||||
| import dev.inmo.micro_utils.ktor.common.* | import dev.inmo.micro_utils.ktor.common.* | ||||||
| import dev.inmo.micro_utils.pagination.* | import dev.inmo.micro_utils.pagination.* | ||||||
| import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo | import dev.inmo.micro_utils.repos.ReadKeyValuesRepo | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.keyParameterName | import dev.inmo.micro_utils.repos.ktor.common.keyParameterName | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName | import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName | ||||||
| @@ -12,12 +12,13 @@ import io.ktor.client.HttpClient | |||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
| import kotlinx.serialization.builtins.serializer | import kotlinx.serialization.builtins.serializer | ||||||
|  |  | ||||||
|  | @Deprecated("Should be replaced with KtorReadKeyValuesRepoClient") | ||||||
| class KtorReadOneToManyKeyValueRepo<Key, Value> ( | class KtorReadOneToManyKeyValueRepo<Key, Value> ( | ||||||
|     private val baseUrl: String, |     private val baseUrl: String, | ||||||
|     private val unifiedRequester: UnifiedRequester, |     private val unifiedRequester: UnifiedRequester, | ||||||
|     private val keySerializer: KSerializer<Key>, |     private val keySerializer: KSerializer<Key>, | ||||||
|     private val valueSerializer: KSerializer<Value> |     private val valueSerializer: KSerializer<Value> | ||||||
| ) : ReadOneToManyKeyValueRepo<Key, Value> { | ) : ReadKeyValuesRepo<Key, Value> { | ||||||
|     private val paginationValueResultSerializer = PaginationResult.serializer(valueSerializer) |     private val paginationValueResultSerializer = PaginationResult.serializer(valueSerializer) | ||||||
|     private val paginationKeyResultSerializer = PaginationResult.serializer(keySerializer) |     private val paginationKeyResultSerializer = PaginationResult.serializer(keySerializer) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,19 +2,20 @@ package dev.inmo.micro_utils.repos.ktor.client.one_to_many | |||||||
|  |  | ||||||
| import dev.inmo.micro_utils.ktor.client.* | import dev.inmo.micro_utils.ktor.client.* | ||||||
| import dev.inmo.micro_utils.ktor.common.* | import dev.inmo.micro_utils.ktor.common.* | ||||||
| import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo | import dev.inmo.micro_utils.repos.WriteKeyValuesRepo | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | ||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
| import kotlinx.serialization.builtins.* | import kotlinx.serialization.builtins.* | ||||||
|  |  | ||||||
|  | @Deprecated("Should be replaced with KtorWriteKeyValuesRepoClient") | ||||||
| class KtorWriteOneToManyKeyValueRepo<Key, Value> ( | class KtorWriteOneToManyKeyValueRepo<Key, Value> ( | ||||||
|     private val baseUrl: String, |     private val baseUrl: String, | ||||||
|     private val unifiedRequester: UnifiedRequester, |     private val unifiedRequester: UnifiedRequester, | ||||||
|     private val keySerializer: KSerializer<Key>, |     private val keySerializer: KSerializer<Key>, | ||||||
|     private val valueSerializer: KSerializer<Value> |     private val valueSerializer: KSerializer<Value> | ||||||
| ) : WriteOneToManyKeyValueRepo<Key, Value> { | ) : WriteKeyValuesRepo<Key, Value> { | ||||||
|     private val keyValueSerializer = PairSerializer(keySerializer, valueSerializer) |     private val keyValueSerializer = PairSerializer(keySerializer, valueSerializer) | ||||||
|     private val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer)) |     private val keyValueMapSerializer = MapSerializer(keySerializer, ListSerializer(valueSerializer)) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,5 +13,22 @@ kotlin { | |||||||
|                 api internalProject("micro_utils.repos.common") |                 api internalProject("micro_utils.repos.common") | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         jvmTest { | ||||||
|  |             dependencies { | ||||||
|  |                 implementation internalProject("micro_utils.repos.common") | ||||||
|  |                 implementation internalProject("micro_utils.repos.ktor.client") | ||||||
|  |                 implementation internalProject("micro_utils.repos.ktor.server") | ||||||
|  |                 implementation internalProject("micro_utils.repos.inmemory") | ||||||
|  |                 implementation libs.kt.coroutines.test | ||||||
|  |  | ||||||
|  |                 implementation libs.ktor.server.cio | ||||||
|  |                 implementation libs.ktor.client.cio | ||||||
|  |                 implementation libs.ktor.server.content.negotiation | ||||||
|  |                 implementation libs.ktor.serialization.kotlinx.json | ||||||
|  |                 implementation libs.ktor.client.content.negotiation | ||||||
|  |                 implementation libs.ktor.client.logging | ||||||
|  |                 implementation libs.ktor.client.websockets | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.common | ||||||
|  |  | ||||||
|  | const val containsRoute = "contains" | ||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.common | ||||||
|  |  | ||||||
|  | const val countRoute = "count" | ||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.common | ||||||
|  |  | ||||||
|  | const val countRouting = "count" | ||||||
| @@ -1,5 +1,6 @@ | |||||||
| package dev.inmo.micro_utils.repos.ktor.common | package dev.inmo.micro_utils.repos.ktor.common | ||||||
|  |  | ||||||
|  | const val idParameterName = "id" | ||||||
| const val keyParameterName = "key" | const val keyParameterName = "key" | ||||||
| const val valueParameterName = "value" | const val valueParameterName = "value" | ||||||
| const val reversedParameterName = "reversed" | const val reversedParameterName = "reversed" | ||||||
| @@ -3,4 +3,3 @@ package dev.inmo.micro_utils.repos.ktor.common.crud | |||||||
| const val getByPaginationRouting = "getByPagination" | const val getByPaginationRouting = "getByPagination" | ||||||
| const val getByIdRouting = "getById" | const val getByIdRouting = "getById" | ||||||
| const val containsRouting = "contains" | const val containsRouting = "contains" | ||||||
| const val countRouting = "count" |  | ||||||
|   | |||||||
| @@ -3,8 +3,8 @@ package dev.inmo.micro_utils.repos.ktor.common.key_value | |||||||
| const val getRoute = "get" | const val getRoute = "get" | ||||||
| const val valuesRoute = "values" | const val valuesRoute = "values" | ||||||
| const val keysRoute = "keys" | const val keysRoute = "keys" | ||||||
| const val containsRoute = "contains" | const val containsRoute = dev.inmo.micro_utils.repos.ktor.common.containsRoute | ||||||
| const val countRoute = "count" | const val countRoute = dev.inmo.micro_utils.repos.ktor.common.countRoute | ||||||
|  |  | ||||||
| const val onNewValueRoute = "onNewValue" | const val onNewValueRoute = "onNewValue" | ||||||
| const val onValueRemovedRoute = "onValueRemoved" | const val onValueRemovedRoute = "onValueRemoved" | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ const val keysRoute = "keys" | |||||||
| const val containsByKeyRoute = "containsByKey" | const val containsByKeyRoute = "containsByKey" | ||||||
| const val containsByKeyValueRoute = "containsByKeyValue" | const val containsByKeyValueRoute = "containsByKeyValue" | ||||||
| const val countByKeyRoute = "countByKey" | const val countByKeyRoute = "countByKey" | ||||||
| const val countRoute = "count" | const val countRoute = dev.inmo.micro_utils.repos.ktor.common.countRoute | ||||||
|  |  | ||||||
| const val onNewValueRoute = "onNewValue" | const val onNewValueRoute = "onNewValue" | ||||||
| const val onValueRemovedRoute = "onValueRemoved" | const val onValueRemovedRoute = "onValueRemoved" | ||||||
|   | |||||||
							
								
								
									
										89
									
								
								repos/ktor/common/src/jvmTest/kotlin/CRUDTests.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								repos/ktor/common/src/jvmTest/kotlin/CRUDTests.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | |||||||
|  | import dev.inmo.micro_utils.repos.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.client.crud.KtorCRUDRepoClient | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.server.crud.configureCRUDRepoRoutes | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.client.plugins.logging.Logging | ||||||
|  | import io.ktor.http.ContentType | ||||||
|  | import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter | ||||||
|  | import io.ktor.serialization.kotlinx.json.json | ||||||
|  | import io.ktor.server.application.install | ||||||
|  | import io.ktor.server.cio.CIO | ||||||
|  | import io.ktor.server.plugins.contentnegotiation.ContentNegotiation | ||||||
|  | import io.ktor.server.routing.routing | ||||||
|  | import io.ktor.server.websocket.WebSockets | ||||||
|  | import kotlinx.coroutines.ExperimentalCoroutinesApi | ||||||
|  | import kotlinx.coroutines.test.runTest | ||||||
|  | import kotlinx.serialization.json.Json | ||||||
|  | import kotlin.test.Test | ||||||
|  | import kotlin.test.assertEquals | ||||||
|  |  | ||||||
|  | class CRUDTests { | ||||||
|  |     @OptIn(ExperimentalCoroutinesApi::class) | ||||||
|  |     @Test | ||||||
|  |     fun testCRUDFunctions() { | ||||||
|  |         runTest { | ||||||
|  |             val map = mutableMapOf<Int, ComplexData>() | ||||||
|  |             val repo = MapCRUDRepo<ComplexData, Int, SimpleData>( | ||||||
|  |                 map, | ||||||
|  |                 { newValue, id, oldValue -> | ||||||
|  |                     oldValue.copy(title = newValue.title) | ||||||
|  |                 } | ||||||
|  |             ) { | ||||||
|  |                 size to ComplexData(size, title = it.title) | ||||||
|  |             } | ||||||
|  |             val server = io.ktor.server.engine.embeddedServer( | ||||||
|  |                 CIO, | ||||||
|  |                 23456, | ||||||
|  |                 "127.0.0.1" | ||||||
|  |             ) { | ||||||
|  |                 install(ContentNegotiation) { | ||||||
|  |                     json() | ||||||
|  |                 } | ||||||
|  |                 install(WebSockets) { | ||||||
|  |                     contentConverter = KotlinxWebsocketSerializationConverter(Json) | ||||||
|  |                 } | ||||||
|  |                 routing { | ||||||
|  |                     configureCRUDRepoRoutes( | ||||||
|  |                         repo | ||||||
|  |                     ) { | ||||||
|  |                         it.toInt() | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }.start(false) | ||||||
|  |             val client = HttpClient { | ||||||
|  |                 install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { | ||||||
|  |                     json() | ||||||
|  |                 } | ||||||
|  |                 install(Logging) | ||||||
|  |                 install(io.ktor.client.plugins.websocket.WebSockets) { | ||||||
|  |                     contentConverter = KotlinxWebsocketSerializationConverter(Json) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             val crudClient = KtorCRUDRepoClient<ComplexData, Int, SimpleData>( | ||||||
|  |                 "http://127.0.0.1:23456", | ||||||
|  |                 client, | ||||||
|  |                 ContentType.Application.Json | ||||||
|  |             ) { | ||||||
|  |                 it.toString() | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             val created = crudClient.create(SimpleData("Example")).single() | ||||||
|  |             assertEquals(map.size, 1) | ||||||
|  |             assertEquals(map.size.toLong(), crudClient.count()) | ||||||
|  |             assertEquals(1, crudClient.count()) | ||||||
|  |             assertEquals(map.getValue(map.keys.first()), created) | ||||||
|  |  | ||||||
|  |             val updated = crudClient.update(created.id, SimpleData("Example2")) | ||||||
|  |             assertEquals(map.size, 1) | ||||||
|  |             assertEquals(map.size.toLong(), crudClient.count()) | ||||||
|  |             assertEquals(1, crudClient.count()) | ||||||
|  |             assertEquals(map.getValue(map.keys.first()), updated) | ||||||
|  |  | ||||||
|  |             crudClient.deleteById(created.id) | ||||||
|  |             assertEquals(map.size, 0) | ||||||
|  |             assertEquals(map.size.toLong(), crudClient.count()) | ||||||
|  |             assertEquals(0, crudClient.count()) | ||||||
|  |             server.stop() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								repos/ktor/common/src/jvmTest/kotlin/ComplexData.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								repos/ktor/common/src/jvmTest/kotlin/ComplexData.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | import com.benasher44.uuid.uuid4 | ||||||
|  | import kotlinx.serialization.Serializable | ||||||
|  |  | ||||||
|  | @Serializable | ||||||
|  | data class ComplexData( | ||||||
|  |     val id: Int, | ||||||
|  |     val simple: SimpleData = SimpleData(), | ||||||
|  |     val simples: List<SimpleData> = (0 until 100).map { SimpleData(("$it")) }, | ||||||
|  |     val title: String = uuid4().toString() | ||||||
|  | ) | ||||||
							
								
								
									
										139
									
								
								repos/ktor/common/src/jvmTest/kotlin/KVTests.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								repos/ktor/common/src/jvmTest/kotlin/KVTests.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | |||||||
|  | import dev.inmo.micro_utils.pagination.firstPageWithOneElementPagination | ||||||
|  | import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | ||||||
|  | import dev.inmo.micro_utils.repos.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.client.key.value.KtorKeyValueRepoClient | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.server.key.value.configureKeyValueRepoRoutes | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.client.plugins.logging.Logging | ||||||
|  | import io.ktor.http.ContentType | ||||||
|  | import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter | ||||||
|  | import io.ktor.serialization.kotlinx.json.json | ||||||
|  | import io.ktor.server.application.install | ||||||
|  | import io.ktor.server.cio.CIO | ||||||
|  | import io.ktor.server.plugins.contentnegotiation.ContentNegotiation | ||||||
|  | import io.ktor.server.routing.routing | ||||||
|  | import io.ktor.server.websocket.WebSockets | ||||||
|  | import kotlinx.coroutines.ExperimentalCoroutinesApi | ||||||
|  | import kotlinx.coroutines.test.runTest | ||||||
|  | import kotlinx.serialization.builtins.serializer | ||||||
|  | import kotlinx.serialization.json.Json | ||||||
|  | import kotlin.test.* | ||||||
|  |  | ||||||
|  | class KVTests { | ||||||
|  |     @OptIn(ExperimentalCoroutinesApi::class) | ||||||
|  |     @Test | ||||||
|  |     fun testKVFunctions() { | ||||||
|  |         runTest { | ||||||
|  |             val map = mutableMapOf<Int, ComplexData>() | ||||||
|  |             val repo = MapKeyValueRepo<Int, ComplexData>(map) | ||||||
|  |             val server = io.ktor.server.engine.embeddedServer( | ||||||
|  |                 CIO, | ||||||
|  |                 23456, | ||||||
|  |                 "127.0.0.1" | ||||||
|  |             ) { | ||||||
|  |                 install(ContentNegotiation) { | ||||||
|  |                     json() | ||||||
|  |                 } | ||||||
|  |                 install(WebSockets) { | ||||||
|  |                     contentConverter = KotlinxWebsocketSerializationConverter(Json) | ||||||
|  |                 } | ||||||
|  |                 routing { | ||||||
|  |                     configureKeyValueRepoRoutes( | ||||||
|  |                         repo, | ||||||
|  |                         Int.serializer(), | ||||||
|  |                         ComplexData.serializer(), | ||||||
|  |                         Json {} | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |             }.start(false) | ||||||
|  |             val client = HttpClient { | ||||||
|  |                 install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { | ||||||
|  |                     json() | ||||||
|  |                 } | ||||||
|  |                 install(Logging) | ||||||
|  |                 install(io.ktor.client.plugins.websocket.WebSockets) { | ||||||
|  |                     contentConverter = KotlinxWebsocketSerializationConverter(Json) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             val crudClient = KtorKeyValueRepoClient<Int, ComplexData>( | ||||||
|  |                 "http://127.0.0.1:23456", | ||||||
|  |                 client, | ||||||
|  |                 ContentType.Application.Json, | ||||||
|  |                 Int.serializer(), | ||||||
|  |                 ComplexData.serializer(), | ||||||
|  |                 Json | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             val dataInOneKey = ComplexData(1, title = "Example1") | ||||||
|  |             val dataInMultipleKeys = ComplexData(2, title = "Example2") | ||||||
|  |             val repeatCount = 3 | ||||||
|  |  | ||||||
|  |             val dataList = listOf( | ||||||
|  |                 1 to dataInOneKey | ||||||
|  |             ) + (0 until repeatCount).map { | ||||||
|  |                 (it + 2) to dataInMultipleKeys | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             dataList.forEachIndexed { i, (id, data) -> | ||||||
|  |                 crudClient.set(id, data) | ||||||
|  |                 assertEquals(map.size, i + 1) | ||||||
|  |                 assertEquals(map.size.toLong(), crudClient.count()) | ||||||
|  |                 assertEquals(i + 1L, crudClient.count()) | ||||||
|  |                 dataList.take(i + 1).forEach { (id, data) -> | ||||||
|  |                     assertEquals(data, map[id]) | ||||||
|  |                     assertEquals(data, crudClient.get(id)) | ||||||
|  |                     assertEquals(map[id], crudClient.get(id)) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             dataList.forEach { (id, data) -> | ||||||
|  |                 assertTrue(crudClient.contains(id)) | ||||||
|  |                 assertEquals(data, crudClient.get(id)) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             assertEquals( | ||||||
|  |                 dataList.mapNotNull { if (it.second == dataInMultipleKeys) it.first else null }, | ||||||
|  |                 getAllWithNextPaging(firstPageWithOneElementPagination) { | ||||||
|  |                     crudClient.keys(dataInMultipleKeys, it) | ||||||
|  |                 } | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             assertEquals( | ||||||
|  |                 dataList.mapNotNull { if (it.second == dataInOneKey) it.first else null }, | ||||||
|  |                 getAllWithNextPaging(firstPageWithOneElementPagination) { | ||||||
|  |                     crudClient.keys(dataInOneKey, it) | ||||||
|  |                 } | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             assertEquals( | ||||||
|  |                 dataList.map { it.first }, | ||||||
|  |                 getAllWithNextPaging(firstPageWithOneElementPagination) { | ||||||
|  |                     crudClient.keys(it) | ||||||
|  |                 } | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             assertEquals( | ||||||
|  |                 dataList.map { it.second }, | ||||||
|  |                 getAllWithNextPaging(firstPageWithOneElementPagination) { | ||||||
|  |                     crudClient.values(it) | ||||||
|  |                 } | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             assertEquals(dataList.size.toLong(), crudClient.count()) | ||||||
|  |  | ||||||
|  |             crudClient.unsetWithValues(dataInMultipleKeys) | ||||||
|  |             assertEquals( | ||||||
|  |                 dataList.filter { it.second == dataInOneKey }.size.toLong(), | ||||||
|  |                 crudClient.count() | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             crudClient.unset(dataList.first { it.second == dataInOneKey }.first) | ||||||
|  |             assertEquals( | ||||||
|  |                 0, | ||||||
|  |                 crudClient.count() | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             server.stop() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										140
									
								
								repos/ktor/common/src/jvmTest/kotlin/KVsTests.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								repos/ktor/common/src/jvmTest/kotlin/KVsTests.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | |||||||
|  | import dev.inmo.micro_utils.pagination.firstPageWithOneElementPagination | ||||||
|  | import dev.inmo.micro_utils.pagination.utils.getAllWithNextPaging | ||||||
|  | import dev.inmo.micro_utils.repos.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.client.key.values.KtorKeyValuesRepoClient | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.server.key.values.configureKeyValuesRepoRoutes | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import io.ktor.client.plugins.logging.Logging | ||||||
|  | import io.ktor.http.ContentType | ||||||
|  | import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter | ||||||
|  | import io.ktor.serialization.kotlinx.json.json | ||||||
|  | import io.ktor.server.application.install | ||||||
|  | import io.ktor.server.cio.CIO | ||||||
|  | import io.ktor.server.plugins.contentnegotiation.ContentNegotiation | ||||||
|  | import io.ktor.server.routing.routing | ||||||
|  | import io.ktor.server.websocket.WebSockets | ||||||
|  | import kotlinx.coroutines.ExperimentalCoroutinesApi | ||||||
|  | import kotlinx.coroutines.test.runTest | ||||||
|  | import kotlinx.serialization.builtins.serializer | ||||||
|  | import kotlinx.serialization.json.Json | ||||||
|  | import kotlin.test.* | ||||||
|  |  | ||||||
|  | class KVsTests { | ||||||
|  |     @OptIn(ExperimentalCoroutinesApi::class) | ||||||
|  |     @Test | ||||||
|  |     fun testKVsFunctions() { | ||||||
|  |         runTest { | ||||||
|  |             val map = mutableMapOf<Int, MutableList<ComplexData>>() | ||||||
|  |             val repo = MapKeyValuesRepo(map) | ||||||
|  |             val server = io.ktor.server.engine.embeddedServer( | ||||||
|  |                 CIO, | ||||||
|  |                 23456, | ||||||
|  |                 "127.0.0.1" | ||||||
|  |             ) { | ||||||
|  |                 install(ContentNegotiation) { | ||||||
|  |                     json() | ||||||
|  |                 } | ||||||
|  |                 install(WebSockets) { | ||||||
|  |                     contentConverter = KotlinxWebsocketSerializationConverter(Json) | ||||||
|  |                 } | ||||||
|  |                 routing { | ||||||
|  |                     configureKeyValuesRepoRoutes( | ||||||
|  |                         repo, | ||||||
|  |                         Int.serializer(), | ||||||
|  |                         ComplexData.serializer(), | ||||||
|  |                         Json {} | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |             }.start(false) | ||||||
|  |             val client = HttpClient { | ||||||
|  |                 install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { | ||||||
|  |                     json() | ||||||
|  |                 } | ||||||
|  |                 install(Logging) | ||||||
|  |                 install(io.ktor.client.plugins.websocket.WebSockets) { | ||||||
|  |                     contentConverter = KotlinxWebsocketSerializationConverter(Json) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             val crudClient = KtorKeyValuesRepoClient( | ||||||
|  |                 "http://127.0.0.1:23456", | ||||||
|  |                 client, | ||||||
|  |                 ContentType.Application.Json, | ||||||
|  |                 Int.serializer(), | ||||||
|  |                 ComplexData.serializer(), | ||||||
|  |                 Json | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             val dataInOneKey = ComplexData(1, title = "Example1") | ||||||
|  |             val dataInMultipleKeys = ComplexData(2, title = "Example2") | ||||||
|  |             val repeatCount = 3 | ||||||
|  |  | ||||||
|  |             val dataList = listOf( | ||||||
|  |                 1 to listOf(dataInOneKey) | ||||||
|  |             ) + (0 until repeatCount).map { | ||||||
|  |                 (it + 2) to listOf(dataInMultipleKeys) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             dataList.forEachIndexed { i, (id, data) -> | ||||||
|  |                 crudClient.set(id, data) | ||||||
|  |                 assertEquals(i + 1, map.size) | ||||||
|  |                 assertEquals(map.size.toLong(), crudClient.count()) | ||||||
|  |                 assertEquals(i + 1L, crudClient.count()) | ||||||
|  |                 dataList.take(i + 1).forEach { (id, data) -> | ||||||
|  |                     assertContentEquals(data, map[id]) | ||||||
|  |                     assertContentEquals(data, crudClient.getAll(id)) | ||||||
|  |                     assertContentEquals(map[id], crudClient.getAll(id)) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             dataList.forEach { (key, data) -> | ||||||
|  |                 assertTrue(crudClient.contains(key)) | ||||||
|  |                 assertContentEquals(data, crudClient.getAll(key)) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             assertEquals( | ||||||
|  |                 dataList.mapNotNull { if (it.second.contains(dataInMultipleKeys)) it.first else null }, | ||||||
|  |                 getAllWithNextPaging(firstPageWithOneElementPagination) { | ||||||
|  |                     crudClient.keys(dataInMultipleKeys, it) | ||||||
|  |                 } | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             assertEquals( | ||||||
|  |                 dataList.mapNotNull { if (it.second.contains(dataInOneKey)) it.first else null }, | ||||||
|  |                 getAllWithNextPaging(firstPageWithOneElementPagination) { | ||||||
|  |                     crudClient.keys(dataInOneKey, it) | ||||||
|  |                 } | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             assertEquals( | ||||||
|  |                 dataList.map { it.first }, | ||||||
|  |                 getAllWithNextPaging(firstPageWithOneElementPagination) { | ||||||
|  |                     crudClient.keys(it) | ||||||
|  |                 } | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             assertEquals( | ||||||
|  |                 dataList.map { it.first }, | ||||||
|  |                 getAllWithNextPaging(firstPageWithOneElementPagination) { | ||||||
|  |                     crudClient.keys(it) | ||||||
|  |                 } | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             assertEquals(dataList.size.toLong(), crudClient.count()) | ||||||
|  |  | ||||||
|  |             crudClient.remove(dataList.filter { it.second.contains(dataInMultipleKeys) }) | ||||||
|  |             println(map) | ||||||
|  |             assertEquals( | ||||||
|  |                 dataList.filter { it.second.contains(dataInOneKey) }.size.toLong(), | ||||||
|  |                 crudClient.count() | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             crudClient.remove(dataList.filter { it.second.contains(dataInOneKey) }) | ||||||
|  |             assertEquals( | ||||||
|  |                 0, | ||||||
|  |                 crudClient.count() | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             server.stop() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								repos/ktor/common/src/jvmTest/kotlin/SimpleData.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								repos/ktor/common/src/jvmTest/kotlin/SimpleData.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | import com.benasher44.uuid.uuid4 | ||||||
|  | import kotlinx.serialization.Serializable | ||||||
|  |  | ||||||
|  | @Serializable | ||||||
|  | data class SimpleData( | ||||||
|  |     val title: String = uuid4().toString() | ||||||
|  | ) | ||||||
							
								
								
									
										198
									
								
								repos/ktor/crud.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								repos/ktor/crud.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,198 @@ | |||||||
|  | openapi: "3.0.0" | ||||||
|  | info: | ||||||
|  |   description: "This is a template for the CRUD repositories from [microutils](https://github.com/InsanusMokrassar/MicroUtils/tree/master/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud)" | ||||||
|  |   version: "0.11.3" | ||||||
|  |   title: "CRUD Repo" | ||||||
|  |   contact: | ||||||
|  |     email: "ovsyannikov.alexey95@gmail.com" | ||||||
|  | tags: | ||||||
|  |   - name: "Read" | ||||||
|  |     description: "Operations with `get` request in most cases" | ||||||
|  |   - name: "Write" | ||||||
|  |     description: "Operations with `post` request in most cases" | ||||||
|  |  | ||||||
|  | components: | ||||||
|  |   parameters: | ||||||
|  |     IdInQuery: | ||||||
|  |       in: "query" | ||||||
|  |       name: "id" | ||||||
|  |       schema: | ||||||
|  |         $ref: "#/components/schemas/Key" | ||||||
|  |     PaginationInQueryPage: | ||||||
|  |       in: "query" | ||||||
|  |       name: "ppage" | ||||||
|  |       description: "Page of pagination" | ||||||
|  |       schema: | ||||||
|  |         type: integer | ||||||
|  |       required: false | ||||||
|  |     PaginationInQuerySize: | ||||||
|  |       in: "query" | ||||||
|  |       name: "psize" | ||||||
|  |       description: "Size of each page in pagination" | ||||||
|  |       schema: | ||||||
|  |         type: integer | ||||||
|  |       required: false | ||||||
|  |   schemas: | ||||||
|  |  | ||||||
|  |     Key: | ||||||
|  |       type: integer | ||||||
|  |       description: "REWRITE THIS TYPE AS KEY IN SWAGGER FILE" | ||||||
|  |     Value: | ||||||
|  |       type: integer | ||||||
|  |       description: "REWRITE THIS TYPE AS VALUE IN SWAGGER FILE" | ||||||
|  |     NewValue: | ||||||
|  |       type: integer | ||||||
|  |       description: "REWRITE THIS TYPE AS NEW VALUE IN SWAGGER FILE" | ||||||
|  |     Pair: | ||||||
|  |       type: object | ||||||
|  |       description: "Pair of objects" | ||||||
|  |       properties: | ||||||
|  |         first: | ||||||
|  |         second: | ||||||
|  |     PaginationResult: | ||||||
|  |       type: object | ||||||
|  |       properties: | ||||||
|  |         page: | ||||||
|  |           type: integer | ||||||
|  |           description: "Page of pagination" | ||||||
|  |         pagesNumber: | ||||||
|  |           type: integer | ||||||
|  |           description: "Count of pages with the size from this pagination" | ||||||
|  |         size: | ||||||
|  |           type: integer | ||||||
|  |           description: "Size of each page in pagination" | ||||||
|  |         results: | ||||||
|  |           type: array | ||||||
|  |           description: "Array of all elements on that page. Size of pagination and size of array can be different and it can be interpreted like current page is the last one" | ||||||
|  |           items: | ||||||
|  |             type: object | ||||||
|  |  | ||||||
|  | paths: | ||||||
|  |   /getByPagination: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/components/parameters/PaginationInQueryPage" | ||||||
|  |         - $ref: "#/components/parameters/PaginationInQuerySize" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Pagination with elements" | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 allOf: | ||||||
|  |                   - $ref: "#/components/schemas/PaginationResult" | ||||||
|  |                   - properties: | ||||||
|  |                       results: | ||||||
|  |                         items: | ||||||
|  |                           $ref: "#/components/schemas/Value" | ||||||
|  |   /getById: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/components/parameters/IdInQuery" | ||||||
|  |           required: true | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Result object" | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 $ref: "#/components/schemas/Value" | ||||||
|  |         "204": | ||||||
|  |           description: "No value by id" | ||||||
|  |   /contains: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/components/parameters/IdInQuery" | ||||||
|  |           required: true | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Object with id availability in repo" | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 type: boolean | ||||||
|  |   /count: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Amount of objects in repo" | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 type: integer | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   /create: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       requestBody: | ||||||
|  |         content: | ||||||
|  |           application/json: | ||||||
|  |             schema: | ||||||
|  |               type: array | ||||||
|  |               items: | ||||||
|  |                 $ref: "#/components/schemas/NewValue" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Objects has been created and saved" | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 type: array | ||||||
|  |                 items: | ||||||
|  |                   $ref: "#/components/schemas/Value" | ||||||
|  |   /update: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       requestBody: | ||||||
|  |         content: | ||||||
|  |           application/json: | ||||||
|  |             schema: | ||||||
|  |               type: array | ||||||
|  |               items: | ||||||
|  |                 allOf: | ||||||
|  |                   - $ref: "#/components/schemas/Pair" | ||||||
|  |                   - properties: | ||||||
|  |                       first: | ||||||
|  |                         $ref: "#/components/schemas/Key" | ||||||
|  |                       second: | ||||||
|  |                         $ref: "#/components/schemas/NewValue" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Objects has been updated" | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 type: array | ||||||
|  |                 items: | ||||||
|  |                   $ref: "#/components/schemas/Value" | ||||||
|  |   /deleteById: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       requestBody: | ||||||
|  |         content: | ||||||
|  |           application/json: | ||||||
|  |             schema: | ||||||
|  |               type: array | ||||||
|  |               items: | ||||||
|  |                 $ref: "#/components/schemas/Key" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Objects has been updated" | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 type: array | ||||||
|  |                 items: | ||||||
|  |                   $ref: "#/components/schemas/Value" | ||||||
							
								
								
									
										201
									
								
								repos/ktor/kv.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								repos/ktor/kv.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | |||||||
|  | openapi: "3.0.0" | ||||||
|  | info: | ||||||
|  |   description: "This is a template for the KeyValue repositories from [microutils](https://github.com/InsanusMokrassar/MicroUtils/tree/master/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key/value)" | ||||||
|  |   version: "0.11.1" | ||||||
|  |   title: "KeyValue Repo" | ||||||
|  |   contact: | ||||||
|  |     email: "ovsyannikov.alexey95@gmail.com" | ||||||
|  | tags: | ||||||
|  |   - name: "Read" | ||||||
|  |     description: "Operations with `get` request in most cases" | ||||||
|  |   - name: "Write" | ||||||
|  |     description: "Operations with `post` request in most cases" | ||||||
|  |  | ||||||
|  | components: | ||||||
|  |   parameters: | ||||||
|  |     KeyInQuery: | ||||||
|  |       in: "query" | ||||||
|  |       name: "key" | ||||||
|  |       schema: | ||||||
|  |         $ref: "#/components/schemas/Key" | ||||||
|  |     PaginationInQueryPage: | ||||||
|  |       in: "query" | ||||||
|  |       name: "ppage" | ||||||
|  |       description: "Page of pagination" | ||||||
|  |       schema: | ||||||
|  |         type: integer | ||||||
|  |       required: false | ||||||
|  |     PaginationInQuerySize: | ||||||
|  |       in: "query" | ||||||
|  |       name: "psize" | ||||||
|  |       description: "Size of each page in pagination" | ||||||
|  |       schema: | ||||||
|  |         type: integer | ||||||
|  |       required: false | ||||||
|  |     ReversedInQuery: | ||||||
|  |       in: "query" | ||||||
|  |       name: "reversed" | ||||||
|  |       description: "If passed, will tell to reverse the result pages" | ||||||
|  |       schema: | ||||||
|  |         type: boolean | ||||||
|  |       required: false | ||||||
|  |     ValueInQuery: | ||||||
|  |       in: "query" | ||||||
|  |       name: "value" | ||||||
|  |       schema: | ||||||
|  |         $ref: "#/components/schemas/Value" | ||||||
|  |   schemas: | ||||||
|  |     Key: | ||||||
|  |       type: integer | ||||||
|  |       description: "REWRITE THIS TYPE AS KEY IN SWAGGER FILE" | ||||||
|  |     Value: | ||||||
|  |       type: integer | ||||||
|  |       description: "REWRITE THIS TYPE AS VALUE IN SWAGGER FILE" | ||||||
|  |     PaginationResult: | ||||||
|  |       type: object | ||||||
|  |       properties: | ||||||
|  |         page: | ||||||
|  |           type: integer | ||||||
|  |           description: "Page of pagination" | ||||||
|  |         pagesNumber: | ||||||
|  |           type: integer | ||||||
|  |           description: "Count of pages with the size from this pagination" | ||||||
|  |         size: | ||||||
|  |           type: integer | ||||||
|  |           description: "Size of each page in pagination" | ||||||
|  |         results: | ||||||
|  |           type: array | ||||||
|  |           description: "Array of all elements on that page. Size of pagination and size of array can be different and it can be interpreted like current page is the last one" | ||||||
|  |           items: | ||||||
|  |             type: object | ||||||
|  |  | ||||||
|  | paths: | ||||||
|  |   /get: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       parameters: | ||||||
|  |         - allOf: | ||||||
|  |             - $ref: "#/components/parameters/KeyInQuery" | ||||||
|  |             - required: true | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Element by key" | ||||||
|  |           content: | ||||||
|  |             "*/*": | ||||||
|  |               schema: | ||||||
|  |                 $ref: "#/components/schemas/Value" | ||||||
|  |         "204": | ||||||
|  |           description: "No value by id" | ||||||
|  |   /values: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/components/parameters/PaginationInQueryPage" | ||||||
|  |         - $ref: "#/components/parameters/PaginationInQuerySize" | ||||||
|  |         - $ref: "#/components/parameters/ReversedInQuery" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Pagination with elements" | ||||||
|  |           content: | ||||||
|  |             "*/*": | ||||||
|  |               schema: | ||||||
|  |                 allOf: | ||||||
|  |                   - $ref: "#/components/schemas/PaginationResult" | ||||||
|  |                   - properties: | ||||||
|  |                       results: | ||||||
|  |                         items: | ||||||
|  |                           $ref: "#/components/schemas/Value" | ||||||
|  |   /keys: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/components/parameters/PaginationInQueryPage" | ||||||
|  |         - $ref: "#/components/parameters/PaginationInQuerySize" | ||||||
|  |         - $ref: "#/components/parameters/ReversedInQuery" | ||||||
|  |         - $ref: "#/components/parameters/ValueInQuery" | ||||||
|  |           required: false | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Pagination with elements" | ||||||
|  |           content: | ||||||
|  |             "*/*": | ||||||
|  |               schema: | ||||||
|  |                 allOf: | ||||||
|  |                   - $ref: "#/components/schemas/PaginationResult" | ||||||
|  |                   - properties: | ||||||
|  |                       results: | ||||||
|  |                         items: | ||||||
|  |                           $ref: "#/components/schemas/Key" | ||||||
|  |   /contains: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/components/parameters/KeyInQuery" | ||||||
|  |           required: true | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Object with id availability in repo" | ||||||
|  |           content: | ||||||
|  |             "*/*": | ||||||
|  |               schema: | ||||||
|  |                 type: boolean | ||||||
|  |   /count: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Amount of objects in repo" | ||||||
|  |           content: | ||||||
|  |             "*/*": | ||||||
|  |               schema: | ||||||
|  |                 type: integer | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   /set: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       requestBody: | ||||||
|  |         content: | ||||||
|  |           "*/*": | ||||||
|  |             schema: | ||||||
|  |               type: object | ||||||
|  |               additionalProperties: | ||||||
|  |                 $ref: "#/components/schemas/Value" | ||||||
|  |               description: "Map with new elements to set. Use keys as a keys of this map" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Will return 200 if everything has been completed ok" | ||||||
|  |   /unset: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       requestBody: | ||||||
|  |         content: | ||||||
|  |           "*/*": | ||||||
|  |             schema: | ||||||
|  |               type: array | ||||||
|  |               items: | ||||||
|  |                 $ref: "#/components/schemas/Key" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Objects with keys from body has been unset" | ||||||
|  |   /unsetWithValues: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       requestBody: | ||||||
|  |         content: | ||||||
|  |           "*/*": | ||||||
|  |             schema: | ||||||
|  |               type: array | ||||||
|  |               items: | ||||||
|  |                 $ref: "#/components/schemas/Value" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Objects with values from body has been unset" | ||||||
							
								
								
									
										222
									
								
								repos/ktor/kvs.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								repos/ktor/kvs.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,222 @@ | |||||||
|  | swagger: "2.0" | ||||||
|  | info: | ||||||
|  |   description: "This is a template for the KeyValues repositories from [microutils](https://github.com/InsanusMokrassar/MicroUtils/tree/master/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key/values)" | ||||||
|  |   version: "0.11.0" | ||||||
|  |   title: "KeyValues Repo" | ||||||
|  |   contact: | ||||||
|  |     email: "ovsyannikov.alexey95@gmail.com" | ||||||
|  | tags: | ||||||
|  |   - name: "Read" | ||||||
|  |     description: "Operations with `get` request in most cases" | ||||||
|  |   - name: "Write" | ||||||
|  |     description: "Operations with `post` request in most cases" | ||||||
|  |  | ||||||
|  | parameters: | ||||||
|  |   KeyInQuery: | ||||||
|  |     in: "query" | ||||||
|  |     name: "key" | ||||||
|  |     allOf: | ||||||
|  |       - $ref: "#/definitions/Key" | ||||||
|  |   KeyInBody: | ||||||
|  |     in: "body" | ||||||
|  |     name: "body" | ||||||
|  |     allOf: | ||||||
|  |       - $ref: "#/definitions/Key" | ||||||
|  |   KeysInBody: | ||||||
|  |     in: "body" | ||||||
|  |     name: "body" | ||||||
|  |     type: array | ||||||
|  |     items: | ||||||
|  |       $ref: "#/definitions/Key" | ||||||
|  |   ValuesInBody: | ||||||
|  |     in: "body" | ||||||
|  |     name: "body" | ||||||
|  |     type: array | ||||||
|  |     items: | ||||||
|  |       $ref: "#/definitions/Value" | ||||||
|  |   PaginationInQueryPage: | ||||||
|  |     in: "query" | ||||||
|  |     type: integer | ||||||
|  |     name: "ppage" | ||||||
|  |     description: "Page of pagination" | ||||||
|  |     required: false | ||||||
|  |   PaginationInQuerySize: | ||||||
|  |     in: "query" | ||||||
|  |     type: integer | ||||||
|  |     name: "psize" | ||||||
|  |     description: "Size of each page in pagination" | ||||||
|  |     required: false | ||||||
|  |   ReversedInQuery: | ||||||
|  |     in: "query" | ||||||
|  |     type: boolean | ||||||
|  |     name: "reversed" | ||||||
|  |     description: "If passed, will tell to reverse the result pages" | ||||||
|  |     required: false | ||||||
|  |   ValueInQuery: | ||||||
|  |     in: "query" | ||||||
|  |     name: "value" | ||||||
|  |     allOf: | ||||||
|  |       - $ref: "#/definitions/Value" | ||||||
|  |   ValueInBody: | ||||||
|  |     in: "body" | ||||||
|  |     name: "body" | ||||||
|  |     allOf: | ||||||
|  |       - $ref: "#/definitions/Value" | ||||||
|  |   MapInBody: | ||||||
|  |     in: "body" | ||||||
|  |     name: "body" | ||||||
|  |     allOf: | ||||||
|  |       - $ref: "#/definitions/Map" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | definitions: | ||||||
|  |   Key: | ||||||
|  |     type: integer | ||||||
|  |     description: "REWRITE THIS TYPE AS KEY IN SWAGGER FILE" | ||||||
|  |   Value: | ||||||
|  |     type: integer | ||||||
|  |     description: "REWRITE THIS TYPE AS VALUE IN SWAGGER FILE" | ||||||
|  |   Map: | ||||||
|  |     type: object | ||||||
|  |     description: "Map of objects" | ||||||
|  |   PaginationResult: | ||||||
|  |     type: object | ||||||
|  |     properties: | ||||||
|  |       page: | ||||||
|  |         type: integer | ||||||
|  |         description: "Page of pagination" | ||||||
|  |       pagesNumber: | ||||||
|  |         type: integer | ||||||
|  |         description: "Count of pages with the size from this pagination" | ||||||
|  |       size: | ||||||
|  |         type: integer | ||||||
|  |         description: "Size of each page in pagination" | ||||||
|  |       results: | ||||||
|  |         type: array | ||||||
|  |         description: "Array of all elements on that page. Size of pagination and size of array can be different and it can be interpreted like current page is the last one" | ||||||
|  |         items: | ||||||
|  |           type: object | ||||||
|  |  | ||||||
|  | paths: | ||||||
|  |   /get: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/parameters/KeyInQuery" | ||||||
|  |           required: true | ||||||
|  |         - $ref: "#/parameters/PaginationInQueryPage" | ||||||
|  |         - $ref: "#/parameters/PaginationInQuerySize" | ||||||
|  |         - $ref: "#/parameters/ReversedInQuery" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Elements by query" | ||||||
|  |           schema: | ||||||
|  |             allOf: | ||||||
|  |               - $ref: "#/definitions/PaginationResult" | ||||||
|  |               - properties: | ||||||
|  |                   results: | ||||||
|  |                     items: | ||||||
|  |                       $ref: "#/definitions/Value" | ||||||
|  |   /keys: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/parameters/PaginationInQueryPage" | ||||||
|  |         - $ref: "#/parameters/PaginationInQuerySize" | ||||||
|  |         - $ref: "#/parameters/ReversedInQuery" | ||||||
|  |         - $ref: "#/parameters/ValueInQuery" | ||||||
|  |           required: false | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Pagination with elements" | ||||||
|  |           schema: | ||||||
|  |             allOf: | ||||||
|  |               - $ref: "#/definitions/PaginationResult" | ||||||
|  |               - properties: | ||||||
|  |                   results: | ||||||
|  |                     items: | ||||||
|  |                       $ref: "#/definitions/Key" | ||||||
|  |   /contains: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/parameters/KeyInQuery" | ||||||
|  |           required: true | ||||||
|  |         - $ref: "#/parameters/ValueInQuery" | ||||||
|  |           required: false | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Object with key and optionally availability in repo" | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |   /count: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - "Read" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Amount of objects in repo" | ||||||
|  |           schema: | ||||||
|  |             type: integer | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   /add: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       parameters: | ||||||
|  |         - allOf: | ||||||
|  |             - $ref: "#/parameters/MapInBody" | ||||||
|  |             - additionalProperties: | ||||||
|  |                 $ref: "#/definitions/Value" | ||||||
|  |               description: "Map with new elements to add. Use keys as a keys of this map. That values will be added to the end of current data by their keys" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Will return 200 if everything has been completed ok" | ||||||
|  |   /set: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       parameters: | ||||||
|  |         - allOf: | ||||||
|  |             - $ref: "#/parameters/MapInBody" | ||||||
|  |             - additionalProperties: | ||||||
|  |                 $ref: "#/definitions/Value" | ||||||
|  |               description: "Map with new elements to set. Use keys as a keys of this map. That values will overwrite all exists data by their keys" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Will return 200 if everything has been completed ok" | ||||||
|  |   /remove: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       parameters: | ||||||
|  |         - allOf: | ||||||
|  |             - $ref: "#/parameters/MapInBody" | ||||||
|  |             - additionalProperties: | ||||||
|  |                 $ref: "#/definitions/Value" | ||||||
|  |               description: "Map with data to remove. Removing will be processed by each value for its key" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Objects with keys and values from body has been unset" | ||||||
|  |   /clear: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/parameters/KeyInBody" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Data with corresponding key has been removed" | ||||||
|  |   /clearWithValues: | ||||||
|  |     post: | ||||||
|  |       tags: | ||||||
|  |         - "Write" | ||||||
|  |       parameters: | ||||||
|  |         - $ref: "#/parameters/ValueInBody" | ||||||
|  |       responses: | ||||||
|  |         "200": | ||||||
|  |           description: "Will remove value from all keys data" | ||||||
| @@ -0,0 +1,30 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.server.crud | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.CRUDRepo | ||||||
|  | import io.ktor.server.routing.Route | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureCRUDRepoRoutes( | ||||||
|  |     originalRepo: CRUDRepo<ObjectType, IdType, InputValue>, | ||||||
|  |     noinline idDeserializer: suspend (String) -> IdType | ||||||
|  | ) { | ||||||
|  |     configureReadCRUDRepoRoutes(originalRepo, idDeserializer) | ||||||
|  |     configureWriteCRUDRepoRoutes(originalRepo) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureCRUDRepoRoutes( | ||||||
|  |     originalRepo: CRUDRepo<ObjectType, IdType, InputValue>, | ||||||
|  |     idsSerializer: KSerializer<IdType>, | ||||||
|  |     serialFormat: StringFormat | ||||||
|  | ) = configureCRUDRepoRoutes(originalRepo) { | ||||||
|  |     serialFormat.decodeFromString(idsSerializer, it) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureCRUDRepoRoutes( | ||||||
|  |     originalRepo: CRUDRepo<ObjectType, IdType, InputValue>, | ||||||
|  |     idsSerializer: KSerializer<IdType>, | ||||||
|  |     serialFormat: BinaryFormat | ||||||
|  | ) = configureCRUDRepoRoutes(originalRepo) { | ||||||
|  |     serialFormat.decodeHex(idsSerializer, it) | ||||||
|  | } | ||||||
| @@ -0,0 +1,72 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.server.crud | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.decodeHex | ||||||
|  | import dev.inmo.micro_utils.ktor.server.* | ||||||
|  | import dev.inmo.micro_utils.pagination.extractPagination | ||||||
|  | import dev.inmo.micro_utils.repos.ReadCRUDRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.countRouting | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.crud.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.idParameterName | ||||||
|  | import io.ktor.http.HttpStatusCode | ||||||
|  | import io.ktor.server.application.call | ||||||
|  | import io.ktor.server.response.respond | ||||||
|  | import io.ktor.server.routing.Route | ||||||
|  | import io.ktor.server.routing.get | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, reified IdType> Route.configureReadCRUDRepoRoutes( | ||||||
|  |     originalRepo: ReadCRUDRepo<ObjectType, IdType>, | ||||||
|  |     noinline idDeserializer: suspend (String) -> IdType | ||||||
|  | ) { | ||||||
|  |     get(getByPaginationRouting) { | ||||||
|  |         val pagination = call.request.queryParameters.extractPagination | ||||||
|  |  | ||||||
|  |         call.respond(originalRepo.getByPagination(pagination)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get(getByIdRouting) { | ||||||
|  |         val id = idDeserializer( | ||||||
|  |             call.getQueryParameterOrSendError(idParameterName) ?: return@get | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         val result = originalRepo.getById(id) | ||||||
|  |  | ||||||
|  |         if (result == null) { | ||||||
|  |             call.respond(HttpStatusCode.NoContent) | ||||||
|  |         } else { | ||||||
|  |             call.respond(result) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get(containsRouting) { | ||||||
|  |         val id = idDeserializer( | ||||||
|  |             call.getQueryParameterOrSendError(idParameterName) ?: return@get | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         call.respond( | ||||||
|  |             originalRepo.contains(id) | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get(countRouting) { | ||||||
|  |         call.respond( | ||||||
|  |             originalRepo.count() | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, reified IdType> Route.configureReadCRUDRepoRoutes( | ||||||
|  |     originalRepo: ReadCRUDRepo<ObjectType, IdType>, | ||||||
|  |     idsSerializer: KSerializer<IdType>, | ||||||
|  |     serialFormat: StringFormat | ||||||
|  | ) = configureReadCRUDRepoRoutes(originalRepo) { | ||||||
|  |     serialFormat.decodeFromString(idsSerializer, it) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType, reified IdType> Route.configureReadCRUDRepoRoutes( | ||||||
|  |     originalRepo: ReadCRUDRepo<ObjectType, IdType>, | ||||||
|  |     idsSerializer: KSerializer<IdType>, | ||||||
|  |     serialFormat: BinaryFormat | ||||||
|  | ) = configureReadCRUDRepoRoutes(originalRepo) { | ||||||
|  |     serialFormat.decodeHex(idsSerializer, it) | ||||||
|  | } | ||||||
| @@ -5,7 +5,8 @@ import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | |||||||
| import dev.inmo.micro_utils.ktor.server.* | import dev.inmo.micro_utils.ktor.server.* | ||||||
| import dev.inmo.micro_utils.pagination.PaginationResult | import dev.inmo.micro_utils.pagination.PaginationResult | ||||||
| import dev.inmo.micro_utils.pagination.extractPagination | import dev.inmo.micro_utils.pagination.extractPagination | ||||||
| import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo | import dev.inmo.micro_utils.repos.ReadCRUDRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.countRouting | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.crud.* | import dev.inmo.micro_utils.repos.ktor.common.crud.* | ||||||
| import io.ktor.http.ContentType | import io.ktor.http.ContentType | ||||||
| import io.ktor.server.application.call | import io.ktor.server.application.call | ||||||
| @@ -14,8 +15,8 @@ import io.ktor.server.routing.get | |||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
| import kotlinx.serialization.builtins.serializer | import kotlinx.serialization.builtins.serializer | ||||||
|  |  | ||||||
| fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes( | fun <ObjectType, IdType> Route.configureReadCRUDRepoRoutes( | ||||||
|     originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>, |     originalRepo: ReadCRUDRepo<ObjectType, IdType>, | ||||||
|     objectsSerializer: KSerializer<ObjectType>, |     objectsSerializer: KSerializer<ObjectType>, | ||||||
|     objectsNullableSerializer: KSerializer<ObjectType?>, |     objectsNullableSerializer: KSerializer<ObjectType?>, | ||||||
|     idsSerializer: KSerializer<IdType>, |     idsSerializer: KSerializer<IdType>, | ||||||
| @@ -72,11 +73,11 @@ fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes( | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| inline fun <ObjectType, IdType> Route.configureReadStandardCrudRepoRoutes( | inline fun <ObjectType, IdType> Route.configureReadCRUDRepoRoutes( | ||||||
|     originalRepo: ReadStandardCRUDRepo<ObjectType, IdType>, |     originalRepo: ReadCRUDRepo<ObjectType, IdType>, | ||||||
|     objectsSerializer: KSerializer<ObjectType>, |     objectsSerializer: KSerializer<ObjectType>, | ||||||
|     objectsNullableSerializer: KSerializer<ObjectType?>, |     objectsNullableSerializer: KSerializer<ObjectType?>, | ||||||
|     idsSerializer: KSerializer<IdType>, |     idsSerializer: KSerializer<IdType>, | ||||||
|     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, |     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, | ||||||
|     serialFormatContentType: ContentType = standardKtorSerialFormatContentType |     serialFormatContentType: ContentType = standardKtorSerialFormatContentType | ||||||
| ) = configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType)) | ) = configureReadCRUDRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType)) | ||||||
|   | |||||||
| @@ -4,15 +4,15 @@ import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat | |||||||
| import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | ||||||
| import dev.inmo.micro_utils.ktor.server.UnifiedRouter | import dev.inmo.micro_utils.ktor.server.UnifiedRouter | ||||||
| import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType | import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType | ||||||
| import dev.inmo.micro_utils.repos.StandardCRUDRepo | import dev.inmo.micro_utils.repos.CRUDRepo | ||||||
| import io.ktor.http.ContentType | import io.ktor.http.ContentType | ||||||
| import io.ktor.server.routing.Route | import io.ktor.server.routing.Route | ||||||
| import io.ktor.server.routing.route | import io.ktor.server.routing.route | ||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
|  |  | ||||||
| fun <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes( | fun <ObjectType, IdType, InputValue> Route.configureCRUDRepoRoutes( | ||||||
|     baseSubpart: String, |     baseSubpart: String, | ||||||
|     originalRepo: StandardCRUDRepo<ObjectType, IdType, InputValue>, |     originalRepo: CRUDRepo<ObjectType, IdType, InputValue>, | ||||||
|     objectsSerializer: KSerializer<ObjectType>, |     objectsSerializer: KSerializer<ObjectType>, | ||||||
|     objectsNullableSerializer: KSerializer<ObjectType?>, |     objectsNullableSerializer: KSerializer<ObjectType?>, | ||||||
|     inputsSerializer: KSerializer<InputValue>, |     inputsSerializer: KSerializer<InputValue>, | ||||||
| @@ -20,20 +20,20 @@ fun <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes( | |||||||
|     unifiedRouter: UnifiedRouter |     unifiedRouter: UnifiedRouter | ||||||
| ) { | ) { | ||||||
|     route(baseSubpart) { |     route(baseSubpart) { | ||||||
|         configureReadStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, unifiedRouter) |         configureReadCRUDRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, idsSerializer, unifiedRouter) | ||||||
|         configureWriteStandardCrudRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, unifiedRouter) |         configureWriteCRUDRepoRoutes(originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, unifiedRouter) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fun <ObjectType, IdType, InputValue> Route.configureStandardCrudRepoRoutes( | fun <ObjectType, IdType, InputValue> Route.configureCRUDRepoRoutes( | ||||||
|     baseSubpart: String, |     baseSubpart: String, | ||||||
|     originalRepo: StandardCRUDRepo<ObjectType, IdType, InputValue>, |     originalRepo: CRUDRepo<ObjectType, IdType, InputValue>, | ||||||
|     objectsSerializer: KSerializer<ObjectType>, |     objectsSerializer: KSerializer<ObjectType>, | ||||||
|     objectsNullableSerializer: KSerializer<ObjectType?>, |     objectsNullableSerializer: KSerializer<ObjectType?>, | ||||||
|     inputsSerializer: KSerializer<InputValue>, |     inputsSerializer: KSerializer<InputValue>, | ||||||
|     idsSerializer: KSerializer<IdType>, |     idsSerializer: KSerializer<IdType>, | ||||||
|     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, |     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, | ||||||
|     serialFormatContentType: ContentType = standardKtorSerialFormatContentType |     serialFormatContentType: ContentType = standardKtorSerialFormatContentType | ||||||
| ) = configureStandardCrudRepoRoutes( | ) = configureCRUDRepoRoutes( | ||||||
|     baseSubpart, originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType) |     baseSubpart, originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType) | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -0,0 +1,41 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.server.crud | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.server.* | ||||||
|  | import dev.inmo.micro_utils.repos.WriteCRUDRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.crud.* | ||||||
|  | import io.ktor.http.HttpStatusCode | ||||||
|  | import io.ktor.server.application.call | ||||||
|  | import io.ktor.server.request.receive | ||||||
|  | import io.ktor.server.response.respond | ||||||
|  | import io.ktor.server.routing.Route | ||||||
|  | import io.ktor.server.routing.post | ||||||
|  |  | ||||||
|  | inline fun <reified ObjectType : Any, reified IdType : Any, reified InputValue : Any> Route.configureWriteCRUDRepoRoutes( | ||||||
|  |     originalRepo: WriteCRUDRepo<ObjectType, IdType, InputValue> | ||||||
|  | ) { | ||||||
|  |     includeWebsocketHandling( | ||||||
|  |         newObjectsFlowRouting, | ||||||
|  |         originalRepo.newObjectsFlow, | ||||||
|  |     ) | ||||||
|  |     includeWebsocketHandling( | ||||||
|  |         updatedObjectsFlowRouting, | ||||||
|  |         originalRepo.updatedObjectsFlow | ||||||
|  |     ) | ||||||
|  |     includeWebsocketHandling( | ||||||
|  |         deletedObjectsIdsFlowRouting, | ||||||
|  |         originalRepo.deletedObjectsIdsFlow | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     post(createRouting) { | ||||||
|  |         call.respond(originalRepo.create(call.receive())) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     post(updateRouting) { | ||||||
|  |         call.respond(originalRepo.update(call.receive())) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     post(deleteByIdRouting) { | ||||||
|  |         originalRepo.deleteById(call.receive()) | ||||||
|  |         call.respond(HttpStatusCode.OK) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -3,7 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.server.crud | |||||||
| import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat | import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat | ||||||
| import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | ||||||
| import dev.inmo.micro_utils.ktor.server.* | import dev.inmo.micro_utils.ktor.server.* | ||||||
| import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo | import dev.inmo.micro_utils.repos.WriteCRUDRepo | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.crud.* | import dev.inmo.micro_utils.repos.ktor.common.crud.* | ||||||
| import io.ktor.http.ContentType | import io.ktor.http.ContentType | ||||||
| import io.ktor.server.routing.Route | import io.ktor.server.routing.Route | ||||||
| @@ -11,8 +11,8 @@ import io.ktor.server.routing.post | |||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
| import kotlinx.serialization.builtins.* | import kotlinx.serialization.builtins.* | ||||||
|  |  | ||||||
| fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes( | fun <ObjectType, IdType, InputValue> Route.configureWriteCRUDRepoRoutes( | ||||||
|     originalRepo: WriteStandardCRUDRepo<ObjectType, IdType, InputValue>, |     originalRepo: WriteCRUDRepo<ObjectType, IdType, InputValue>, | ||||||
|     objectsSerializer: KSerializer<ObjectType>, |     objectsSerializer: KSerializer<ObjectType>, | ||||||
|     objectsNullableSerializer: KSerializer<ObjectType?>, |     objectsNullableSerializer: KSerializer<ObjectType?>, | ||||||
|     inputsSerializer: KSerializer<InputValue>, |     inputsSerializer: KSerializer<InputValue>, | ||||||
| @@ -94,14 +94,14 @@ fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes( | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fun <ObjectType, IdType, InputValue> Route.configureWriteStandardCrudRepoRoutes( | fun <ObjectType, IdType, InputValue> Route.configureWriteCRUDRepoRoutes( | ||||||
|     originalRepo: WriteStandardCRUDRepo<ObjectType, IdType, InputValue>, |     originalRepo: WriteCRUDRepo<ObjectType, IdType, InputValue>, | ||||||
|     objectsSerializer: KSerializer<ObjectType>, |     objectsSerializer: KSerializer<ObjectType>, | ||||||
|     objectsNullableSerializer: KSerializer<ObjectType?>, |     objectsNullableSerializer: KSerializer<ObjectType?>, | ||||||
|     inputsSerializer: KSerializer<InputValue>, |     inputsSerializer: KSerializer<InputValue>, | ||||||
|     idsSerializer: KSerializer<IdType>, |     idsSerializer: KSerializer<IdType>, | ||||||
|     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, |     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, | ||||||
|     serialFormatContentType: ContentType = standardKtorSerialFormatContentType |     serialFormatContentType: ContentType = standardKtorSerialFormatContentType | ||||||
| ) = configureWriteStandardCrudRepoRoutes( | ) = configureWriteCRUDRepoRoutes( | ||||||
|     originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType) |     originalRepo, objectsSerializer, objectsNullableSerializer, inputsSerializer, idsSerializer, UnifiedRouter(serialFormat, serialFormatContentType) | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -0,0 +1,47 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.server.key.value | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.KeyValueRepo | ||||||
|  | import io.ktor.http.* | ||||||
|  | import io.ktor.server.routing.Route | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValueRepoRoutes ( | ||||||
|  |     originalRepo: KeyValueRepo<Key, Value>, | ||||||
|  |     noinline idDeserializer: suspend (String) -> Key, | ||||||
|  |     noinline valueDeserializer: suspend (String) -> Value | ||||||
|  | ) { | ||||||
|  |     configureReadKeyValueRepoRoutes(originalRepo, idDeserializer, valueDeserializer) | ||||||
|  |     configureWriteKeyValueRepoRoutes(originalRepo) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValueRepoRoutes( | ||||||
|  |     originalRepo: KeyValueRepo<Key, Value>, | ||||||
|  |     idsSerializer: DeserializationStrategy<Key>, | ||||||
|  |     valueSerializer: DeserializationStrategy<Value>, | ||||||
|  |     serialFormat: StringFormat | ||||||
|  | ) = configureKeyValueRepoRoutes( | ||||||
|  |     originalRepo, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent()) | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent()) | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValueRepoRoutes( | ||||||
|  |     originalRepo: KeyValueRepo<Key, Value>, | ||||||
|  |     idsSerializer: DeserializationStrategy<Key>, | ||||||
|  |     valueSerializer: DeserializationStrategy<Value>, | ||||||
|  |     serialFormat: BinaryFormat | ||||||
|  | ) = configureKeyValueRepoRoutes( | ||||||
|  |     originalRepo, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeHex(idsSerializer, it) | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeHex(valueSerializer, it) | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
| @@ -0,0 +1,107 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.server.key.value | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.ktor.server.* | ||||||
|  | import dev.inmo.micro_utils.pagination.PaginationResult | ||||||
|  | import dev.inmo.micro_utils.pagination.extractPagination | ||||||
|  | import dev.inmo.micro_utils.repos.ReadKeyValueRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.containsRoute | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.countRoute | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.keyParameterName | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.key_value.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.reversedParameterName | ||||||
|  | import io.ktor.http.* | ||||||
|  | import io.ktor.server.application.call | ||||||
|  | import io.ktor.server.response.respond | ||||||
|  | import io.ktor.server.routing.Route | ||||||
|  | import io.ktor.server.routing.get | ||||||
|  | import io.ktor.util.InternalAPI | ||||||
|  | import io.ktor.util.reflect.typeInfo | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | @OptIn(InternalAPI::class) | ||||||
|  | inline fun <reified Key, reified Value> Route.configureReadKeyValueRepoRoutes ( | ||||||
|  |     originalRepo: ReadKeyValueRepo<Key, Value>, | ||||||
|  |     noinline idDeserializer: suspend (String) -> Key, | ||||||
|  |     noinline valueDeserializer: suspend (String) -> Value | ||||||
|  | ) { | ||||||
|  |     val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>() | ||||||
|  |     val paginationWithKeysTypeInfo = typeInfo<PaginationResult<Key>>() | ||||||
|  |  | ||||||
|  |     get(getRoute) { | ||||||
|  |         val key = idDeserializer( | ||||||
|  |             call.getQueryParameterOrSendError(keyParameterName) ?: return@get | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         originalRepo.get(key) ?.let { | ||||||
|  |             call.respond(it) | ||||||
|  |         } ?: call.respond(HttpStatusCode.NoContent) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get(valuesRoute) { | ||||||
|  |         val pagination = call.request.queryParameters.extractPagination | ||||||
|  |         val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false | ||||||
|  |  | ||||||
|  |         call.respond( | ||||||
|  |             originalRepo.values(pagination, reversed), | ||||||
|  |             paginationWithValuesTypeInfo | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get(keysRoute) { | ||||||
|  |         val pagination = call.request.queryParameters.extractPagination | ||||||
|  |         val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false | ||||||
|  |         val value = call.getQueryParameter(valueParameterName) ?.let { | ||||||
|  |             valueDeserializer(it) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         call.respond( | ||||||
|  |             value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed), | ||||||
|  |             paginationWithKeysTypeInfo | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get(containsRoute) { | ||||||
|  |         val key = idDeserializer( | ||||||
|  |             call.getQueryParameterOrSendError(keyParameterName) ?: return@get | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         call.respond(originalRepo.contains(key)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get(countRoute) { | ||||||
|  |         call.respond(originalRepo.count()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> Route.configureReadKeyValueRepoRoutes( | ||||||
|  |     originalRepo: ReadKeyValueRepo<Key, Value>, | ||||||
|  |     idsSerializer: DeserializationStrategy<Key>, | ||||||
|  |     valueSerializer: DeserializationStrategy<Value>, | ||||||
|  |     serialFormat: StringFormat | ||||||
|  | ) = configureReadKeyValueRepoRoutes( | ||||||
|  |     originalRepo, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeFromString(idsSerializer, it.decodeURLQueryComponent()) | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent()) | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> Route.configureReadKeyValueRepoRoutes( | ||||||
|  |     originalRepo: ReadKeyValueRepo<Key, Value>, | ||||||
|  |     idsSerializer: DeserializationStrategy<Key>, | ||||||
|  |     valueSerializer: DeserializationStrategy<Value>, | ||||||
|  |     serialFormat: BinaryFormat | ||||||
|  | ) = configureReadKeyValueRepoRoutes( | ||||||
|  |     originalRepo, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeHex(idsSerializer, it) | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeHex(valueSerializer, it) | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.server.key.value | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.server.* | ||||||
|  | import dev.inmo.micro_utils.repos.WriteKeyValueRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.key_value.* | ||||||
|  | import io.ktor.http.HttpStatusCode | ||||||
|  | import io.ktor.server.application.call | ||||||
|  | import io.ktor.server.request.receive | ||||||
|  | import io.ktor.server.response.respond | ||||||
|  | import io.ktor.server.routing.Route | ||||||
|  | import io.ktor.server.routing.post | ||||||
|  | import io.ktor.util.reflect.typeInfo | ||||||
|  |  | ||||||
|  | inline fun <reified Key : Any, reified Value : Any> Route.configureWriteKeyValueRepoRoutes ( | ||||||
|  |     originalRepo: WriteKeyValueRepo<Key, Value> | ||||||
|  | ) { | ||||||
|  |     includeWebsocketHandling( | ||||||
|  |         onNewValueRoute, | ||||||
|  |         originalRepo.onNewValue | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     includeWebsocketHandling( | ||||||
|  |         onValueRemovedRoute, | ||||||
|  |         originalRepo.onValueRemoved | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     val mapType = typeInfo<Map<Key, Value>>() | ||||||
|  |     val listKeysType = typeInfo<List<Key>>() | ||||||
|  |     val listValuesType = typeInfo<List<Value>>() | ||||||
|  |  | ||||||
|  |     post(setRoute) { | ||||||
|  |         originalRepo.set(call.receive(mapType)) | ||||||
|  |         call.respond(HttpStatusCode.OK) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     post(unsetRoute) { | ||||||
|  |         originalRepo.unset(call.receive(listKeysType)) | ||||||
|  |         call.respond(HttpStatusCode.OK) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     post(unsetWithValuesRoute) { | ||||||
|  |         originalRepo.unsetWithValues(call.receive(listValuesType)) | ||||||
|  |         call.respond(HttpStatusCode.OK) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,47 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.server.key.values | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.* | ||||||
|  | import io.ktor.http.* | ||||||
|  | import io.ktor.server.routing.Route | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValuesRepoRoutes ( | ||||||
|  |     originalRepo: KeyValuesRepo<Key, Value>, | ||||||
|  |     noinline keyDeserializer: suspend (String) -> Key, | ||||||
|  |     noinline valueDeserializer: suspend (String) -> Value | ||||||
|  | ) { | ||||||
|  |     configureReadKeyValuesRepoRoutes(originalRepo, keyDeserializer, valueDeserializer) | ||||||
|  |     configureWriteKeyValuesRepoRoutes(originalRepo) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValuesRepoRoutes( | ||||||
|  |     originalRepo: KeyValuesRepo<Key, Value>, | ||||||
|  |     keySerializer: DeserializationStrategy<Key>, | ||||||
|  |     valueSerializer: DeserializationStrategy<Value>, | ||||||
|  |     serialFormat: StringFormat | ||||||
|  | ) = configureKeyValuesRepoRoutes( | ||||||
|  |     originalRepo, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeFromString(keySerializer, it.decodeURLQueryComponent()) | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent()) | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | inline fun <reified Key : Any, reified Value : Any> Route.configureKeyValuesRepoRoutes( | ||||||
|  |     originalRepo: KeyValuesRepo<Key, Value>, | ||||||
|  |     keySerializer: DeserializationStrategy<Key>, | ||||||
|  |     valueSerializer: DeserializationStrategy<Value>, | ||||||
|  |     serialFormat: BinaryFormat | ||||||
|  | ) = configureKeyValuesRepoRoutes( | ||||||
|  |     originalRepo, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeHex(keySerializer, it) | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeHex(valueSerializer, it) | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
| @@ -0,0 +1,108 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.server.key.values | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.ktor.server.* | ||||||
|  | import dev.inmo.micro_utils.pagination.PaginationResult | ||||||
|  | import dev.inmo.micro_utils.pagination.extractPagination | ||||||
|  | import dev.inmo.micro_utils.repos.ReadKeyValuesRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.containsRoute | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.countRoute | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | ||||||
|  | import io.ktor.http.* | ||||||
|  | import io.ktor.server.application.call | ||||||
|  | import io.ktor.server.response.respond | ||||||
|  | import io.ktor.server.routing.Route | ||||||
|  | import io.ktor.server.routing.get | ||||||
|  | import io.ktor.util.InternalAPI | ||||||
|  | import io.ktor.util.reflect.typeInfo | ||||||
|  | import kotlinx.serialization.* | ||||||
|  |  | ||||||
|  | @OptIn(InternalAPI::class) | ||||||
|  | inline fun <reified Key, reified Value> Route.configureReadKeyValuesRepoRoutes ( | ||||||
|  |     originalRepo: ReadKeyValuesRepo<Key, Value>, | ||||||
|  |     noinline keyDeserializer: suspend (String) -> Key, | ||||||
|  |     noinline valueDeserializer: suspend (String) -> Value | ||||||
|  | ) { | ||||||
|  |     val paginationWithValuesTypeInfo = typeInfo<PaginationResult<Value>>() | ||||||
|  |     val paginationWithKeysTypeInfo = typeInfo<PaginationResult<Key>>() | ||||||
|  |  | ||||||
|  |     get(getRoute) { | ||||||
|  |         val key = keyDeserializer( | ||||||
|  |             call.getQueryParameterOrSendError(keyParameterName) ?: return@get | ||||||
|  |         ) | ||||||
|  |         val pagination = call.request.queryParameters.extractPagination | ||||||
|  |         val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false | ||||||
|  |  | ||||||
|  |         call.respond( | ||||||
|  |             originalRepo.get(key, pagination, reversed), | ||||||
|  |             paginationWithValuesTypeInfo | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get(keysRoute) { | ||||||
|  |         val pagination = call.request.queryParameters.extractPagination | ||||||
|  |         val reversed = call.getQueryParameter(reversedParameterName) ?.toBoolean() ?: false | ||||||
|  |         val value = call.getQueryParameter(valueParameterName) ?.let { | ||||||
|  |             valueDeserializer(it) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         call.respond( | ||||||
|  |             value ?.let { originalRepo.keys(value, pagination, reversed) } ?: originalRepo.keys(pagination, reversed), | ||||||
|  |             paginationWithKeysTypeInfo | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get(containsRoute) { | ||||||
|  |         val key = keyDeserializer( | ||||||
|  |             call.getQueryParameterOrSendError(keyParameterName) ?: return@get | ||||||
|  |         ) | ||||||
|  |         val value = call.getQueryParameter(valueParameterName) ?.let { | ||||||
|  |             valueDeserializer(it) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         call.respond( | ||||||
|  |             value ?.let { originalRepo.contains(key, value) } ?: originalRepo.contains(key) | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     get(countRoute) { | ||||||
|  |         val id = call.getQueryParameter(keyParameterName) ?.let { | ||||||
|  |             keyDeserializer(it) | ||||||
|  |         } | ||||||
|  |         call.respond( | ||||||
|  |             id ?.let { originalRepo.count(it) } ?: originalRepo.count() | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> Route.configureReadKeyValuesRepoRoutes( | ||||||
|  |     originalRepo: ReadKeyValuesRepo<Key, Value>, | ||||||
|  |     keySerializer: DeserializationStrategy<Key>, | ||||||
|  |     valueSerializer: DeserializationStrategy<Value>, | ||||||
|  |     serialFormat: StringFormat | ||||||
|  | ) = configureReadKeyValuesRepoRoutes( | ||||||
|  |     originalRepo, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeFromString(keySerializer, it.decodeURLQueryComponent()) | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeFromString(valueSerializer, it.decodeURLQueryComponent()) | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | inline fun <reified Key, reified Value> Route.configureReadKeyValuesRepoRoutes( | ||||||
|  |     originalRepo: ReadKeyValuesRepo<Key, Value>, | ||||||
|  |     keySerializer: DeserializationStrategy<Key>, | ||||||
|  |     valueSerializer: DeserializationStrategy<Value>, | ||||||
|  |     serialFormat: BinaryFormat | ||||||
|  | ) = configureReadKeyValuesRepoRoutes( | ||||||
|  |     originalRepo, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeHex(keySerializer, it) | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         serialFormat.decodeHex(valueSerializer, it) | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
| @@ -0,0 +1,58 @@ | |||||||
|  | package dev.inmo.micro_utils.repos.ktor.server.key.values | ||||||
|  |  | ||||||
|  | import dev.inmo.micro_utils.ktor.server.* | ||||||
|  | import dev.inmo.micro_utils.repos.WriteKeyValuesRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | ||||||
|  | import io.ktor.http.HttpStatusCode | ||||||
|  | import io.ktor.server.application.call | ||||||
|  | import io.ktor.server.request.receive | ||||||
|  | import io.ktor.server.response.respond | ||||||
|  | import io.ktor.server.routing.Route | ||||||
|  | import io.ktor.server.routing.post | ||||||
|  | import io.ktor.util.reflect.typeInfo | ||||||
|  |  | ||||||
|  | inline fun <reified Key : Any, reified Value : Any> Route.configureWriteKeyValuesRepoRoutes ( | ||||||
|  |     originalRepo: WriteKeyValuesRepo<Key, Value> | ||||||
|  | ) { | ||||||
|  |     includeWebsocketHandling( | ||||||
|  |         onNewValueRoute, | ||||||
|  |         originalRepo.onNewValue | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     includeWebsocketHandling( | ||||||
|  |         onValueRemovedRoute, | ||||||
|  |         originalRepo.onValueRemoved | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     includeWebsocketHandling( | ||||||
|  |         onDataClearedRoute, | ||||||
|  |         originalRepo.onDataCleared | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     val mapType = typeInfo<Map<Key, List<Value>>>() | ||||||
|  |  | ||||||
|  |     post(addRoute) { | ||||||
|  |         originalRepo.add(call.receive(mapType)) | ||||||
|  |         call.respond(HttpStatusCode.OK) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     post(setRoute) { | ||||||
|  |         originalRepo.set(call.receive(mapType)) | ||||||
|  |         call.respond(HttpStatusCode.OK) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     post(removeRoute) { | ||||||
|  |         originalRepo.remove(call.receive(mapType)) | ||||||
|  |         call.respond(HttpStatusCode.OK) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     post(clearRoute) { | ||||||
|  |         originalRepo.clear(call.receive()) | ||||||
|  |         call.respond(HttpStatusCode.OK) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     post(clearWithValueRoute) { | ||||||
|  |         originalRepo.clearWithValue(call.receive()) | ||||||
|  |         call.respond(HttpStatusCode.OK) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -4,15 +4,15 @@ import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat | |||||||
| import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | ||||||
| import dev.inmo.micro_utils.ktor.server.UnifiedRouter | import dev.inmo.micro_utils.ktor.server.UnifiedRouter | ||||||
| import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType | import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType | ||||||
| import dev.inmo.micro_utils.repos.StandardKeyValueRepo | import dev.inmo.micro_utils.repos.KeyValueRepo | ||||||
| import io.ktor.http.ContentType | import io.ktor.http.ContentType | ||||||
| import io.ktor.server.routing.Route | import io.ktor.server.routing.Route | ||||||
| import io.ktor.server.routing.route | import io.ktor.server.routing.route | ||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
|  |  | ||||||
| fun <K, V> Route.configureStandardKeyValueRepoRoutes( | fun <K, V> Route.configureKeyValueRepoRoutes( | ||||||
|     baseSubpart: String, |     baseSubpart: String, | ||||||
|     originalRepo: StandardKeyValueRepo<K, V>, |     originalRepo: KeyValueRepo<K, V>, | ||||||
|     keySerializer: KSerializer<K>, |     keySerializer: KSerializer<K>, | ||||||
|     valueSerializer: KSerializer<V>, |     valueSerializer: KSerializer<V>, | ||||||
|     valueNullableSerializer: KSerializer<V?>, |     valueNullableSerializer: KSerializer<V?>, | ||||||
| @@ -26,7 +26,7 @@ fun <K, V> Route.configureStandardKeyValueRepoRoutes( | |||||||
|             valueNullableSerializer, |             valueNullableSerializer, | ||||||
|             unifiedRouter |             unifiedRouter | ||||||
|         ) |         ) | ||||||
|         configureWriteStandardKeyValueRepoRoutes( |         configureWriteKeyValueRepoRoutes( | ||||||
|             originalRepo, |             originalRepo, | ||||||
|             keySerializer, |             keySerializer, | ||||||
|             valueSerializer, |             valueSerializer, | ||||||
| @@ -37,10 +37,10 @@ fun <K, V> Route.configureStandardKeyValueRepoRoutes( | |||||||
|  |  | ||||||
| fun <K, V> Route.configureStandartKeyValueRepoRoutes( | fun <K, V> Route.configureStandartKeyValueRepoRoutes( | ||||||
|     baseSubpart: String, |     baseSubpart: String, | ||||||
|     originalRepo: StandardKeyValueRepo<K, V>, |     originalRepo: KeyValueRepo<K, V>, | ||||||
|     keySerializer: KSerializer<K>, |     keySerializer: KSerializer<K>, | ||||||
|     valueSerializer: KSerializer<V>, |     valueSerializer: KSerializer<V>, | ||||||
|     valueNullableSerializer: KSerializer<V?>, |     valueNullableSerializer: KSerializer<V?>, | ||||||
|     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, |     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, | ||||||
|     serialFormatContentType: ContentType = standardKtorSerialFormatContentType |     serialFormatContentType: ContentType = standardKtorSerialFormatContentType | ||||||
| ) = configureStandardKeyValueRepoRoutes(baseSubpart, originalRepo, keySerializer, valueSerializer, valueNullableSerializer, UnifiedRouter(serialFormat, serialFormatContentType)) | ) = configureKeyValueRepoRoutes(baseSubpart, originalRepo, keySerializer, valueSerializer, valueNullableSerializer, UnifiedRouter(serialFormat, serialFormatContentType)) | ||||||
|   | |||||||
| @@ -5,9 +5,13 @@ import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | |||||||
| import dev.inmo.micro_utils.ktor.server.* | import dev.inmo.micro_utils.ktor.server.* | ||||||
| import dev.inmo.micro_utils.pagination.PaginationResult | import dev.inmo.micro_utils.pagination.PaginationResult | ||||||
| import dev.inmo.micro_utils.pagination.extractPagination | import dev.inmo.micro_utils.pagination.extractPagination | ||||||
| import dev.inmo.micro_utils.repos.ReadStandardKeyValueRepo | import dev.inmo.micro_utils.repos.ReadKeyValueRepo | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.* | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.containsRoute | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.countRoute | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.key_value.* | import dev.inmo.micro_utils.repos.ktor.common.key_value.* | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.valueParameterName | import dev.inmo.micro_utils.repos.ktor.common.key_value.keyParameterName | ||||||
|  | import dev.inmo.micro_utils.repos.ktor.common.key_value.reversedParameterName | ||||||
| import io.ktor.http.ContentType | import io.ktor.http.ContentType | ||||||
| import io.ktor.server.application.call | import io.ktor.server.application.call | ||||||
| import io.ktor.server.routing.Route | import io.ktor.server.routing.Route | ||||||
| @@ -16,7 +20,7 @@ import kotlinx.serialization.KSerializer | |||||||
| import kotlinx.serialization.builtins.serializer | import kotlinx.serialization.builtins.serializer | ||||||
|  |  | ||||||
| fun <K, V> Route.configureReadStandartKeyValueRepoRoutes ( | fun <K, V> Route.configureReadStandartKeyValueRepoRoutes ( | ||||||
|     originalRepo: ReadStandardKeyValueRepo<K, V>, |     originalRepo: ReadKeyValueRepo<K, V>, | ||||||
|     keySerializer: KSerializer<K>, |     keySerializer: KSerializer<K>, | ||||||
|     valueSerializer: KSerializer<V>, |     valueSerializer: KSerializer<V>, | ||||||
|     valueNullableSerializer: KSerializer<V?>, |     valueNullableSerializer: KSerializer<V?>, | ||||||
| @@ -92,7 +96,7 @@ fun <K, V> Route.configureReadStandartKeyValueRepoRoutes ( | |||||||
| } | } | ||||||
|  |  | ||||||
| inline fun <K, V> Route.configureReadStandartKeyValueRepoRoutes ( | inline fun <K, V> Route.configureReadStandartKeyValueRepoRoutes ( | ||||||
|     originalRepo: ReadStandardKeyValueRepo<K, V>, |     originalRepo: ReadKeyValueRepo<K, V>, | ||||||
|     keySerializer: KSerializer<K>, |     keySerializer: KSerializer<K>, | ||||||
|     valueSerializer: KSerializer<V>, |     valueSerializer: KSerializer<V>, | ||||||
|     valueNullableSerializer: KSerializer<V?>, |     valueNullableSerializer: KSerializer<V?>, | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.server.key_value | |||||||
| import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat | import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat | ||||||
| import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | ||||||
| import dev.inmo.micro_utils.ktor.server.* | import dev.inmo.micro_utils.ktor.server.* | ||||||
| import dev.inmo.micro_utils.repos.WriteStandardKeyValueRepo | import dev.inmo.micro_utils.repos.WriteKeyValueRepo | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.key_value.* | import dev.inmo.micro_utils.repos.ktor.common.key_value.* | ||||||
| import io.ktor.http.ContentType | import io.ktor.http.ContentType | ||||||
| import io.ktor.server.routing.Route | import io.ktor.server.routing.Route | ||||||
| @@ -11,8 +11,8 @@ import io.ktor.server.routing.post | |||||||
| import kotlinx.serialization.KSerializer | import kotlinx.serialization.KSerializer | ||||||
| import kotlinx.serialization.builtins.* | import kotlinx.serialization.builtins.* | ||||||
|  |  | ||||||
| fun <K, V> Route.configureWriteStandardKeyValueRepoRoutes ( | fun <K, V> Route.configureWriteKeyValueRepoRoutes ( | ||||||
|     originalRepo: WriteStandardKeyValueRepo<K, V>, |     originalRepo: WriteKeyValueRepo<K, V>, | ||||||
|     keySerializer: KSerializer<K>, |     keySerializer: KSerializer<K>, | ||||||
|     valueSerializer: KSerializer<V>, |     valueSerializer: KSerializer<V>, | ||||||
|     unifiedRouter: UnifiedRouter |     unifiedRouter: UnifiedRouter | ||||||
| @@ -62,9 +62,9 @@ fun <K, V> Route.configureWriteStandardKeyValueRepoRoutes ( | |||||||
| } | } | ||||||
|  |  | ||||||
| fun <K, V> Route.configureWriteStandartKeyValueRepoRoutes ( | fun <K, V> Route.configureWriteStandartKeyValueRepoRoutes ( | ||||||
|     originalRepo: WriteStandardKeyValueRepo<K, V>, |     originalRepo: WriteKeyValueRepo<K, V>, | ||||||
|     keySerializer: KSerializer<K>, |     keySerializer: KSerializer<K>, | ||||||
|     valueSerializer: KSerializer<V>, |     valueSerializer: KSerializer<V>, | ||||||
|     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, |     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, | ||||||
|     serialFormatContentType: ContentType = standardKtorSerialFormatContentType |     serialFormatContentType: ContentType = standardKtorSerialFormatContentType | ||||||
| ) = configureWriteStandardKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType)) | ) = configureWriteKeyValueRepoRoutes(originalRepo, keySerializer, valueSerializer, UnifiedRouter(serialFormat, serialFormatContentType)) | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat | |||||||
| import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | ||||||
| import dev.inmo.micro_utils.ktor.server.UnifiedRouter | import dev.inmo.micro_utils.ktor.server.UnifiedRouter | ||||||
| import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType | import dev.inmo.micro_utils.ktor.server.standardKtorSerialFormatContentType | ||||||
| import dev.inmo.micro_utils.repos.OneToManyKeyValueRepo | import dev.inmo.micro_utils.repos.KeyValuesRepo | ||||||
| import io.ktor.http.ContentType | import io.ktor.http.ContentType | ||||||
| import io.ktor.server.routing.Route | import io.ktor.server.routing.Route | ||||||
| import io.ktor.server.routing.route | import io.ktor.server.routing.route | ||||||
| @@ -12,7 +12,7 @@ import kotlinx.serialization.KSerializer | |||||||
|  |  | ||||||
| fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes( | fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes( | ||||||
|     baseSubpart: String, |     baseSubpart: String, | ||||||
|     originalRepo: OneToManyKeyValueRepo<Key, Value>, |     originalRepo: KeyValuesRepo<Key, Value>, | ||||||
|     keySerializer: KSerializer<Key>, |     keySerializer: KSerializer<Key>, | ||||||
|     valueSerializer: KSerializer<Value>, |     valueSerializer: KSerializer<Value>, | ||||||
|     unifiedRouter: UnifiedRouter |     unifiedRouter: UnifiedRouter | ||||||
| @@ -25,7 +25,7 @@ fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes( | |||||||
|  |  | ||||||
| fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes( | fun <Key, Value> Route.configureOneToManyKeyValueRepoRoutes( | ||||||
|     baseSubpart: String, |     baseSubpart: String, | ||||||
|     originalRepo: OneToManyKeyValueRepo<Key, Value>, |     originalRepo: KeyValuesRepo<Key, Value>, | ||||||
|     keySerializer: KSerializer<Key>, |     keySerializer: KSerializer<Key>, | ||||||
|     valueSerializer: KSerializer<Value>, |     valueSerializer: KSerializer<Value>, | ||||||
|     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, |     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | |||||||
| import dev.inmo.micro_utils.ktor.server.* | import dev.inmo.micro_utils.ktor.server.* | ||||||
| import dev.inmo.micro_utils.pagination.PaginationResult | import dev.inmo.micro_utils.pagination.PaginationResult | ||||||
| import dev.inmo.micro_utils.pagination.extractPagination | import dev.inmo.micro_utils.pagination.extractPagination | ||||||
| import dev.inmo.micro_utils.repos.ReadOneToManyKeyValueRepo | import dev.inmo.micro_utils.repos.ReadKeyValuesRepo | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.keyParameterName | import dev.inmo.micro_utils.repos.ktor.common.keyParameterName | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.valueParameterName | import dev.inmo.micro_utils.repos.ktor.common.valueParameterName | ||||||
| @@ -18,7 +18,7 @@ import kotlinx.serialization.KSerializer | |||||||
| import kotlinx.serialization.builtins.serializer | import kotlinx.serialization.builtins.serializer | ||||||
|  |  | ||||||
| fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes( | fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes( | ||||||
|     originalRepo: ReadOneToManyKeyValueRepo<Key, Value>, |     originalRepo: ReadKeyValuesRepo<Key, Value>, | ||||||
|     keySerializer: KSerializer<Key>, |     keySerializer: KSerializer<Key>, | ||||||
|     valueSerializer: KSerializer<Value>, |     valueSerializer: KSerializer<Value>, | ||||||
|     unifiedRouter: UnifiedRouter |     unifiedRouter: UnifiedRouter | ||||||
| @@ -121,7 +121,7 @@ fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes( | |||||||
| } | } | ||||||
|  |  | ||||||
| inline fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes( | inline fun <Key, Value> Route.configureOneToManyReadKeyValueRepoRoutes( | ||||||
|     originalRepo: ReadOneToManyKeyValueRepo<Key, Value>, |     originalRepo: ReadKeyValuesRepo<Key, Value>, | ||||||
|     keySerializer: KSerializer<Key>, |     keySerializer: KSerializer<Key>, | ||||||
|     valueSerializer: KSerializer<Value>, |     valueSerializer: KSerializer<Value>, | ||||||
|     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, |     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ package dev.inmo.micro_utils.repos.ktor.server.one_to_many | |||||||
| import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat | import dev.inmo.micro_utils.ktor.common.StandardKtorSerialFormat | ||||||
| import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat | ||||||
| import dev.inmo.micro_utils.ktor.server.* | import dev.inmo.micro_utils.ktor.server.* | ||||||
| import dev.inmo.micro_utils.repos.WriteOneToManyKeyValueRepo | import dev.inmo.micro_utils.repos.WriteKeyValuesRepo | ||||||
| import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* | ||||||
| import io.ktor.http.ContentType | import io.ktor.http.ContentType | ||||||
| import io.ktor.server.routing.Route | import io.ktor.server.routing.Route | ||||||
| @@ -12,7 +12,7 @@ import kotlinx.serialization.KSerializer | |||||||
| import kotlinx.serialization.builtins.* | import kotlinx.serialization.builtins.* | ||||||
|  |  | ||||||
| fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes( | fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes( | ||||||
|     originalRepo: WriteOneToManyKeyValueRepo<Key, Value>, |     originalRepo: WriteKeyValuesRepo<Key, Value>, | ||||||
|     keySerializer: KSerializer<Key>, |     keySerializer: KSerializer<Key>, | ||||||
|     valueSerializer: KSerializer<Value>, |     valueSerializer: KSerializer<Value>, | ||||||
|     unifiedRouter: UnifiedRouter |     unifiedRouter: UnifiedRouter | ||||||
| @@ -95,7 +95,7 @@ fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes( | |||||||
| } | } | ||||||
|  |  | ||||||
| fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes( | fun <Key, Value> Route.configureOneToManyWriteKeyValueRepoRoutes( | ||||||
|     originalRepo: WriteOneToManyKeyValueRepo<Key, Value>, |     originalRepo: WriteKeyValuesRepo<Key, Value>, | ||||||
|     keySerializer: KSerializer<Key>, |     keySerializer: KSerializer<Key>, | ||||||
|     valueSerializer: KSerializer<Value>, |     valueSerializer: KSerializer<Value>, | ||||||
|     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, |     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user