mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-10-31 12:10:29 +00:00 
			
		
		
		
	Compare commits
	
		
			49 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 4d155d0505 | |||
| a169e733d9 | |||
| f081e237c8 | |||
| f412d387fa | |||
| 67354b43e2 | |||
| 39135a4000 | |||
| eaa014cebd | |||
| 856e657f81 | |||
| 3a609e5b66 | |||
| d0022dd599 | |||
| 7ba6eed453 | |||
| beeb6ecc0a | |||
| 7cdc17a714 | |||
| 4765a950a9 | |||
| 65e8137e08 | |||
| ae546dd9ad | |||
| 8110c42be0 | |||
| bd2b5ae5fc | |||
| 2ddfffa6a9 | |||
| a4b54e861d | |||
| c6785f1a4f | |||
| 83fe621c56 | |||
| b3a93e17eb | |||
| 546a391af3 | |||
| 786cf9bd8b | |||
| dfd6fe062d | |||
| b6ef818613 | |||
| b0f9e9c30a | |||
| 7e5c88ddc3 | |||
| 9824c3e00f | |||
| 9171d5ed11 | |||
| a1830ebb82 | |||
| 22d2a3d9bf | |||
| c9b97fc965 | |||
| 51f85becd5 | |||
| a8a281cfb4 | |||
| ddd1304949 | |||
| 86d70b6c02 | |||
| a22bdb39e7 | |||
| 7ae4d5ef95 | |||
| a2038cbefa | |||
| 992091eade | |||
| e3bfead0c5 | |||
| 0de96141fd | |||
| fa18d15c3c | |||
| ea9dbf2371 | |||
| d34e3ec7a9 | |||
| c8833a36af | |||
| a067cb0c0f | 
							
								
								
									
										76
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,5 +1,81 @@ | ||||
| # Changelog | ||||
|  | ||||
| ## 0.19.9 | ||||
|  | ||||
| * `Versions`: | ||||
|     * `Koin`: `3.4.2` -> `3.4.3` | ||||
| * `Startup`: | ||||
|     * Now it is possible to start application in synchronous way | ||||
|  | ||||
| ## 0.19.8 | ||||
|  | ||||
| * `Versions`: | ||||
|     * `Coroutines`: `1.7.2` -> `1.7.3` | ||||
|     * `Kotlin`: `1.8.20` -> `1.8.22` | ||||
|     * `Compose`: `1.4.1` -> `1.4.3` | ||||
|     * `Okio`: `3.3.0` -> `3.4.0` | ||||
|     * `RecyclerView`: `1.3.0` -> `1.3.1` | ||||
|     * `Fragment`: `1.6.0` -> `1.6.1` | ||||
| * `Repos`: | ||||
|     * Fixes In `KeyValueRepo.clear()` of almost all inheritors of `KeyValueRepo` | ||||
|     * `Cache`: | ||||
|         * All full caches got `skipStartInvalidate` property. By default, this property is `false` and fully caching repos | ||||
|           will be automatically invalidated on start of their work | ||||
|  | ||||
| ## 0.19.7 | ||||
|  | ||||
| * `Versions`: | ||||
|     * `Coroutines`: `1.7.1` -> `1.7.2` | ||||
|  | ||||
| ## 0.19.6 | ||||
|  | ||||
| * `Versions`: | ||||
|     * `Coroutines`: `1.6.4` -> `1.7.1` | ||||
|     * `Ktor`: `2.3.1` -> `2.3.2` | ||||
|     * `Compose`: `1.4.0` -> `1.4.1` | ||||
|  | ||||
| ## 0.19.5 | ||||
|  | ||||
| * `Repos`: | ||||
|     * `Generator`: | ||||
|         * Fixes in new type generation | ||||
|  | ||||
| ## 0.19.4 | ||||
|  | ||||
| * `Versions`: | ||||
|     * `Koin`: `3.4.1` -> `3.4.2` | ||||
|     * `Android Fragments`: `1.5.7` -> `1.6.0` | ||||
| * `Koin` | ||||
|     * `Generator` | ||||
|         * Fixes in new generic generator part | ||||
|  | ||||
| ## 0.19.3 | ||||
|  | ||||
| * `Koin` | ||||
|     * `Generator` | ||||
|         * New getter methods now available with opportunity to use parameters | ||||
|         * Old notation `*Single` and `*Factory` is deprecated since this release. With old | ||||
|           will be generated new `single*` and `factory*` notations for new generations | ||||
|         * Add opportunity to use generic-oriented koin definitions | ||||
|  | ||||
| ## 0.19.2 | ||||
|  | ||||
| * `Versions`: | ||||
|     * `Ktor`: `2.3.0` -> `2.3.1` | ||||
|     * `Koin`: `3.4.0` -> `3.4.1` | ||||
|     * `Uuid`: `0.7.0` -> `0.7.1` | ||||
|  | ||||
| ## 0.19.1 | ||||
|  | ||||
| * `Versions`: | ||||
|     * `Korlibs`: `4.0.1` -> `4.0.3` | ||||
|     * `Kotlin Poet`: `1.13.2` -> `1.14.0` | ||||
|  | ||||
| ## 0.19.0 | ||||
|  | ||||
| * `Versions`: | ||||
|     * `Korlibs`: `3.4.0` -> `4.0.1` | ||||
|  | ||||
| ## 0.18.4 | ||||
|  | ||||
| * `Koin`: | ||||
|   | ||||
| @@ -17,6 +17,10 @@ buildscript { | ||||
|     } | ||||
| } | ||||
|  | ||||
| plugins { | ||||
|     alias(libs.plugins.versions) | ||||
| } | ||||
|  | ||||
| allprojects { | ||||
|     repositories { | ||||
|         mavenLocal() | ||||
| @@ -38,3 +42,4 @@ allprojects { | ||||
|  | ||||
| apply from: "./extensions.gradle" | ||||
| apply from: "./github_release.gradle" | ||||
| apply from: "./versions_plugin_setup.gradle" | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| package dev.inmo.micro_utils.crypto | ||||
|  | ||||
| import com.soywiz.krypto.md5 | ||||
| import korlibs.crypto.md5 | ||||
|  | ||||
| typealias MD5 = String | ||||
|  | ||||
|   | ||||
| @@ -13,10 +13,10 @@ repositories { | ||||
|  | ||||
| kotlin { | ||||
|     jvm() | ||||
| //    js(IR) { | ||||
| //        browser() | ||||
| //        nodejs() | ||||
| //    } | ||||
|     js(IR) { | ||||
|         browser() | ||||
|         nodejs() | ||||
|     } | ||||
|     android {} | ||||
|  | ||||
|     sourceSets { | ||||
| @@ -29,7 +29,7 @@ kotlin { | ||||
|                             it != project | ||||
|                                     && it.hasProperty("kotlin") | ||||
|                                     && it.kotlin.sourceSets.any { it.name.contains("commonMain") } | ||||
| //                        && it.kotlin.sourceSets.any { it.name.contains("jsMain") } | ||||
|                                     && it.kotlin.sourceSets.any { it.name.contains("jsMain") } | ||||
|                                     && it.kotlin.sourceSets.any { it.name.contains("jvmMain") } | ||||
|                                     && it.kotlin.sourceSets.any { it.name.contains("androidMain") } | ||||
|                     ) { | ||||
| @@ -38,22 +38,22 @@ kotlin { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| //        jsMain { | ||||
| //            dependencies { | ||||
| //                implementation kotlin('stdlib') | ||||
|         jsMain { | ||||
|             dependencies { | ||||
|                 implementation kotlin('stdlib') | ||||
|  | ||||
| //                project.parent.subprojects.forEach { | ||||
| //                    if ( | ||||
| //                        it != project | ||||
| //                        && it.hasProperty("kotlin") | ||||
| //                        && it.kotlin.sourceSets.any { it.name.contains("commonMain") } | ||||
| //                        && it.kotlin.sourceSets.any { it.name.contains("jsMain") } | ||||
| //                    ) { | ||||
| //                        api it | ||||
| //                    } | ||||
| //                } | ||||
| //            } | ||||
| //        } | ||||
|                 project.parent.subprojects.forEach { | ||||
|                     if ( | ||||
|                             it != project | ||||
|                                     && it.hasProperty("kotlin") | ||||
|                                     && it.kotlin.sourceSets.any { it.name.contains("commonMain") } | ||||
|                                     && it.kotlin.sourceSets.any { it.name.contains("jsMain") } | ||||
|                     ) { | ||||
|                         api it | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         jvmMain { | ||||
|             dependencies { | ||||
|                 implementation kotlin('stdlib') | ||||
| @@ -116,9 +116,9 @@ tasks.dokkaHtml { | ||||
|             sourceRoots.setFrom(findSourcesWithName("commonMain")) | ||||
|         } | ||||
|  | ||||
| //        named("jsMain") { | ||||
| //            sourceRoots.setFrom(findSourcesWithName("jsMain", "commonMain")) | ||||
| //        } | ||||
|         named("jsMain") { | ||||
|             sourceRoots.setFrom(findSourcesWithName("jsMain")) | ||||
|         } | ||||
|  | ||||
|         named("jvmMain") { | ||||
|             sourceRoots.setFrom(findSourcesWithName("jvmMain")) | ||||
|   | ||||
| @@ -14,5 +14,5 @@ crypto_js_version=4.1.1 | ||||
| # Project data | ||||
|  | ||||
| group=dev.inmo | ||||
| version=0.18.4 | ||||
| android_code_version=195 | ||||
| version=0.19.9 | ||||
| android_code_version=205 | ||||
|   | ||||
| @@ -1,36 +1,38 @@ | ||||
| [versions] | ||||
|  | ||||
| kt = "1.8.20" | ||||
| kt = "1.8.22" | ||||
| kt-serialization = "1.5.1" | ||||
| kt-coroutines = "1.6.4" | ||||
| kt-coroutines = "1.7.3" | ||||
|  | ||||
| kslog = "1.1.1" | ||||
|  | ||||
| jb-compose = "1.4.0" | ||||
| jb-compose = "1.4.3" | ||||
| jb-exposed = "0.41.1" | ||||
| jb-dokka = "1.8.10" | ||||
| jb-dokka = "1.8.20" | ||||
|  | ||||
| korlibs = "3.4.0" | ||||
| uuid = "0.7.0" | ||||
| korlibs = "4.0.3" | ||||
| uuid = "0.7.1" | ||||
|  | ||||
| ktor = "2.3.0" | ||||
| ktor = "2.3.2" | ||||
|  | ||||
| gh-release = "2.4.1" | ||||
|  | ||||
| koin = "3.4.0" | ||||
| koin = "3.4.3" | ||||
|  | ||||
| okio = "3.3.0" | ||||
| okio = "3.4.0" | ||||
|  | ||||
| ksp = "1.8.20-1.0.11" | ||||
| kotlin-poet = "1.13.2" | ||||
| ksp = "1.8.22-1.0.11" | ||||
| kotlin-poet = "1.14.2" | ||||
|  | ||||
| versions = "0.47.0" | ||||
|  | ||||
| android-gradle = "7.4.2" | ||||
| dexcount = "4.0.0" | ||||
|  | ||||
| android-coreKtx = "1.10.1" | ||||
| android-recyclerView = "1.3.0" | ||||
| android-recyclerView = "1.3.1" | ||||
| android-appCompat = "1.6.1" | ||||
| android-fragment = "1.5.7" | ||||
| android-fragment = "1.6.1" | ||||
| android-espresso = "3.5.1" | ||||
| android-test = "1.1.5" | ||||
|  | ||||
| @@ -109,3 +111,5 @@ buildscript-android-dexcount = { module = "com.getkeepsafe.dexcount:dexcount-gra | ||||
| [plugins] | ||||
|  | ||||
| jb-compose = { id = "org.jetbrains.compose", version.ref = "jb-compose" } | ||||
|  | ||||
| versions = { id = "com.github.ben-manes.versions", version.ref = "versions" } | ||||
|   | ||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,5 @@ | ||||
| distributionBase=GRADLE_USER_HOME | ||||
| distributionPath=wrapper/dists | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip | ||||
| zipStoreBase=GRADLE_USER_HOME | ||||
| zipStorePath=wrapper/dists | ||||
|   | ||||
| @@ -13,3 +13,8 @@ dependencies { | ||||
|     api libs.kotlin.poet | ||||
|     api libs.ksp | ||||
| } | ||||
|  | ||||
| java { | ||||
|     sourceCompatibility = JavaVersion.VERSION_1_8 | ||||
|     targetCompatibility = JavaVersion.VERSION_1_8 | ||||
| } | ||||
|   | ||||
| @@ -9,19 +9,28 @@ import com.google.devtools.ksp.processing.Resolver | ||||
| import com.google.devtools.ksp.processing.SymbolProcessor | ||||
| import com.google.devtools.ksp.symbol.KSAnnotated | ||||
| import com.google.devtools.ksp.symbol.KSFile | ||||
| import com.google.devtools.ksp.symbol.Modifier | ||||
| import com.squareup.kotlinpoet.AnnotationSpec | ||||
| import com.squareup.kotlinpoet.ClassName | ||||
| import com.squareup.kotlinpoet.CodeBlock | ||||
| import com.squareup.kotlinpoet.FileSpec | ||||
| import com.squareup.kotlinpoet.FunSpec | ||||
| import com.squareup.kotlinpoet.KModifier | ||||
| import com.squareup.kotlinpoet.ParameterSpec | ||||
| import com.squareup.kotlinpoet.ParameterizedTypeName | ||||
| import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy | ||||
| import com.squareup.kotlinpoet.PropertySpec | ||||
| import com.squareup.kotlinpoet.TypeName | ||||
| import com.squareup.kotlinpoet.TypeVariableName | ||||
| import com.squareup.kotlinpoet.asTypeName | ||||
| import com.squareup.kotlinpoet.ksp.toClassName | ||||
| import com.squareup.kotlinpoet.ksp.toTypeName | ||||
| import com.squareup.kotlinpoet.ksp.writeTo | ||||
| import dev.inmo.micro_utils.koin.annotations.GenerateGenericKoinDefinition | ||||
| import dev.inmo.micro_utils.koin.annotations.GenerateKoinDefinition | ||||
| import org.koin.core.Koin | ||||
| import org.koin.core.module.Module | ||||
| import org.koin.core.parameter.ParametersDefinition | ||||
| import org.koin.core.scope.Scope | ||||
| import java.io.File | ||||
| import kotlin.reflect.KClass | ||||
| @@ -32,11 +41,236 @@ class Processor( | ||||
|     private val definitionClassName = ClassName("org.koin.core.definition", "Definition") | ||||
|     private val koinDefinitionClassName = ClassName("org.koin.core.definition", "KoinDefinition") | ||||
|  | ||||
|     private fun FileSpec.Builder.addCodeForType( | ||||
|         targetType: TypeName, | ||||
|         name: String, | ||||
|         nullable: Boolean, | ||||
|         generateSingle: Boolean, | ||||
|         generateFactory: Boolean, | ||||
|     ) { | ||||
|         val targetTypeAsGenericType = (targetType as? TypeVariableName) ?.copy(reified = true) | ||||
|  | ||||
|         fun addGetterProperty( | ||||
|             receiver: KClass<*> | ||||
|         ) { | ||||
|             addProperty( | ||||
|                 PropertySpec.builder( | ||||
|                     name, | ||||
|                     targetType, | ||||
|                 ).apply { | ||||
|                     addKdoc( | ||||
|                         """ | ||||
|                             @return Definition by key "${name}" | ||||
|                         """.trimIndent() | ||||
|                     ) | ||||
|                     getter( | ||||
|                         FunSpec.getterBuilder().apply { | ||||
|                             targetTypeAsGenericType ?.let { | ||||
|                                 addModifiers(KModifier.INLINE) | ||||
|                             } | ||||
|                             addCode( | ||||
|                                 "return " + (if (nullable) { | ||||
|                                     "getOrNull" | ||||
|                                 } else { | ||||
|                                     "get" | ||||
|                                 }) + "(named(\"${name}\"))" | ||||
|                             ) | ||||
|                         }.build() | ||||
|                     ) | ||||
|                     targetTypeAsGenericType ?.let { | ||||
|                         addTypeVariable(it) | ||||
|                     } | ||||
|                     receiver(receiver) | ||||
|                 }.build() | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         if (targetTypeAsGenericType == null) { | ||||
|             addGetterProperty(Scope::class) | ||||
|             addGetterProperty(Koin::class) | ||||
|         } | ||||
|  | ||||
|         val parametersDefinitionClassName = ClassName( | ||||
|             "org.koin.core.parameter", | ||||
|             "ParametersDefinition" | ||||
|         ) | ||||
|         fun addGetterMethod( | ||||
|             receiver: KClass<*> | ||||
|         ) { | ||||
|             addFunction( | ||||
|                 FunSpec.builder( | ||||
|                     name | ||||
|                 ).apply { | ||||
|                     addKdoc( | ||||
|                         """ | ||||
|                             @return Definition by key "${name}" with [parameters] | ||||
|                         """.trimIndent() | ||||
|                     ) | ||||
|                     receiver(receiver) | ||||
|                     addParameter( | ||||
|                         ParameterSpec( | ||||
|                             "parameters", | ||||
|                             parametersDefinitionClassName.let { | ||||
|                                 if (targetTypeAsGenericType != null) { | ||||
|                                     it.copy(nullable = true) | ||||
|                                 } else { | ||||
|                                     it | ||||
|                                 } | ||||
|                             }, | ||||
|                             KModifier.NOINLINE | ||||
|                         ).toBuilder().apply { | ||||
|                             if (targetTypeAsGenericType != null) { | ||||
|                                 defaultValue("null") | ||||
|                             } | ||||
|                         }.build() | ||||
|                     ) | ||||
|                     addModifiers(KModifier.INLINE) | ||||
|                     targetTypeAsGenericType ?.let { | ||||
|                         addTypeVariable(it) | ||||
|                         returns(it.copy(nullable = nullable)) | ||||
|                     } ?: returns(targetType) | ||||
|                     addCode( | ||||
|                         "return " + (if (nullable) { | ||||
|                             "getOrNull" | ||||
|                         } else { | ||||
|                             "get" | ||||
|                         }) + "(named(\"${name}\"), parameters)" | ||||
|                     ) | ||||
|                 }.build() | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         addGetterMethod(Scope::class) | ||||
|         addGetterMethod(Koin::class) | ||||
|  | ||||
|         fun FunSpec.Builder.addDefinitionParameter() { | ||||
|             val definitionModifiers = if (targetTypeAsGenericType == null) { | ||||
|                 arrayOf() | ||||
|             } else { | ||||
|                 arrayOf(KModifier.NOINLINE) | ||||
|             } | ||||
|             addParameter( | ||||
|                 ParameterSpec.builder( | ||||
|                     "definition", | ||||
|                     definitionClassName.parameterizedBy(targetType.copy(nullable = false)), | ||||
|                     *definitionModifiers | ||||
|                 ).build() | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         if (generateSingle) { | ||||
|             fun FunSpec.Builder.configure( | ||||
|                 useInstead: String? = null | ||||
|             ) { | ||||
|                 addKdoc( | ||||
|                     """ | ||||
|                         Will register [definition] with [org.koin.core.module.Module.single] and key "${name}" | ||||
|                     """.trimIndent() | ||||
|                 ) | ||||
|                 receiver(Module::class) | ||||
|                 addParameter( | ||||
|                     ParameterSpec.builder( | ||||
|                         "createdAtStart", | ||||
|                         Boolean::class | ||||
|                     ).apply { | ||||
|                         defaultValue("false") | ||||
|                     }.build() | ||||
|                 ) | ||||
|                 addDefinitionParameter() | ||||
|                 returns(koinDefinitionClassName.parameterizedBy(targetType.copy(nullable = false))) | ||||
|                 addCode( | ||||
|                     "return single(named(\"${name}\"), createdAtStart = createdAtStart, definition = definition)" | ||||
|                 ) | ||||
|                 targetTypeAsGenericType ?.let { | ||||
|                     addTypeVariable(it) | ||||
|                     addModifiers(KModifier.INLINE) | ||||
|                 } | ||||
|                 if (useInstead != null) { | ||||
|                     addAnnotation( | ||||
|                         AnnotationSpec.builder( | ||||
|                             Deprecated::class | ||||
|                         ).apply { | ||||
|                             addMember( | ||||
|                                 CodeBlock.of( | ||||
|                                     """ | ||||
|                                         "This definition is old style and should not be used anymore. Use $useInstead instead" | ||||
|                                     """.trimIndent() | ||||
|                                 ) | ||||
|                             ) | ||||
|                             addMember(CodeBlock.of("ReplaceWith(\"$useInstead\")")) | ||||
|                         }.build() | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             val actualSingleName = "single${name.replaceFirstChar { it.uppercase() }}" | ||||
|             if (targetTypeAsGenericType == null) { // classic type | ||||
|                 addFunction( | ||||
|                     FunSpec.builder("${name}Single").apply { configure(actualSingleName) }.build() | ||||
|                 ) | ||||
|             } | ||||
|  | ||||
|             addFunction( | ||||
|                 FunSpec.builder(actualSingleName).apply { configure() }.build() | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         if (generateFactory) { | ||||
|             fun FunSpec.Builder.configure( | ||||
|                 useInstead: String? = null | ||||
|             ) { | ||||
|                 addKdoc( | ||||
|                     """ | ||||
|                         Will register [definition] with [org.koin.core.module.Module.factory] and key "${name}" | ||||
|                     """.trimIndent() | ||||
|                 ) | ||||
|                 receiver(Module::class) | ||||
|                 addDefinitionParameter() | ||||
|                 returns(koinDefinitionClassName.parameterizedBy(targetType.copy(nullable = false))) | ||||
|                 addCode( | ||||
|                     "return factory(named(\"${name}\"), definition = definition)" | ||||
|                 ) | ||||
|                 targetTypeAsGenericType ?.let { | ||||
|                     addTypeVariable(it) | ||||
|                     addModifiers(KModifier.INLINE) | ||||
|                 } | ||||
|                 if (useInstead != null) { | ||||
|                     addAnnotation( | ||||
|                         AnnotationSpec.builder( | ||||
|                             Deprecated::class | ||||
|                         ).apply { | ||||
|                             addMember( | ||||
|                                 CodeBlock.of( | ||||
|                                     """ | ||||
|                                         "This definition is old style and should not be used anymore. Use $useInstead instead" | ||||
|                                     """.trimIndent() | ||||
|                                 ) | ||||
|                             ) | ||||
|                             addMember(CodeBlock.of("ReplaceWith(\"$useInstead\")")) | ||||
|                         }.build() | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|             val actualFactoryName = "factory${name.replaceFirstChar { it.uppercase() }}" | ||||
|             if (targetTypeAsGenericType == null) { // classic type | ||||
|                 addFunction( | ||||
|                     FunSpec.builder("${name}Factory").apply { configure(useInstead = actualFactoryName) }.build() | ||||
|                 ) | ||||
|             } | ||||
|             addFunction( | ||||
|                 FunSpec.builder(actualFactoryName).apply { configure() }.build() | ||||
|             ) | ||||
|         } | ||||
|         addImport("org.koin.core.qualifier", "named") | ||||
|     } | ||||
|  | ||||
|     @OptIn(KspExperimental::class) | ||||
|     override fun process(resolver: Resolver): List<KSAnnotated> { | ||||
|         resolver.getSymbolsWithAnnotation( | ||||
|         (resolver.getSymbolsWithAnnotation( | ||||
|             GenerateKoinDefinition::class.qualifiedName!! | ||||
|         ).filterIsInstance<KSFile>().forEach { ksFile -> | ||||
|         ) + resolver.getSymbolsWithAnnotation( | ||||
|             GenerateGenericKoinDefinition::class.qualifiedName!! | ||||
|         )).filterIsInstance<KSFile>().forEach { ksFile -> | ||||
|             FileSpec.builder( | ||||
|                 ksFile.packageName.asString(), | ||||
|                 "GeneratedDefinitions${ksFile.fileName.removeSuffix(".kt")}" | ||||
| @@ -72,92 +306,12 @@ class Processor( | ||||
|                     }.copy( | ||||
|                         nullable = it.nullable | ||||
|                     ) | ||||
|                     fun addGetterProperty( | ||||
|                         receiver: KClass<*> | ||||
|                     ) { | ||||
|                         addProperty( | ||||
|                             PropertySpec.builder( | ||||
|                                 it.name, | ||||
|                                 targetType, | ||||
|                             ).apply { | ||||
|                                 addKdoc( | ||||
|                                     """ | ||||
|                                         @return Definition by key "${it.name}" | ||||
|                                     """.trimIndent() | ||||
|                                 ) | ||||
|                                 getter( | ||||
|                                     FunSpec.getterBuilder().apply { | ||||
|                                         addCode( | ||||
|                                             "return " + (if (it.nullable) { | ||||
|                                                 "getOrNull" | ||||
|                                             } else { | ||||
|                                                 "get" | ||||
|                                             }) + "(named(\"${it.name}\"))" | ||||
|                                         ) | ||||
|                                     }.build() | ||||
|                                 ) | ||||
|                                 receiver(receiver) | ||||
|                             }.build() | ||||
|                         ) | ||||
|                     } | ||||
|  | ||||
|                     addGetterProperty(Scope::class) | ||||
|                     addGetterProperty(Koin::class) | ||||
|  | ||||
|                     if (it.generateSingle) { | ||||
|                         addFunction( | ||||
|                             FunSpec.builder("${it.name}Single").apply { | ||||
|                                 addKdoc( | ||||
|                                     """ | ||||
|                                         Will register [definition] with [org.koin.core.module.Module.single] and key "${it.name}" | ||||
|                                     """.trimIndent() | ||||
|                                 ) | ||||
|                                 receiver(Module::class) | ||||
|                                 addParameter( | ||||
|                                     ParameterSpec.builder( | ||||
|                                         "createdAtStart", | ||||
|                                         Boolean::class | ||||
|                                     ).apply { | ||||
|                                         defaultValue("false") | ||||
|                                     }.build() | ||||
|                                 ) | ||||
|                                 addParameter( | ||||
|                                     ParameterSpec.builder( | ||||
|                                         "definition", | ||||
|                                         definitionClassName.parameterizedBy(targetType.copy(nullable = false)) | ||||
|                                     ).build() | ||||
|                                 ) | ||||
|                                 returns(koinDefinitionClassName.parameterizedBy(targetType.copy(nullable = false))) | ||||
|                                 addCode( | ||||
|                                     "return single(named(\"${it.name}\"), createdAtStart = createdAtStart, definition = definition)" | ||||
|                                 ) | ||||
|                             }.build() | ||||
|                         ) | ||||
|                     addCodeForType(targetType, it.name, it.nullable, it.generateSingle, it.generateFactory) | ||||
|                 } | ||||
|  | ||||
|                     if (it.generateFactory) { | ||||
|                         addFunction( | ||||
|                             FunSpec.builder("${it.name}Factory").apply { | ||||
|                                 addKdoc( | ||||
|                                     """ | ||||
|                                         Will register [definition] with [org.koin.core.module.Module.factory] and key "${it.name}" | ||||
|                                     """.trimIndent() | ||||
|                                 ) | ||||
|                                 receiver(Module::class) | ||||
|                                 addParameter( | ||||
|                                     ParameterSpec.builder( | ||||
|                                         "definition", | ||||
|                                         definitionClassName.parameterizedBy(targetType.copy(nullable = false)) | ||||
|                                     ).build() | ||||
|                                 ) | ||||
|                                 returns(koinDefinitionClassName.parameterizedBy(targetType.copy(nullable = false))) | ||||
|                                 addCode( | ||||
|                                     "return factory(named(\"${it.name}\"), definition = definition)" | ||||
|                                 ) | ||||
|                             }.build() | ||||
|                         ) | ||||
|                     } | ||||
|                     addImport("org.koin.core.qualifier", "named") | ||||
|                 ksFile.getAnnotationsByType(GenerateGenericKoinDefinition::class).forEach { | ||||
|                     val targetType = TypeVariableName("T", Any::class) | ||||
|                     addCodeForType(targetType, it.name, it.nullable, it.generateSingle, it.generateFactory) | ||||
|                 } | ||||
|             }.build().let { | ||||
|                 File( | ||||
|   | ||||
| @@ -3,12 +3,15 @@ | ||||
| // ORIGINAL FILE: Test.kt | ||||
| package dev.inmo.micro_utils.koin.generator.test | ||||
|  | ||||
| import kotlin.Any | ||||
| import kotlin.Boolean | ||||
| import kotlin.Deprecated | ||||
| import kotlin.String | ||||
| import org.koin.core.Koin | ||||
| import org.koin.core.definition.Definition | ||||
| import org.koin.core.definition.KoinDefinition | ||||
| import org.koin.core.module.Module | ||||
| import org.koin.core.parameter.ParametersDefinition | ||||
| import org.koin.core.qualifier.named | ||||
| import org.koin.core.scope.Scope | ||||
|  | ||||
| @@ -24,15 +27,98 @@ public val Scope.sampleInfo: Test<String> | ||||
| public val Koin.sampleInfo: Test<String> | ||||
|   get() = get(named("sampleInfo")) | ||||
|  | ||||
| /** | ||||
|  * @return Definition by key "sampleInfo" with [parameters] | ||||
|  */ | ||||
| public inline fun Scope.sampleInfo(noinline parameters: ParametersDefinition): Test<String> = | ||||
|     get(named("sampleInfo"), parameters) | ||||
|  | ||||
| /** | ||||
|  * @return Definition by key "sampleInfo" with [parameters] | ||||
|  */ | ||||
| public inline fun Koin.sampleInfo(noinline parameters: ParametersDefinition): Test<String> = | ||||
|     get(named("sampleInfo"), parameters) | ||||
|  | ||||
| /** | ||||
|  * Will register [definition] with [org.koin.core.module.Module.single] and key "sampleInfo" | ||||
|  */ | ||||
| @Deprecated( | ||||
|   "This definition is old style and should not be used anymore. Use singleSampleInfo instead", | ||||
|   ReplaceWith("singleSampleInfo"), | ||||
| ) | ||||
| public fun Module.sampleInfoSingle(createdAtStart: Boolean = false, | ||||
|     definition: Definition<Test<String>>): KoinDefinition<Test<String>> = | ||||
|     single(named("sampleInfo"), createdAtStart = createdAtStart, definition = definition) | ||||
|  | ||||
| /** | ||||
|  * Will register [definition] with [org.koin.core.module.Module.single] and key "sampleInfo" | ||||
|  */ | ||||
| public fun Module.singleSampleInfo(createdAtStart: Boolean = false, | ||||
|     definition: Definition<Test<String>>): KoinDefinition<Test<String>> = | ||||
|     single(named("sampleInfo"), createdAtStart = createdAtStart, definition = definition) | ||||
|  | ||||
| /** | ||||
|  * Will register [definition] with [org.koin.core.module.Module.factory] and key "sampleInfo" | ||||
|  */ | ||||
| @Deprecated( | ||||
|   "This definition is old style and should not be used anymore. Use factorySampleInfo instead", | ||||
|   ReplaceWith("factorySampleInfo"), | ||||
| ) | ||||
| public fun Module.sampleInfoFactory(definition: Definition<Test<String>>): | ||||
|     KoinDefinition<Test<String>> = factory(named("sampleInfo"), definition = definition) | ||||
|  | ||||
| /** | ||||
|  * Will register [definition] with [org.koin.core.module.Module.factory] and key "sampleInfo" | ||||
|  */ | ||||
| public fun Module.factorySampleInfo(definition: Definition<Test<String>>): | ||||
|     KoinDefinition<Test<String>> = factory(named("sampleInfo"), definition = definition) | ||||
|  | ||||
| /** | ||||
|  * @return Definition by key "test" with [parameters] | ||||
|  */ | ||||
| public inline fun <reified T : Any> Scope.test(noinline parameters: ParametersDefinition? = null): T | ||||
|     = get(named("test"), parameters) | ||||
|  | ||||
| /** | ||||
|  * @return Definition by key "test" with [parameters] | ||||
|  */ | ||||
| public inline fun <reified T : Any> Koin.test(noinline parameters: ParametersDefinition? = null): T | ||||
|     = get(named("test"), parameters) | ||||
|  | ||||
| /** | ||||
|  * Will register [definition] with [org.koin.core.module.Module.single] and key "test" | ||||
|  */ | ||||
| public inline fun <reified T : Any> Module.singleTest(createdAtStart: Boolean = false, noinline | ||||
|     definition: Definition<T>): KoinDefinition<T> = single(named("test"), createdAtStart = | ||||
|     createdAtStart, definition = definition) | ||||
|  | ||||
| /** | ||||
|  * Will register [definition] with [org.koin.core.module.Module.factory] and key "test" | ||||
|  */ | ||||
| public inline fun <reified T : Any> Module.factoryTest(noinline definition: Definition<T>): | ||||
|     KoinDefinition<T> = factory(named("test"), definition = definition) | ||||
|  | ||||
| /** | ||||
|  * @return Definition by key "testNullable" with [parameters] | ||||
|  */ | ||||
| public inline fun <reified T : Any> Scope.testNullable(noinline parameters: ParametersDefinition? = | ||||
|     null): T? = getOrNull(named("testNullable"), parameters) | ||||
|  | ||||
| /** | ||||
|  * @return Definition by key "testNullable" with [parameters] | ||||
|  */ | ||||
| public inline fun <reified T : Any> Koin.testNullable(noinline parameters: ParametersDefinition? = | ||||
|     null): T? = getOrNull(named("testNullable"), parameters) | ||||
|  | ||||
| /** | ||||
|  * Will register [definition] with [org.koin.core.module.Module.single] and key "testNullable" | ||||
|  */ | ||||
| public inline fun <reified T : Any> Module.singleTestNullable(createdAtStart: Boolean = false, | ||||
|     noinline definition: Definition<T>): KoinDefinition<T> = single(named("testNullable"), | ||||
|     createdAtStart = createdAtStart, definition = definition) | ||||
|  | ||||
| /** | ||||
|  * Will register [definition] with [org.koin.core.module.Module.factory] and key "testNullable" | ||||
|  */ | ||||
| public inline fun <reified T : Any> Module.factoryTestNullable(noinline definition: Definition<T>): | ||||
|     KoinDefinition<T> = factory(named("testNullable"), definition = definition) | ||||
|   | ||||
| @@ -1,6 +1,9 @@ | ||||
| @file:GenerateKoinDefinition("sampleInfo", Test::class, String::class, nullable = false) | ||||
| @file:GenerateGenericKoinDefinition("test", nullable = false) | ||||
| @file:GenerateGenericKoinDefinition("testNullable", nullable = true) | ||||
| package dev.inmo.micro_utils.koin.generator.test | ||||
|  | ||||
| import dev.inmo.micro_utils.koin.annotations.GenerateGenericKoinDefinition | ||||
| import dev.inmo.micro_utils.koin.annotations.GenerateKoinDefinition | ||||
| import org.koin.core.Koin | ||||
|  | ||||
|   | ||||
							
								
								
									
										40
									
								
								koin/src/commonMain/kotlin/GetWithDefinition.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								koin/src/commonMain/kotlin/GetWithDefinition.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| package dev.inmo.micro_utils.koin | ||||
|  | ||||
| import org.koin.core.Koin | ||||
| import org.koin.core.definition.BeanDefinition | ||||
| import org.koin.core.definition.KoinDefinition | ||||
| import org.koin.core.instance.InstanceFactory | ||||
| import org.koin.core.parameter.ParametersDefinition | ||||
| import org.koin.core.scope.Scope | ||||
|  | ||||
| fun <T> Koin.get(definition: BeanDefinition<T>, parameters: ParametersDefinition? = null): T = get( | ||||
|     definition.primaryType, | ||||
|     definition.qualifier, | ||||
|     parameters | ||||
| ) | ||||
|  | ||||
| fun <T> Koin.get(definition: InstanceFactory<T>, parameters: ParametersDefinition? = null): T = get( | ||||
|     definition.beanDefinition, | ||||
|     parameters | ||||
| ) | ||||
|  | ||||
| fun <T> Koin.get(definition: KoinDefinition<T>, parameters: ParametersDefinition? = null): T = get( | ||||
|     definition.factory, | ||||
|     parameters | ||||
| ) | ||||
|  | ||||
| fun <T> Scope.get(definition: BeanDefinition<T>, parameters: ParametersDefinition? = null): T = get( | ||||
|     definition.primaryType, | ||||
|     definition.qualifier, | ||||
|     parameters | ||||
| ) | ||||
|  | ||||
| fun <T> Scope.get(definition: InstanceFactory<T>, parameters: ParametersDefinition? = null): T = get( | ||||
|     definition.beanDefinition, | ||||
|     parameters | ||||
| ) | ||||
|  | ||||
| fun <T> Scope.get(definition: KoinDefinition<T>, parameters: ParametersDefinition? = null): T = get( | ||||
|     definition.factory, | ||||
|     parameters | ||||
| ) | ||||
| @@ -0,0 +1,26 @@ | ||||
| package dev.inmo.micro_utils.koin.annotations | ||||
|  | ||||
| import kotlin.reflect.KClass | ||||
|  | ||||
| /** | ||||
|  * Use this annotation to mark files near to which generator should place generated extensions for koin [org.koin.core.scope.Scope] | ||||
|  * and [org.koin.core.Koin] | ||||
|  * | ||||
|  * @param name Name for definitions. This name will be available as extension for [org.koin.core.scope.Scope] and [org.koin.core.Koin] | ||||
|  * @param type Type of extensions. It is base star-typed class | ||||
|  * @param typeArgs Generic types for [type]. For example, if [type] == `Something::class` and [typeArgs] == `G1::class, | ||||
|  * G2::class`, the result type will be `Something<G1, G2>` | ||||
|  * @param nullable In case when true, extension will not throw error when definition has not been registered in koin | ||||
|  * @param generateSingle Generate definition factory with [org.koin.core.module.Module.single]. You will be able to use | ||||
|  * the extension [org.koin.core.module.Module].[name]Single(createdAtStart/* default false */) { /* your definition */ } | ||||
|  * @param generateFactory Generate definition factory with [org.koin.core.module.Module.factory]. You will be able to use | ||||
|  * the extension [org.koin.core.module.Module].[name]Factory { /* your definition */ } | ||||
|  */ | ||||
| @Target(AnnotationTarget.FILE) | ||||
| @Repeatable | ||||
| annotation class GenerateGenericKoinDefinition( | ||||
|     val name: String, | ||||
|     val nullable: Boolean = true, | ||||
|     val generateSingle: Boolean = true, | ||||
|     val generateFactory: Boolean = true | ||||
| ) | ||||
| @@ -1,6 +1,6 @@ | ||||
| package dev.inmo.micro_utils.ktor.common | ||||
|  | ||||
| import com.soywiz.klock.DateTime | ||||
| import korlibs.time.DateTime | ||||
|  | ||||
| typealias FromToDateTime = Pair<DateTime?, DateTime?> | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| package dev.inmo.micro_utils.ktor.server | ||||
|  | ||||
| import com.soywiz.klock.DateTime | ||||
| import korlibs.time.DateTime | ||||
| import dev.inmo.micro_utils.ktor.common.FromToDateTime | ||||
| import io.ktor.http.Parameters | ||||
|  | ||||
|   | ||||
| @@ -38,7 +38,7 @@ fun <Key, Value> ReadKeyValueRepo<Key, Value>.cached( | ||||
| ) = ReadKeyValueCacheRepo(this, kvCache) | ||||
|  | ||||
| open class KeyValueCacheRepo<Key,Value>( | ||||
|     parentRepo: KeyValueRepo<Key, Value>, | ||||
|     override val parentRepo: KeyValueRepo<Key, Value>, | ||||
|     kvCache: KVCache<Key, Value>, | ||||
|     scope: CoroutineScope = CoroutineScope(Dispatchers.Default) | ||||
| ) : ReadKeyValueCacheRepo<Key,Value>(parentRepo, kvCache), KeyValueRepo<Key,Value>, WriteKeyValueRepo<Key, Value> by parentRepo, CommonCacheRepo { | ||||
| @@ -46,6 +46,11 @@ open class KeyValueCacheRepo<Key,Value>( | ||||
|     protected val onRemoveJob = parentRepo.onValueRemoved.onEach { kvCache.unset(it) }.launchIn(scope) | ||||
|  | ||||
|     override suspend fun invalidate() = kvCache.clear() | ||||
|  | ||||
|     override suspend fun clear() { | ||||
|         parentRepo.clear() | ||||
|         kvCache.clear() | ||||
|     } | ||||
| } | ||||
|  | ||||
| fun <Key, Value> KeyValueRepo<Key, Value>.cached( | ||||
|   | ||||
| @@ -21,6 +21,12 @@ open class SimpleFullKVCache<K, V>( | ||||
|             kvParent.unset(toUnset) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override suspend fun clear() { | ||||
|         syncMutex.withLock { | ||||
|             kvParent.clear() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| inline fun <K, V> FullKVCache( | ||||
|   | ||||
| @@ -37,6 +37,10 @@ open class SimpleKVCache<K, V>( | ||||
|     override suspend fun unset(toUnset: List<K>) { | ||||
|         syncMutex.withLock { makeUnset(toUnset) } | ||||
|     } | ||||
|  | ||||
|     override suspend fun clear() { | ||||
|         syncMutex.withLock { makeUnset(cacheQueue) } | ||||
|     } | ||||
| } | ||||
|  | ||||
| inline fun <K, V> KVCache( | ||||
|   | ||||
| @@ -39,4 +39,9 @@ open class AutoRecacheKeyValueRepo<Id, RegisteredObject>( | ||||
|     ).also { | ||||
|         kvCache.unsetWithValues(toUnset) | ||||
|     } | ||||
|  | ||||
|     override suspend fun clear() { | ||||
|         originalRepo.clear() | ||||
|         kvCache.clear() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package dev.inmo.micro_utils.repos.cache.full | ||||
|  | ||||
| import dev.inmo.micro_utils.common.* | ||||
| import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions | ||||
| import dev.inmo.micro_utils.pagination.Pagination | ||||
| import dev.inmo.micro_utils.pagination.PaginationResult | ||||
| import dev.inmo.micro_utils.repos.* | ||||
| @@ -84,6 +85,7 @@ open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>( | ||||
|     override val parentRepo: CRUDRepo<ObjectType, IdType, InputValueType>, | ||||
|     kvCache: FullKVCache<IdType, ObjectType>, | ||||
|     scope: CoroutineScope = CoroutineScope(Dispatchers.Default), | ||||
|     skipStartInvalidate: Boolean = false, | ||||
|     idGetter: (ObjectType) -> IdType | ||||
| ) : FullReadCRUDCacheRepo<ObjectType, IdType>( | ||||
|     parentRepo, | ||||
| @@ -97,6 +99,12 @@ open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>( | ||||
|         idGetter | ||||
|     ), | ||||
|     CRUDRepo<ObjectType, IdType, InputValueType> { | ||||
|     init { | ||||
|         if (!skipStartInvalidate) { | ||||
|             scope.launchSafelyWithoutExceptions { invalidate() } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override suspend fun invalidate() { | ||||
|         actualizeAll() | ||||
|     } | ||||
| @@ -105,12 +113,14 @@ open class FullCRUDCacheRepo<ObjectType, IdType, InputValueType>( | ||||
| fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.fullyCached( | ||||
|     kvCache: FullKVCache<IdType, ObjectType> = FullKVCache(), | ||||
|     scope: CoroutineScope = CoroutineScope(Dispatchers.Default), | ||||
|     skipStartInvalidate: Boolean = false, | ||||
|     idGetter: (ObjectType) -> IdType | ||||
| ) = FullCRUDCacheRepo(this, kvCache, scope, idGetter) | ||||
| ) = FullCRUDCacheRepo(this, kvCache, scope, skipStartInvalidate, idGetter) | ||||
|  | ||||
| @Deprecated("Renamed", ReplaceWith("this.fullyCached(kvCache, scope, idGetter)", "dev.inmo.micro_utils.repos.cache.full.fullyCached")) | ||||
| fun <ObjectType, IdType, InputType> CRUDRepo<ObjectType, IdType, InputType>.cached( | ||||
|     kvCache: FullKVCache<IdType, ObjectType>, | ||||
|     scope: CoroutineScope = CoroutineScope(Dispatchers.Default), | ||||
|     skipStartInvalidate: Boolean = false, | ||||
|     idGetter: (ObjectType) -> IdType | ||||
| ) = fullyCached(kvCache, scope, idGetter) | ||||
| ) = fullyCached(kvCache, scope, skipStartInvalidate, idGetter) | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package dev.inmo.micro_utils.repos.cache.full | ||||
|  | ||||
| import dev.inmo.micro_utils.common.* | ||||
| import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions | ||||
| import dev.inmo.micro_utils.pagination.Pagination | ||||
| import dev.inmo.micro_utils.pagination.PaginationResult | ||||
| import dev.inmo.micro_utils.repos.* | ||||
| @@ -106,15 +107,30 @@ fun <Key, Value> WriteKeyValueRepo<Key, Value>.caching( | ||||
| open class FullKeyValueCacheRepo<Key,Value>( | ||||
|     protected open val parentRepo: KeyValueRepo<Key, Value>, | ||||
|     kvCache: FullKVCache<Key, Value>, | ||||
|     scope: CoroutineScope = CoroutineScope(Dispatchers.Default) | ||||
|     scope: CoroutineScope = CoroutineScope(Dispatchers.Default), | ||||
|     skipStartInvalidate: Boolean = false | ||||
| ) : FullWriteKeyValueCacheRepo<Key,Value>(parentRepo, kvCache, scope), | ||||
|     KeyValueRepo<Key,Value>, | ||||
|     ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo(parentRepo, kvCache) { | ||||
|     ReadKeyValueRepo<Key, Value> by FullReadKeyValueCacheRepo( | ||||
|         parentRepo, | ||||
|         kvCache | ||||
| ) { | ||||
|     init { | ||||
|         if (!skipStartInvalidate) { | ||||
|             scope.launchSafelyWithoutExceptions { invalidate() } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override suspend fun unsetWithValues(toUnset: List<Value>) = parentRepo.unsetWithValues(toUnset) | ||||
|  | ||||
|     override suspend fun invalidate() { | ||||
|         kvCache.actualizeAll(parentRepo) | ||||
|     } | ||||
|  | ||||
|     override suspend fun clear() { | ||||
|         parentRepo.clear() | ||||
|         kvCache.clear() | ||||
|     } | ||||
| } | ||||
|  | ||||
| fun <Key, Value> KeyValueRepo<Key, Value>.fullyCached( | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package dev.inmo.micro_utils.repos.cache.full | ||||
|  | ||||
| import dev.inmo.micro_utils.common.* | ||||
| import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions | ||||
| import dev.inmo.micro_utils.pagination.* | ||||
| import dev.inmo.micro_utils.pagination.utils.* | ||||
| import dev.inmo.micro_utils.repos.* | ||||
| @@ -142,10 +143,17 @@ fun <Key, Value> WriteKeyValuesRepo<Key, Value>.caching( | ||||
| open class FullKeyValuesCacheRepo<Key,Value>( | ||||
|     protected open val parentRepo: KeyValuesRepo<Key, Value>, | ||||
|     kvCache: FullKVCache<Key, List<Value>>, | ||||
|     scope: CoroutineScope = CoroutineScope(Dispatchers.Default) | ||||
|     scope: CoroutineScope = CoroutineScope(Dispatchers.Default), | ||||
|     skipStartInvalidate: Boolean = false | ||||
| ) : FullWriteKeyValuesCacheRepo<Key, Value>(parentRepo, kvCache, scope), | ||||
|     KeyValuesRepo<Key, Value>, | ||||
|     ReadKeyValuesRepo<Key, Value> by FullReadKeyValuesCacheRepo(parentRepo, kvCache) { | ||||
|     init { | ||||
|         if (!skipStartInvalidate) { | ||||
|             scope.launchSafelyWithoutExceptions { invalidate() } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override suspend fun clearWithValue(v: Value) { | ||||
|         doAllWithCurrentPaging { | ||||
|             keys(v, it).also { | ||||
|   | ||||
| @@ -127,7 +127,11 @@ open class MapperKeyValueRepo<FromKey, FromValue, ToKey, ToValue>( | ||||
| ) : KeyValueRepo<FromKey, FromValue>, | ||||
|     MapperRepo<FromKey, FromValue, ToKey, ToValue> by mapper, | ||||
|     ReadKeyValueRepo<FromKey, FromValue> by MapperReadKeyValueRepo(to, mapper), | ||||
|     WriteKeyValueRepo<FromKey, FromValue> by MapperWriteKeyValueRepo(to, mapper) | ||||
|     WriteKeyValueRepo<FromKey, FromValue> by MapperWriteKeyValueRepo(to, mapper) { | ||||
|     override suspend fun clear() { | ||||
|         to.clear() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Suppress("NOTHING_TO_INLINE") | ||||
| inline fun <FromKey, FromValue, ToKey, ToValue> KeyValueRepo<ToKey, ToValue>.withMapper( | ||||
|   | ||||
| @@ -202,9 +202,14 @@ class FileWriteKeyValueRepo( | ||||
| @Warning("Files watching will not correctly works on Android Platform with version of API lower than API 26") | ||||
| @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") | ||||
| class FileKeyValueRepo( | ||||
|     folder: File, | ||||
|     private val folder: File, | ||||
|     filesChangedProcessingScope: CoroutineScope? = null | ||||
| ) : KeyValueRepo<String, File>, | ||||
|     WriteKeyValueRepo<String, File> by FileWriteKeyValueRepo(folder, filesChangedProcessingScope), | ||||
|     ReadKeyValueRepo<String, File> by FileReadKeyValueRepo(folder) { | ||||
|     override suspend fun clear() { | ||||
|         withContext(Dispatchers.IO) { | ||||
|             folder.listFiles() ?.forEach { runCatching { it.deleteRecursively() } } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import dev.inmo.micro_utils.pagination.* | ||||
| import dev.inmo.micro_utils.pagination.utils.paginate | ||||
| import dev.inmo.micro_utils.pagination.utils.reverse | ||||
| import dev.inmo.micro_utils.repos.KeyValueRepo | ||||
| import dev.inmo.micro_utils.repos.pagination.maxPagePagination | ||||
| import kotlinx.coroutines.flow.* | ||||
|  | ||||
| private val cache = HashMap<String, KeyValueStore<*>>() | ||||
| @@ -159,6 +160,24 @@ class KeyValueStore<T : Any> internal constructor ( | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override suspend fun clear() { | ||||
|         val keys = mutableSetOf<String>() | ||||
|         doWithPagination(maxPagePagination()) { | ||||
|             keys(it).also { | ||||
|                 keys.addAll(it.results) | ||||
|             }.nextPageIfNotEmpty() | ||||
|         } | ||||
|         val success = sharedPreferences.edit().apply { | ||||
|             clear() | ||||
|         }.commit() | ||||
|  | ||||
|         if (success) { | ||||
|             keys.forEach { | ||||
|                 _onValueRemovedFlow.emit(it) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         operator fun <T : Any> invoke( | ||||
|             context: Context, | ||||
|   | ||||
| @@ -73,4 +73,18 @@ abstract class AbstractExposedKeyValueRepo<Key, Value>( | ||||
|             _onValueRemoved.emit(it) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override suspend fun clear() { | ||||
|         transaction(database) { | ||||
|             val keys = selectAll().map { it.asKey } | ||||
|  | ||||
|             deleteAll() | ||||
|  | ||||
|             keys | ||||
|         }.also { | ||||
|             it.forEach { | ||||
|                 _onValueRemoved.emit(it) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.* | ||||
| import org.jetbrains.exposed.sql.* | ||||
| import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq | ||||
| import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList | ||||
| import org.jetbrains.exposed.sql.SqlExpressionBuilder.inSubQuery | ||||
| import org.jetbrains.exposed.sql.transactions.transaction | ||||
|  | ||||
| open class ExposedKeyValueRepo<Key, Value>( | ||||
| @@ -72,4 +73,18 @@ open class ExposedKeyValueRepo<Key, Value>( | ||||
|             _onValueRemoved.emit(it) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override suspend fun clear() { | ||||
|         transaction(database) { | ||||
|             val keys = selectAll().map { it.asKey } | ||||
|  | ||||
|             deleteAll() | ||||
|  | ||||
|             keys | ||||
|         }.also { | ||||
|             it.forEach { | ||||
|                 _onValueRemoved.emit(it) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -14,3 +14,8 @@ dependencies { | ||||
|     api libs.kotlin.poet | ||||
|     api libs.ksp | ||||
| } | ||||
|  | ||||
| java { | ||||
|     sourceCompatibility = JavaVersion.VERSION_1_8 | ||||
|     targetCompatibility = JavaVersion.VERSION_1_8 | ||||
| } | ||||
|   | ||||
| @@ -100,7 +100,11 @@ class Processor( | ||||
|                         primaryConstructor( | ||||
|                             FunSpec.constructorBuilder().apply { | ||||
|                                 ksClassProperties.forEach { | ||||
|                                     addParameter(it.simpleName.getShortName(), it.typeName) | ||||
|                                     addParameter( | ||||
|                                         ParameterSpec.builder(it.simpleName.getShortName(), it.typeName).apply { | ||||
|                                             annotations += it.annotations.map { it.toAnnotationSpec() } | ||||
|                                         }.build() | ||||
|                                     ) | ||||
|                                     typeBuilder.addProperty( | ||||
|                                         PropertySpec.builder(it.simpleName.getShortName(), it.typeName, KModifier.OVERRIDE).apply { | ||||
|                                             initializer(it.simpleName.getShortName()) | ||||
|   | ||||
| @@ -11,18 +11,20 @@ import kotlinx.serialization.Serializable | ||||
| @Serializable | ||||
| @SerialName(value = "NewTest") | ||||
| public data class NewTest( | ||||
|   public override val property1: String, | ||||
|   public override val property2: Int, | ||||
|   public override val parent: ParentTypeId?, | ||||
|   override val property1: String, | ||||
|   override val property2: Int, | ||||
|   @Serializable | ||||
|   override val parent: ParentTypeId?, | ||||
| ) : Test | ||||
|  | ||||
| @Serializable | ||||
| @SerialName(value = "RegisteredTest") | ||||
| public data class RegisteredTest( | ||||
|   public override val id: TestId, | ||||
|   public override val property1: String, | ||||
|   public override val property2: Int, | ||||
|   public override val parent: ParentTypeId?, | ||||
|   override val id: TestId, | ||||
|   override val property1: String, | ||||
|   override val property2: Int, | ||||
|   @Serializable | ||||
|   override val parent: ParentTypeId?, | ||||
| ) : Test, IRegisteredTest | ||||
|  | ||||
| public fun Test.asNew(): NewTest = NewTest(property1, property2, parent) | ||||
|   | ||||
| @@ -17,6 +17,7 @@ typealias ParentTypeId = TestId | ||||
| sealed interface Test { | ||||
|     val property1: String | ||||
|     val property2: Int | ||||
|     @Serializable | ||||
|     val parent: ParentTypeId? | ||||
|  | ||||
|     @GenerateCRUDModelExcludeOverride | ||||
|   | ||||
| @@ -94,6 +94,10 @@ class MapKeyValueRepo<Key, Value>( | ||||
|     private val map: MutableMap<Key, Value> = mutableMapOf() | ||||
| ) : KeyValueRepo<Key, Value>, | ||||
|     ReadKeyValueRepo<Key, Value> by ReadMapKeyValueRepo(map), | ||||
|     WriteKeyValueRepo<Key, Value> by WriteMapKeyValueRepo(map) | ||||
|     WriteKeyValueRepo<Key, Value> by WriteMapKeyValueRepo(map) { | ||||
|     override suspend fun clear() { | ||||
|         map.clear() | ||||
|     } | ||||
| } | ||||
|  | ||||
| fun <K, V> MutableMap<K, V>.asKeyValueRepo(): KeyValueRepo<K, V> = MapKeyValueRepo(this) | ||||
|   | ||||
| @@ -9,10 +9,7 @@ import dev.inmo.micro_utils.koin.annotations.GenerateKoinDefinition | ||||
| import dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin.setupDI | ||||
| import dev.inmo.micro_utils.startup.launcher.StartLauncherPlugin.startPlugin | ||||
| import dev.inmo.micro_utils.startup.plugin.StartPlugin | ||||
| import kotlinx.coroutines.CoroutineScope | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| import kotlinx.coroutines.joinAll | ||||
| import kotlinx.coroutines.launch | ||||
| import kotlinx.coroutines.* | ||||
| import kotlinx.serialization.SerialFormat | ||||
| import kotlinx.serialization.StringFormat | ||||
| import kotlinx.serialization.json.Json | ||||
| @@ -116,12 +113,16 @@ object StartLauncherPlugin : StartPlugin { | ||||
|     /** | ||||
|      * Will create [KoinApplication], init, load modules using [StartLauncherPlugin] and start plugins using the same base | ||||
|      * plugin. It is basic [start] method which accepts both [config] and [rawConfig] which suppose to be the same or | ||||
|      * at least [rawConfig] must contain serialized variant of [config] | ||||
|      * at least [rawConfig] must contain serialized variant of [config]. | ||||
|      * | ||||
|      * Koin part will be started in-place. This means, that after ending of this method call you will be able to | ||||
|      * take any declared dependency from koin | ||||
|      * | ||||
|      * @param rawConfig It is expected that this [JsonObject] will contain serialized [Config] ([StartLauncherPlugin] will | ||||
|      * deserialize it in its [StartLauncherPlugin.setupDI] | ||||
|      * @return [KoinApplication] of current start and [Job] which can be used to call [CoroutineScope.join] | ||||
|      */ | ||||
|     suspend fun start(config: Config, rawConfig: JsonObject) { | ||||
|     fun startAsync(config: Config, rawConfig: JsonObject): Pair<KoinApplication, Job> { | ||||
|  | ||||
|         logger.i("Start initialization") | ||||
|         val koinApp = KoinApplication.init() | ||||
| @@ -133,8 +134,44 @@ object StartLauncherPlugin : StartPlugin { | ||||
|         logger.i("Modules loaded") | ||||
|         startKoin(koinApp) | ||||
|         logger.i("Koin started") | ||||
|         val launchJob = koinApp.koin.get<CoroutineScope>().launch { | ||||
|             startPlugin(koinApp.koin) | ||||
|         logger.i("App has been setup") | ||||
|             logger.i("App has been started") | ||||
|         } | ||||
|  | ||||
|         return koinApp to launchJob | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Will create [KoinApplication], init, load modules using [StartLauncherPlugin] and start plugins using the same base | ||||
|      * plugin. It is basic [start] method which accepts both [config] and [rawConfig] which suppose to be the same or | ||||
|      * at least [rawConfig] must contain serialized variant of [config] | ||||
|      * | ||||
|      * @param rawConfig It is expected that this [JsonObject] will contain serialized [Config] ([StartLauncherPlugin] will | ||||
|      * deserialize it in its [StartLauncherPlugin.setupDI] | ||||
|      * @return [KoinApplication] of current launch | ||||
|      */ | ||||
|     suspend fun start(config: Config, rawConfig: JsonObject): KoinApplication { | ||||
|  | ||||
|         val (koinApp, job) = startAsync(config, rawConfig) | ||||
|  | ||||
|         job.join() | ||||
|  | ||||
|         return koinApp | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Call [start] with deserialized [Config] as config and [rawConfig] as is | ||||
|      * | ||||
|      * Koin part will be started in-place. This means, that after ending of this method call you will be able to | ||||
|      * take any declared dependency from koin | ||||
|      * | ||||
|      * @param rawConfig It is expected that this [JsonObject] will contain serialized [Config] | ||||
|      * @return [KoinApplication] of current launch and [Job] of starting launch | ||||
|      */ | ||||
|     fun startAsync(rawConfig: JsonObject): Pair<KoinApplication, Job> { | ||||
|  | ||||
|         return startAsync(defaultJson.decodeFromJsonElement(Config.serializer(), rawConfig), rawConfig) | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -143,9 +180,30 @@ object StartLauncherPlugin : StartPlugin { | ||||
|      * | ||||
|      * @param rawConfig It is expected that this [JsonObject] will contain serialized [Config] | ||||
|      */ | ||||
|     suspend fun start(rawConfig: JsonObject) { | ||||
|     suspend fun start(rawConfig: JsonObject): KoinApplication { | ||||
|  | ||||
|         start(defaultJson.decodeFromJsonElement(Config.serializer(), rawConfig), rawConfig) | ||||
|         val (koinApp, job) = startAsync(rawConfig) | ||||
|  | ||||
|         job.join() | ||||
|  | ||||
|         return koinApp | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Call [start] with deserialized [Config] as is and serialize it to [JsonObject] to pass as the first parameter | ||||
|      * to the basic [start] method | ||||
|      * | ||||
|      * Koin part will be started in-place. This means, that after ending of this method call you will be able to | ||||
|      * take any declared dependency from koin | ||||
|      * | ||||
|      * @param config Will be converted to [JsonObject] as raw config. That means that all plugins from [config] will | ||||
|      * receive serialized version of [config] in [StartPlugin.setupDI] method | ||||
|      * @return [KoinApplication] of current launch and [Job] of starting launch | ||||
|      */ | ||||
|     fun startAsync(config: Config): Pair<KoinApplication, Job> { | ||||
|  | ||||
|         return startAsync(config, defaultJson.encodeToJsonElement(Config.serializer(), config).jsonObject) | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -156,9 +214,13 @@ object StartLauncherPlugin : StartPlugin { | ||||
|      * @param config Will be converted to [JsonObject] as raw config. That means that all plugins from [config] will | ||||
|      * receive serialized version of [config] in [StartPlugin.setupDI] method | ||||
|      */ | ||||
|     suspend fun start(config: Config) { | ||||
|     suspend fun start(config: Config): KoinApplication { | ||||
|  | ||||
|         start(config, defaultJson.encodeToJsonElement(Config.serializer(), config).jsonObject) | ||||
|         val (koinApp, job) = startAsync(config) | ||||
|  | ||||
|         job.join() | ||||
|  | ||||
|         return koinApp | ||||
|  | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										11
									
								
								versions_plugin_setup.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								versions_plugin_setup.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| def isNonStable = { String version -> | ||||
|     def stableKeyword = ['RELEASE', 'FINAL', 'GA'].any { it -> version.toUpperCase().contains(it) } | ||||
|     def regex = /^[0-9,.v-]+(-r)?$/ | ||||
|     return !stableKeyword && !(version ==~ regex) | ||||
| } | ||||
|  | ||||
| tasks.named("dependencyUpdates").configure { | ||||
|     rejectVersionIf { | ||||
|         isNonStable(it.candidate.version) | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user