diff --git a/LightningServer.podspec b/LightningServer.podspec deleted file mode 100644 index 9fd1ced7..00000000 --- a/LightningServer.podspec +++ /dev/null @@ -1,22 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'LightningServer' - s.version = '0.9.5' - s.summary = 'LightningServer' - - s.description = <<-DESC - Helpers for connecting to a Ktor server - DESC - - s.homepage = 'https://github.com/lightningkite/lightning-server' - # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' - s.license = { :type => 'MIT', :file => 'LICENSE' } - s.author = { 'Joseph' => 'joseph@lightningkite.com' } - s.source = { :git => 'https://github.com/lightningkite/lightning-server.git', :tag => s.version.to_s } - # s.social_media_url = 'https://twitter.com/' - - s.ios.deployment_target = '11.0' - - s.source_files = 'ios/lightningserver/Classes/**/*' - s.dependency 'RxSwiftPlus/Http' - s.dependency 'KhrysalisRuntime' -end diff --git a/demo/src/main/kotlin/AwsHandler.kt b/demo/src/main/kotlin/AwsHandler.kt index 4255f6d2..845d395c 100644 --- a/demo/src/main/kotlin/AwsHandler.kt +++ b/demo/src/main/kotlin/AwsHandler.kt @@ -16,7 +16,7 @@ class AwsHandler : AwsAdapter() { CloudwatchMetrics Server preventLambdaTimeoutReuse = true - loadSettings(AwsHandler::class.java) + loadSettings() } } diff --git a/processor/bin/main/com/lightningkite/lightningdb/AnnotationProcessor.kt b/processor/bin/main/com/lightningkite/lightningdb/AnnotationProcessor.kt index 2f26405a..77b091f6 100644 --- a/processor/bin/main/com/lightningkite/lightningdb/AnnotationProcessor.kt +++ b/processor/bin/main/com/lightningkite/lightningdb/AnnotationProcessor.kt @@ -5,7 +5,6 @@ import com.google.devtools.ksp.processing.* import com.google.devtools.ksp.symbol.* lateinit var comparable: KSClassDeclaration -var khrysalisUsed = false class TableGenerator( val codeGenerator: CodeGenerator, @@ -56,13 +55,7 @@ class TableGenerator( ).bufferedWriter().use { out -> with(TabAppendable(out)) { - if(khrysalisUsed) { - appendLine("@file:SharedCode") - } appendLine("package ${ksName}") - if(khrysalisUsed) { - appendLine("import com.lightningkite.khrysalis.*") - } appendLine("fun prepareModels() {") tab { ksClassDeclarations diff --git a/processor/bin/main/com/lightningkite/lightningdb/MongoFields.kt b/processor/bin/main/com/lightningkite/lightningdb/MongoFields.kt index 9efbe458..34d0ed6e 100644 --- a/processor/bin/main/com/lightningkite/lightningdb/MongoFields.kt +++ b/processor/bin/main/com/lightningkite/lightningdb/MongoFields.kt @@ -42,7 +42,6 @@ data class MongoFields( } else -> { try { - if(it.shortName.asString() == "SharedCode") khrysalisUsed = true appendLine( "@file:${it.shortName.asString()}(${ it.arguments.joinToString(", ") { diff --git a/processor/src/main/kotlin/com/lightningkite/lightningdb/AnnotationProcessor.kt b/processor/src/main/kotlin/com/lightningkite/lightningdb/AnnotationProcessor.kt index 6df04140..3598a170 100644 --- a/processor/src/main/kotlin/com/lightningkite/lightningdb/AnnotationProcessor.kt +++ b/processor/src/main/kotlin/com/lightningkite/lightningdb/AnnotationProcessor.kt @@ -8,12 +8,11 @@ import java.io.File import java.util.UUID lateinit var comparable: KSClassDeclaration -var khrysalisUsed = false class TableGenerator( val codeGenerator: CodeGenerator, val logger: KSPLogger, -) : CommonSymbolProcessor2(codeGenerator, "lightningdb", 1) { +) : CommonSymbolProcessor2(codeGenerator, "lightningdb", 2) { override fun interestedIn(resolver: Resolver): Set { return resolver.getAllFiles() .filter { @@ -66,14 +65,7 @@ class TableGenerator( fileName = "init" ).use { out -> with(TabAppendable(out)) { - - if(khrysalisUsed) { - appendLine("@file:SharedCode") - } if(ksName.isNotEmpty()) appendLine("package ${ksName}") - if(khrysalisUsed) { - appendLine("import com.lightningkite.khrysalis.*") - } appendLine("fun prepareModels() {") tab { ksClassDeclarations diff --git a/processor/src/main/kotlin/com/lightningkite/lightningdb/CommonSymbolProcessor2.kt b/processor/src/main/kotlin/com/lightningkite/lightningdb/CommonSymbolProcessor2.kt index f835d14c..a397c753 100644 --- a/processor/src/main/kotlin/com/lightningkite/lightningdb/CommonSymbolProcessor2.kt +++ b/processor/src/main/kotlin/com/lightningkite/lightningdb/CommonSymbolProcessor2.kt @@ -29,7 +29,7 @@ abstract class CommonSymbolProcessor2( val interestedIn = interestedIn(resolver) - val stub = myCodeGenerator.createNewFile( + myCodeGenerator.createNewFile( Dependencies.ALL_FILES, fileName = "$myId", extensionName = "txt", @@ -42,7 +42,7 @@ abstract class CommonSymbolProcessor2( val projectFolder = generateSequence(outSample) { it.parentFile!! } .first { it.name == "build" } .parentFile!! - val common = interestedIn.any { it.filePath?.contains("/src/common", true) == true } + val common = interestedIn.any { it.filePath.contains("/src/common", true) } val flavor = outSample.path.split(File.separatorChar) .dropWhile { it != "ksp" } .drop(2) @@ -61,7 +61,7 @@ abstract class CommonSymbolProcessor2( lockFile = outFolder.resolve("$myId.lock"), destinationFolder = outFolder.resolve(myId).also { it.mkdirs() }, action = { - fileCreator = label@{ dependencies, packageName, fileName, extensionName -> + fileCreator = label@{ _, packageName, fileName, extensionName -> val packagePath = packageName.split('.').filter { it.isNotBlank() }.joinToString("") { "$it/" } this.file("${packagePath}$fileName.$extensionName") } diff --git a/processor/src/main/kotlin/com/lightningkite/lightningdb/MongoFields.kt b/processor/src/main/kotlin/com/lightningkite/lightningdb/MongoFields.kt index ee0646ec..d902dca5 100644 --- a/processor/src/main/kotlin/com/lightningkite/lightningdb/MongoFields.kt +++ b/processor/src/main/kotlin/com/lightningkite/lightningdb/MongoFields.kt @@ -33,7 +33,6 @@ data class MongoFields( } else -> { try { - if(it.shortName.asString() == "SharedCode") return@forEach appendLine( "@file:${it.shortName.asString()}(${ it.arguments.joinToString(", ") { @@ -50,7 +49,8 @@ data class MongoFields( } } } - appendLine("@file:OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class)") + appendLine("""@file:OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class)""") + appendLine("""@file:Suppress("UNCHECKED_CAST", "UNUSED_PARAMETER", "UnusedImport")""") appendLine() if(packageName.isNotEmpty()) appendLine("package ${packageName}") appendLine() @@ -72,7 +72,10 @@ data class MongoFields( appendLine() val contextualTypes = declaration.containingFile?.annotation("UseContextualSerialization", "kotlinx.serialization")?.arguments?.firstOrNull() ?.value - ?.let { it as? List } + ?.let { + @Suppress("UNCHECKED_CAST") + it as? List + } ?.map { it.declaration } ?: listOf() appendLine("// Contextual types: ${contextualTypes.joinToString { it.qualifiedName?.asString() ?: "-" }}") @@ -95,7 +98,7 @@ data class MongoFields( appendLine("""override val name: String = "${field.name}"""") appendLine("""override fun get(receiver: $typeReference): ${field.kotlinType.toKotlin()} = receiver.${field.name}""") appendLine("""override fun setCopy(receiver: $typeReference, value: ${field.kotlinType.toKotlin()}) = receiver.copy(${field.name} = value)""") - appendLine("""override val serializer: KSerializer<${field.kotlinType.toKotlin()}> = ${field.kotlinType.resolve()!!.toKotlinSerializer(contextualTypes)}""") + appendLine("""override val serializer: KSerializer<${field.kotlinType.toKotlin()}> = ${field.kotlinType.resolve().toKotlinSerializer(contextualTypes)}""") appendLine("""override val annotations: List = $classReference.serializer().tryFindAnnotations("${field.name}")""") } appendLine("}") @@ -125,7 +128,7 @@ data class MongoFields( appendLine("""override val name: String = "${field.name}"""") appendLine("""override fun get(receiver: $typeReference): ${field.kotlinType.toKotlin()} = receiver.${field.name}""") appendLine("""override fun setCopy(receiver: $typeReference, value: ${field.kotlinType.toKotlin()}) = receiver.copy(${field.name} = value)""") - appendLine("""override val serializer: KSerializer<${field.kotlinType.toKotlin()}> = ${field.kotlinType.resolve()!!.toKotlinSerializer(contextualTypes)}""") + appendLine("""override val serializer: KSerializer<${field.kotlinType.toKotlin()}> = ${field.kotlinType.resolve().toKotlinSerializer(contextualTypes)}""") appendLine("""override val annotations: List = $classReference.serializer($nothings).tryFindAnnotations("${field.name}")""") appendLine("""override fun hashCode(): Int = ${field.name.hashCode() * 31 + simpleName.hashCode()}""") appendLine("""override fun equals(other: Any?): Boolean = other is ${simpleName}_${field.name}<${declaration.typeParameters.joinToString(", ") { "* "}}>""") diff --git a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/AwsAdapter.kt b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/AwsAdapter.kt index aeecff24..a97f00cf 100644 --- a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/AwsAdapter.kt +++ b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/AwsAdapter.kt @@ -85,7 +85,9 @@ abstract class AwsAdapter : RequestStreamHandler, Resource { val logger: Logger = LoggerFactory.getLogger(AwsAdapter::class.java) var preventLambdaTimeoutReuse: Boolean = false - fun loadSettings(jclass: Class<*>) { + @Deprecated("Just load settings directly", ReplaceWith("loadSettings()")) + fun loadSettings(jclass: Class<*>) = loadSettings() + fun loadSettings() { logger.debug("Loading settings...") val root = File(System.getenv("LAMBDA_TASK_ROOT")) root.resolve("settings.json").takeIf { it.exists() }?.let { @@ -276,6 +278,7 @@ abstract class AwsAdapter : RequestStreamHandler, Resource { } } } + @OptIn(DelicateCoroutinesApi::class) val backgroundRegularHealthActionsJob = GlobalScope.launch { println("Running ${backgroundReportingActions.size} backgroundRegularHealthActions...") backgroundReportingActions.forEach { diff --git a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/AwsEvents.kt b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/AwsEvents.kt index c5e19621..951e77a0 100644 --- a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/AwsEvents.kt +++ b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/AwsEvents.kt @@ -3,6 +3,7 @@ package com.lightningkite.lightningserver.aws import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.* +import java.util.* @Serializable data class APIGatewayV2HTTPEvent( @@ -100,7 +101,7 @@ data class APIGatewayV2WebsocketRequest( private fun JsonElement.jankType(key: String): String = when(this) { JsonNull -> "Any?" - is JsonObject -> key.capitalize() + is JsonObject -> key.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } is JsonArray -> "List<${this.firstOrNull()?.jankType(key)}>" is JsonPrimitive -> when(this.content) { "true", "false" -> "Boolean" @@ -116,7 +117,7 @@ internal fun JsonObject.jankMeADataClass(name: String) { } println(") {") entries.filter { it.value is JsonObject }.forEach { - (it.value as JsonObject).jankMeADataClass(it.key.capitalize()) + (it.value as JsonObject).jankMeADataClass(it.key.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }) } println("}") } diff --git a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/blocking.kt b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/blocking.kt index 27addc1b..e051d40d 100644 --- a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/blocking.kt +++ b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/blocking.kt @@ -1,14 +1,12 @@ package com.lightningkite.lightningserver.aws -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.async +import kotlinx.coroutines.* import kotlinx.coroutines.future.asCompletableFuture -import kotlinx.coroutines.runBlocking import java.util.Timer import java.util.TimerTask import java.util.concurrent.TimeUnit +@OptIn(DelicateCoroutinesApi::class) fun blockingTimeout(timeoutMs: Long, action: suspend ()->T): T { val result = GlobalScope.async(Dispatchers.Default) { action() diff --git a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/terraform.kt b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/terraform.kt index a645fb97..266ac54c 100644 --- a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/terraform.kt +++ b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/aws/terraform.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.lightningkite.lightningserver.aws import com.lightningkite.lightningserver.auth.JwtSigner @@ -748,7 +750,7 @@ internal fun handlers() { TerraformHandler.handler( name = "DynamoDB", priority = 1, - settingOutput = { key -> + settingOutput = { _ -> """ { url = "dynamodb://${'$'}{var.deployment_location}/${namePrefixUnderscores}" @@ -785,7 +787,7 @@ internal fun handlers() { } ) TerraformHandler.handler( - inputs = { key -> + inputs = { _ -> listOf( ) }, diff --git a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/files/S3File.kt b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/files/S3File.kt index 70fbf267..785ac7a0 100644 --- a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/files/S3File.kt +++ b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/files/S3File.kt @@ -142,12 +142,10 @@ data class S3File(val system: S3FileSystem, val path: File) : FileObject { ), Charsets.UTF_8 ) } - val accessKey = system.credentialProvider.resolveCredentials().accessKeyId() val secretKey = system.credentialProvider.resolveCredentials().secretAccessKey() val objectPath = path.unixPath val date = headers["X-Amz-Date"] ?: return false val algorithm = headers["X-Amz-Algorithm"] ?: return false - val expires = headers["X-Amz-Expires"] ?: return false val credential = headers["X-Amz-Credential"] ?: return false val scope = credential.substringAfter("/") @@ -193,7 +191,7 @@ data class S3File(val system: S3FileSystem, val path: File) : FileObject { val creds = system.creds() val accessKey = creds.access val tokenPreEncoded = creds.tokenPreEncoded - var dateOnly = "" + var dateOnly: String val date = now().atZone(TimeZone.UTC).run { buildString { this.append(date.year.toString().padStart(4, '0')) @@ -243,7 +241,7 @@ data class S3File(val system: S3FileSystem, val path: File) : FileObject { } ?: url val officialSignedUrl: String - get() = system.signedUrlDuration?.let { e -> + get() = system.signedUrlDuration?.let { _ -> system.signer.presignGetObject { it.signatureDuration(system.signedUrlDuration.toJavaDuration()) it.getObjectRequest { diff --git a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/metrics/CloudwatchMetrics.kt b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/metrics/CloudwatchMetrics.kt index 44613d52..0eff7f0e 100644 --- a/server-aws/src/main/kotlin/com/lightningkite/lightningserver/metrics/CloudwatchMetrics.kt +++ b/server-aws/src/main/kotlin/com/lightningkite/lightningserver/metrics/CloudwatchMetrics.kt @@ -64,9 +64,9 @@ class CloudwatchMetrics( events.map { it.metricType.name }.distinct().joinToString() }" ) - events.chunked(1000).forEach { events -> + events.chunked(1000).forEach { eventSubset -> cw.putMetricData { - it.metricData(events.flatMap { + it.metricData(eventSubset.flatMap { val unit = when (it.metricType.unit) { MetricUnit.Seconds -> StandardUnit.SECONDS MetricUnit.Microseconds -> StandardUnit.MICROSECONDS diff --git a/server-azure/src/main/kotlin/com/lightningkite/lightningserver/azure/experimental.kt b/server-azure/src/main/kotlin/com/lightningkite/lightningserver/azure/experimental.kt index dc4919b3..76815a0a 100644 --- a/server-azure/src/main/kotlin/com/lightningkite/lightningserver/azure/experimental.kt +++ b/server-azure/src/main/kotlin/com/lightningkite/lightningserver/azure/experimental.kt @@ -10,12 +10,12 @@ import kotlinx.serialization.KSerializer import kotlinx.serialization.serializer - fun terraformAzure(projectName: String = "project", appendable: Appendable) { val namePrefix = "${projectName}_\${var.deployment_name}" val dependencies = ArrayList() val appSettings = ArrayList() - appendable.appendLine(""" + appendable.appendLine( + """ #### # General configuration for an Azure functions project #### @@ -122,16 +122,18 @@ fun terraformAzure(projectName: String = "project", appendable: Appendable) { ] } - """.trimIndent()) + """.trimIndent() + ) dependencies.add("azurerm_resource_group.resources") dependencies.add("azurerm_storage_account.function_storage") dependencies.add("azurerm_application_insights.insights") dependencies.add("azurerm_key_vault.vault") - for(setting in Settings.requirements) { - when(setting.value.serializer) { + for (setting in Settings.requirements) { + when (setting.value.serializer) { serializer() -> { dependencies.add("azurerm_storage_account.${setting.key}_account") - appendable.appendLine(""" + appendable.appendLine( + """ #### # ${setting.key}: FilesSettings @@ -169,16 +171,21 @@ fun terraformAzure(projectName: String = "project", appendable: Appendable) { azurerm_storage_account.${setting.key}_account ] } - """.trimIndent()) - appSettings.add("""${setting.key} = { + """.trimIndent() + ) + appSettings.add( + """${setting.key} = { storageUrl = azurerm_storage_account.${setting.key}_account.primary_file_endpoint key = "@Microsoft.KeyVault(SecretUri=${'$'}{azurerm_key_vault.vault.vault_uri}secrets/${setting.key}_key)" signedUrlExpirationSeconds = var.${setting.key}_expiry - }""".trimIndent()) + }""".trimIndent() + ) } + serializer() -> { dependencies.add("azurerm_cosmosdb_account.${setting.key}") - appendable.appendLine(""" + appendable.appendLine( + """ #### # ${setting.key}: DatabaseSettings @@ -227,15 +234,20 @@ fun terraformAzure(projectName: String = "project", appendable: Appendable) { azurerm_cosmosdb_account.${setting.key} ] } - """.trimIndent()) - appSettings.add("""${setting.key} = { + """.trimIndent() + ) + appSettings.add( + """${setting.key} = { url = "@Microsoft.KeyVault(SecretUri=${'$'}{azurerm_key_vault.vault.vault_uri}secrets/${setting.key}_key)" databaseName = var.${setting.key}_databaseName - }""".trimIndent()) + }""".trimIndent() + ) } + serializer() -> { dependencies.add("azurerm_redis_cache.${setting.key}") - appendable.appendLine(""" + appendable.appendLine( + """ #### # ${setting.key}: CacheSettings @@ -282,15 +294,20 @@ fun terraformAzure(projectName: String = "project", appendable: Appendable) { azurerm_redis_cache.${setting.key} ] } - """.trimIndent()) - appSettings.add("""${setting.key} = { + """.trimIndent() + ) + appSettings.add( + """${setting.key} = { url = "redis://" connectionString = "@Microsoft.KeyVault(SecretUri=${'$'}{azurerm_key_vault.vault.vault_uri}secrets/${setting.key}_primaryConnectionString)" databaseNumber = var.${setting.key}_databaseNumber - }""".trimIndent()) + }""".trimIndent() + ) } + serializer() -> { - appendable.appendLine(""" + appendable.appendLine( + """ #### # ${setting.key}: SecretBasis @@ -309,22 +326,34 @@ fun terraformAzure(projectName: String = "project", appendable: Appendable) { azurerm_key_vault.vault ] } - """.trimIndent()) - appSettings.add("""${setting.key} = { + """.trimIndent() + ) + appSettings.add( + """${setting.key} = { secret = "@Microsoft.KeyVault(SecretUri=${'$'}{azurerm_key_vault.vault.vault_uri}secrets/${setting.key}_key)" - }""".trimIndent()) + }""".trimIndent() + ) } + else -> { - appendable.appendLine(""" + appendable.appendLine( + """ #### # ${setting.key} #### variable "${setting.key}" { - default = jsondecode("${setting.value.let { Serialization.json.encodeToString(it.serializer as KSerializer, it.default).replace("\"", "\\\"") }}") + default = jsondecode("${ + setting.value.let { + @Suppress("UNCHECKED_CAST") + Serialization.json.encodeToString(it.serializer as KSerializer, it.default) + .replace("\"", "\\\"") + } + }") } - """.trimIndent()) + """.trimIndent() + ) appSettings.add("""${setting.key} = var.${setting.key}""".trimIndent()) } // serializer() -> {} // Azure has no email service, oddly enough @@ -333,7 +362,8 @@ fun terraformAzure(projectName: String = "project", appendable: Appendable) { } // Now we create the outputs. - appendable.appendLine(""" + appendable.appendLine( + """ #### # Primary function app declaration. @@ -373,5 +403,6 @@ fun terraformAzure(projectName: String = "project", appendable: Appendable) { depends_on = [${dependencies.joinToString()}] } - """.trimIndent()) + """.trimIndent() + ) } \ No newline at end of file diff --git a/server-cassandra/build.gradle.kts b/server-cassandra/build.gradle.kts index dcc24b22..b190184c 100644 --- a/server-cassandra/build.gradle.kts +++ b/server-cassandra/build.gradle.kts @@ -13,7 +13,6 @@ plugins { } val kotlinVersion: String by project -val khrysalisVersion: String by project val coroutines: String by project val awsVersion = "2.25.24" dependencies { diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningdb/ConditionSimplify.kt b/server-core/src/main/kotlin/com/lightningkite/lightningdb/ConditionSimplify.kt index ed47c992..9b757120 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningdb/ConditionSimplify.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningdb/ConditionSimplify.kt @@ -12,12 +12,16 @@ fun Condition.simplify(): Condition { .groupBy { it.first } .mapNotNull { // println("AND key ${it.key.map { it.name }}: merging parts ${it.value.map { it.second }}") + @Suppress("UNCHECKED_CAST") val keyCond = it.value.map { it.second as Condition }.reduce(::reduceAnd).finalSimplify() // println("AND reduced to $keyCond") when (keyCond) { is Condition.Always -> return@mapNotNull null is Condition.Never -> return Condition.Never() - else -> make(it.key, keyCond) as Condition + else -> { + @Suppress("UNCHECKED_CAST") + make(it.key, keyCond) as Condition + } } } .let { @@ -34,12 +38,18 @@ fun Condition.simplify(): Condition { .groupBy { it.first } .mapNotNull { // println("OR key ${it.key.map { it.name }}: merging parts ${it.value.map { it.second }}") - val keyCond = it.value.map { it.second as Condition }.reduce(::reduceOr).finalSimplify() + val keyCond = it.value.map { + @Suppress("UNCHECKED_CAST") + it.second as Condition + }.reduce(::reduceOr).finalSimplify() // println("OR reduced to $keyCond") when (keyCond) { is Condition.Always -> return Condition.Always() is Condition.Never -> return@mapNotNull null - else -> make(it.key, keyCond) as Condition + else -> { + @Suppress("UNCHECKED_CAST") + make(it.key, keyCond) as Condition + } } } .let { @@ -99,6 +109,7 @@ private fun make(prop: List>, cond: Condition<*>): Co )) } +@Suppress("UNCHECKED_CAST") private fun reduceAnd(a: Condition, b: Condition): Condition { return when (a) { is Condition.Always -> b @@ -200,6 +211,7 @@ private fun reduceAnd(a: Condition, b: Condition): Condition { else -> Condition.And(listOf(a, b)) } } +@Suppress("UNCHECKED_CAST") private fun reduceOr(a: Condition, b: Condition): Condition { return when (a) { is Condition.Always -> a diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningdb/Mask.kt b/server-core/src/main/kotlin/com/lightningkite/lightningdb/Mask.kt index 20f7777d..870e1506 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningdb/Mask.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningdb/Mask.kt @@ -1,6 +1,5 @@ package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.IsCodableAndHashable import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import org.slf4j.LoggerFactory diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningdb/Modification.ext.kt b/server-core/src/main/kotlin/com/lightningkite/lightningdb/Modification.ext.kt index 12855f56..a18ad140 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningdb/Modification.ext.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningdb/Modification.ext.kt @@ -8,7 +8,10 @@ fun Modification.forFieldOrNull(field: SerializableProperty): Mo is Modification.Chain -> modifications.mapNotNull { it.forFieldOrNull(field) }.takeUnless { it.isEmpty() } ?.let { Modification.Chain(it) } - is Modification.OnField<*, *> -> if (this.key == field) this.modification as Modification else null + is Modification.OnField<*, *> -> { + @Suppress("UNCHECKED_CAST") + if (this.key == field) this.modification as Modification else null + } else -> null } } @@ -17,9 +20,12 @@ fun Modification.vet(field: SerializableProperty, onModification when (this) { is Modification.Assign -> onModification(Modification.Assign(field.get(this.value))) is Modification.Chain -> modifications.forEach { it.vet(field, onModification) } - is Modification.OnField<*, *> -> if (this.key == field) (this.modification as Modification).vet( - onModification - ) else null + is Modification.OnField<*, *> -> if (this.key == field) { + @Suppress("UNCHECKED_CAST") + (this.modification as Modification).vet( + onModification + ) + } else -> {} } @@ -64,11 +70,17 @@ fun Modification.map( ): Modification { return when (this) { is Modification.Chain -> modifications.map { it.map(field, onModification) }.let { Modification.Chain(it) } - is Modification.OnField<*, *> -> if (this.key == field) (this as Modification.OnField).copy( - modification = onModification( - modification + is Modification.OnField<*, *> -> if (this.key == field) { + @Suppress("UNCHECKED_CAST") + (this as Modification.OnField).copy( + modification = onModification( + modification + ) ) - ) else this as Modification + } else { + @Suppress("USELESS_CAST") + this as Modification + } is Modification.Assign -> Modification.Assign( field.setCopy( @@ -87,11 +99,17 @@ suspend fun Modification.mapSuspend( ): Modification { return when (this) { is Modification.Chain -> modifications.map { it.mapSuspend(field, onModification) }.let { Modification.Chain(it) } - is Modification.OnField<*, *> -> if (this.key == field) (this as Modification.OnField).copy( - modification = onModification( - modification + is Modification.OnField<*, *> -> if (this.key == field) { + @Suppress("UNCHECKED_CAST") + (this as Modification.OnField).copy( + modification = onModification( + modification + ) ) - ) else this as Modification + }else { + @Suppress("USELESS_CAST") + this as Modification + } is Modification.Assign -> Modification.Assign( field.setCopy( diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningdb/ModificationSimplify.kt b/server-core/src/main/kotlin/com/lightningkite/lightningdb/ModificationSimplify.kt index 8a8d5f90..8ea0dca4 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningdb/ModificationSimplify.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningdb/ModificationSimplify.kt @@ -17,9 +17,10 @@ fun Modification.simplify(): Modification { Modification.Assign(value) } } else if (this is Modification.OnField<*, *>) { - Modification.OnField( + @Suppress("UNCHECKED_CAST") + Modification.OnField( key as SerializableProperty, modification.simplify() as Modification - ) as Modification + ) } else this } diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningdb/aggregateExtensions.kt b/server-core/src/main/kotlin/com/lightningkite/lightningdb/aggregateExtensions.kt index d445e7d7..c08f228a 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningdb/aggregateExtensions.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningdb/aggregateExtensions.kt @@ -1,13 +1,11 @@ package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.IsHashable - /** * Runs an aggregation directly on the system. * Used for testing and aggregating in the RAM test database. */ -fun Sequence>.aggregate(aggregate: Aggregate): Map { +fun Sequence>.aggregate(aggregate: Aggregate): Map { val aggregators = HashMap() for (entry in this) { aggregators.getOrPut(entry.first) { aggregate.aggregator() }.consume(entry.second) diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningdb/paths.kt b/server-core/src/main/kotlin/com/lightningkite/lightningdb/paths.kt index 9a37e015..0604da47 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningdb/paths.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningdb/paths.kt @@ -1,18 +1,17 @@ package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.IsCodableAndHashable import com.lightningkite.lightningdb.SerializableProperty import kotlinx.serialization.KSerializer import kotlinx.serialization.builtins.NothingSerializer -fun Modification.valueSetForDataClassPath(path: DataClassPath): V? = +fun Modification.valueSetForDataClassPath(path: DataClassPath): V? = (forDataClassPath(path.properties) as? Modification.Assign)?.value -fun Modification.forDataClassPath(path: DataClassPath): Modification? = +fun Modification.forDataClassPath(path: DataClassPath): Modification? = forDataClassPath(path.properties) @Suppress("UNCHECKED_CAST") -private fun Modification<*>.forDataClassPath(list: List>): Modification? { +private fun Modification<*>.forDataClassPath(list: List>): Modification? { return when (this) { is Modification.OnField<*, *> -> if (list.first() == this.key) { if (list.size == 1) modification as Modification @@ -85,6 +84,7 @@ fun Condition.emitReadPaths(out: (DataClassPathPartial) -> Unit) = emi NothingSerializer() as KSerializer )) { out(it as DataClassPathPartial) } private fun Condition<*>.emitReadPaths(soFar: DataClassPath<*, *>, out: (DataClassPathPartial<*>) -> Unit) { + @Suppress("UNCHECKED_CAST") when (this) { is Condition.Always -> {} is Condition.Never -> {} @@ -151,17 +151,15 @@ fun Condition.guaranteedAfter(modification: Modification): Boolean { is Modification.SetPerElement<*> -> { @Suppress("UNCHECKED_CAST") ((this as? Condition.SetAllElements)?.condition - ?: (this as? Condition.SetAnyElements)?.condition)?.let { - (it as Condition).guaranteedAfter(modification.modification as Modification) - } ?: false + ?: (this as? Condition.SetAnyElements)?.condition)?.guaranteedAfter(modification.modification as Modification) + ?: false } is Modification.ListPerElement<*> -> { @Suppress("UNCHECKED_CAST") ((this as? Condition.ListAllElements)?.condition - ?: (this as? Condition.ListAnyElements)?.condition)?.let { - (it as Condition).guaranteedAfter(modification.modification as Modification) - } ?: false + ?: (this as? Condition.ListAnyElements)?.condition)?.guaranteedAfter(modification.modification as Modification) + ?: false } is Modification.Chain -> modification.modifications.all { guaranteedAfter(it) } @@ -193,7 +191,7 @@ private fun Modification<*>.map( if (list.size == 1) Modification.OnField( key = this.key as SerializableProperty, modification = onModification(modification as Modification) as Modification - ) as Modification + ) else this.modification.map(list.drop(1), onModification) } else this diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/AuthOption.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/AuthOption.kt index fd95e425..b13e339f 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/AuthOption.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/AuthOption.kt @@ -33,7 +33,10 @@ inline fun > authRequired( AuthType(type), scopes, maxAge, limitationDescription, - { additionalRequirement(it as RequestAuth) } + { + @Suppress("UNCHECKED_CAST") + additionalRequirement(it as RequestAuth) + } ) ) ) @@ -46,13 +49,17 @@ inline fun > authOptional( crossinline additionalRequirement: suspend (RequestAuth) -> Boolean = { true } ): AuthOptions { val type = typeOf() + @Suppress("UNCHECKED_CAST") return AuthOptions( setOf( AuthOption( AuthType(type), scopes, maxAge, limitationDescription, - { additionalRequirement(it as RequestAuth) } + { + @Suppress("UNCHECKED_CAST") + additionalRequirement(it as RequestAuth) + } ), null ) ) diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/RequestAuth.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/RequestAuth.kt index 522feeed..673fcdf8 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/RequestAuth.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/RequestAuth.kt @@ -146,6 +146,7 @@ data class RequestAuth>( private suspend fun getRawSubject(): SUBJECT { if (now() > rawExpiresAt) { + @Suppress("UNCHECKED_CAST") rawSubject = (subject as Authentication.SubjectHandler>, Comparable>).fetch(rawId as Comparable) as SUBJECT rawExpiresAt = now().plus(subject.subjectCacheExpiration) @@ -153,7 +154,6 @@ data class RequestAuth>( return rawSubject } - @Suppress("UNCHECKED_CAST") suspend fun get() = getRawSubject() fun clearCache(): RequestAuth { @@ -209,7 +209,7 @@ suspend inline fun Request.user(): T = authAny()?.get() as T suspend fun ?> AuthOptions.accepts(auth: RequestAuth<*>?): Boolean = null in this.options || (auth != null && this.options.any { it?.accepts(auth) ?: false }) -@Suppress("UNCHECKED_CAST") +@Suppress("UNCHECKED_CAST", "UNNECESSARY_NOT_NULL_ASSERTION") fun ?> RequestAuth.Companion.test( item: USER, scopes: Set = setOf("*"), diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/RequestAuthSerializable.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/RequestAuthSerializable.kt index dadd26b6..85989474 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/RequestAuthSerializable.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/RequestAuthSerializable.kt @@ -49,6 +49,7 @@ fun RequestAuth<*>.serializable(expiresAt: Instant) = RequestAuthSerializable( ) fun RequestAuthSerializable.real(subjectHandler: Authentication.SubjectHandler<*, *>? = null): RequestAuth<*> { + @Suppress("UNCHECKED_CAST") val subject = subjectHandler ?: Authentication.subjects.values.find { it.name == this.subjectType } as? Authentication.SubjectHandler>, Comparable> ?: throw TokenException("Auth type ${subjectType} not known.") diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/deprecatedTypeAliases.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/deprecatedTypeAliases.kt index 0c79bcbe..daad22af 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/deprecatedTypeAliases.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/deprecatedTypeAliases.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.lightningkite.lightningserver.auth import com.lightningkite.lightningdb.HasId diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/oauth/OauthClientEndpoints.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/oauth/OauthClientEndpoints.kt index 085d0541..b1505885 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/oauth/OauthClientEndpoints.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/oauth/OauthClientEndpoints.kt @@ -35,7 +35,7 @@ class OauthClientEndpoints( serializer = Serialization.module.serializer(), idSerializer = Serialization.module.serializer() ), - authOptions = (maintainPermissions as AuthOptions>) + noAuth, + authOptions = @Suppress("UNCHECKED_CAST") (maintainPermissions as AuthOptions>) + noAuth, getBaseCollection = { database().collection() }, forUser = { val isRoot = maintainPermissions.accepts(authOrNull) diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/BaseAuthEndpoints.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/BaseAuthEndpoints.kt index ed587640..4dd784ed 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/BaseAuthEndpoints.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/BaseAuthEndpoints.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.lightningkite.lightningserver.auth.old import com.lightningkite.lightningdb.HasId @@ -171,7 +173,7 @@ open class BaseAuthEndpoints, ID : Comparable>( description = "Creates a new token for the user, which can be used to authenticate with the API via the header 'Authorization: Bearer [insert token here]'.", errorCases = listOf(), examples = listOf(ApiExample(input = Unit, output = "jwt.jwt.jwt")), - implementation = { input: Unit -> + implementation = { _: Unit -> token(user()) } ) diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/EmailAuthEndpoints.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/EmailAuthEndpoints.kt index cd628e3e..f3f372b8 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/EmailAuthEndpoints.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/EmailAuthEndpoints.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.lightningkite.lightningserver.auth.old import com.lightningkite.lightningdb.HasId @@ -40,7 +42,7 @@ open class EmailAuthEndpoints, ID: Comparable>( val pinExpiration: Duration = 15.minutes, val pinMaxAttempts: Int = 5, private val emailSubject: () -> String = { "${generalSettings().projectName} Log In" }, - private val template: (suspend (email: String, link: String, pin: String) -> String) = { email, link, pin -> + private val template: (suspend (email: String, link: String, pin: String) -> String) = { userEmail, link, pin -> HtmlDefaults.baseEmail(""" ${ @@ -51,7 +53,7 @@ open class EmailAuthEndpoints, ID: Comparable>( } ?: "" } - +

Log In to ${generalSettings().projectName}

We received a request for a login email for ${email}. To log in, please click the link below or enter the PIN.

We received a request for a login email for ${userEmail}. To log in, please click the link below or enter the PIN.

@@ -89,7 +91,7 @@ open class EmailAuthEndpoints, ID: Comparable>( ), ), successCode = HttpStatus.NoContent, - implementation = { user: Unit, addressUnsafe: String -> + implementation = { _: Unit, addressUnsafe: String -> val address = addressUnsafe.lowercase().trim() val jwt = base.token(emailAccess.byEmail(address), base.emailExpiration) val pin = pin.establish(address) @@ -111,7 +113,7 @@ open class EmailAuthEndpoints, ID: Comparable>( errorCases = listOf(), examples = listOf(ApiExample(input = EmailPinLogin("test@test.com", pin.generate()), output = "jwt.jwt.jwt")), successCode = HttpStatus.OK, - implementation = { anon: Unit, input: EmailPinLogin -> + implementation = { _: Unit, input: EmailPinLogin -> val email = input.email.lowercase().trim() pin.assert(email, input.pin) base.token(emailAccess.byEmail(email)) @@ -137,7 +139,7 @@ open class EmailAuthEndpoints, ID: Comparable>( val callback = path("oauth/${it.first.pathName}/callback").oauthCallback( oauthProviderInfo = it.first, credentials = { credRead(rawCreds) } - ) { response, uuid -> + ) { response, _ -> val profile = it.first.getProfile(response) val user = emailAccess.asExternal().byExternalService(profile) val token = base.token(user, 1.minutes) @@ -156,7 +158,7 @@ open class EmailAuthEndpoints, ID: Comparable>( "${it.first.loginUrl}?someparams=x" ) ), - implementation = { anon: Unit, _: Unit -> + implementation = { _: Unit, _: Unit -> callback.loginUrl(uuid()) } ) @@ -194,7 +196,7 @@ open class EmailAuthEndpoints, ID: Comparable>( val email = it.body!!.text().split('&') .associate { it.substringBefore('=') to URLDecoder.decode(it.substringAfter('='), Charsets.UTF_8) } .get("email")!!.lowercase().trim() - val basis = try { + try { loginEmail.implementation(AuthAndPathParts(null, null, arrayOf()), email) } catch (e: Exception) { e.printStackTrace() diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/PasswordAuthEndpoints.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/PasswordAuthEndpoints.kt index b701ab65..e36f946c 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/PasswordAuthEndpoints.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/PasswordAuthEndpoints.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.lightningkite.lightningserver.auth.old import com.lightningkite.lightningdb.HasId @@ -25,7 +27,7 @@ open class PasswordAuthEndpoints, ID: Comparable>( summary = "Password Login", description = "Log in with a password", errorCases = listOf(), - implementation = { anon: Unit, input: PasswordLogin -> + implementation = { _: Unit, input: PasswordLogin -> val user = info.byUsername(input.username, input.password) if (!input.password.checkAgainstHash(info.hashedPassword(user))) throw BadRequestException( diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/PinHandler.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/PinHandler.kt index 3347b7e2..792369c1 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/PinHandler.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/PinHandler.kt @@ -36,9 +36,9 @@ open class PinHandler( fun generate(): String { val r = SecureRandom() - var pin = "" + var pin: String do { - pin = String(CharArray(length) { availableCharacters.get(r.nextInt(availableCharacters.size)) }) + pin = String(CharArray(length) { availableCharacters[r.nextInt(availableCharacters.size)] }) } while (BadWordList.detectParanoid(pin)) return pin } diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/SmsAuthEndpoints.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/SmsAuthEndpoints.kt index c9449135..56f82274 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/SmsAuthEndpoints.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/old/SmsAuthEndpoints.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.lightningkite.lightningserver.auth.old import com.lightningkite.lightningdb.HasId @@ -55,7 +57,7 @@ open class SmsAuthEndpoints, ID: Comparable>( ), ), successCode = HttpStatus.NoContent, - implementation = { user: Unit, phoneUnsafe: String -> + implementation = { _: Unit, phoneUnsafe: String -> val phone = phoneUnsafe.filter { it.isDigit() } if(phone.isEmpty()) throw BadRequestException("Blank phone number given.") if(phone.isEmpty()) throw BadRequestException("Invalid phone number.") @@ -73,7 +75,7 @@ open class SmsAuthEndpoints, ID: Comparable>( errorCases = listOf(), examples = listOf(ApiExample(PhonePinLogin("801-369-3729", pin.generate()), "jwt.jwt.jwt")), successCode = HttpStatus.OK, - implementation = { anon: Unit, input: PhonePinLogin -> + implementation = { _: Unit, input: PhonePinLogin -> val phone = input.phone.filter { it.isDigit() } pin.assert(phone, input.pin) base.token(phoneAccess.byPhone(input.phone)) @@ -100,7 +102,7 @@ open class SmsAuthEndpoints, ID: Comparable>( val phone = it.body!!.text().split('&') .associate { it.substringBefore('=') to URLDecoder.decode(it.substringAfter('='), Charsets.UTF_8) } .get("phone")!!.filter { it.isDigit() } - val basis = try { + try { loginSms.implementation(AuthAndPathParts(null, null, arrayOf()), phone) } catch (e: Exception) { e.printStackTrace() diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OauthProofEndpoints.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OauthProofEndpoints.kt index c30a598f..df7fcece 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OauthProofEndpoints.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OauthProofEndpoints.kt @@ -45,11 +45,10 @@ class OauthProofEndpoints( Authentication.register(this) } - @Suppress("UNCHECKED_CAST") val callback = path("callback").oauthCallback( oauthProviderInfo = provider, credentials = credentials - ) { response, uuid -> + ) { response, _ -> val profile = provider.getProfile(response) val email = profile.email ?: throw BadRequestException("No email was found for this profile.") HttpResponse.redirectToGet(continueUiAuthUrl() + "?proof=${Serialization.json.encodeToString(Proof.serializer(), proofHasher().makeProof( diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OneTimePasswordProofEndpoints.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OneTimePasswordProofEndpoints.kt index 283de56a..4960239b 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OneTimePasswordProofEndpoints.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OneTimePasswordProofEndpoints.kt @@ -79,9 +79,9 @@ class OneTimePasswordProofEndpoints( Tasks.onSettingsReady { Authentication.subjects.forEach { @Suppress("UNCHECKED_CAST") - ModelRestEndpoints, OtpSecret>, Comparable>( + ModelRestEndpoints( path("secrets/${it.value.name.lowercase()}"), - modelInfo, OtpSecret>, Comparable>( + modelInfo( serialization = ModelSerializationInfo( OtpSecret.serializer(it.value.idSerializer as KSerializer>), it.value.idSerializer as KSerializer> @@ -104,7 +104,7 @@ class OneTimePasswordProofEndpoints( update = Condition.Always(), delete = Condition.Always(), ) - ) as FieldCollection>> + ) }, modelName = "OtpSecret For ${it.value.name}" ) @@ -125,6 +125,7 @@ class OneTimePasswordProofEndpoints( errorCases = listOf(), examples = listOf(), implementation = { input: EstablishOtp -> + @Suppress("UNCHECKED_CAST") val secret = OtpSecret( _id = auth.rawId as Comparable, secret = ByteArray(32).also { SecureRandom.getInstanceStrong().nextBytes(it) }, @@ -147,8 +148,8 @@ class OneTimePasswordProofEndpoints( errorCases = listOf(), examples = listOf(), implementation = { code: String -> - val existing = table(auth.subject).get(auth.rawId as Comparable) ?: throw NotFoundException() @Suppress("UNCHECKED_CAST") + table(auth.subject).get(auth.rawId as Comparable) ?: throw NotFoundException() prove.implementation( AuthAndPathParts(null, null, arrayOf()), IdentificationAndPassword( @@ -171,6 +172,7 @@ class OneTimePasswordProofEndpoints( errorCases = listOf(), examples = listOf(), implementation = { _: Unit -> + @Suppress("UNCHECKED_CAST") table(auth.subject).deleteOneById(auth.rawId as Comparable) } ) @@ -184,6 +186,7 @@ class OneTimePasswordProofEndpoints( errorCases = listOf(), examples = listOf(), implementation = { _: Unit -> + @Suppress("UNCHECKED_CAST") table(auth.subject).get(auth.rawId as Comparable)?.let { SecretMetadata( establishedAt = it.establishedAt, diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OtpSecret.ext.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OtpSecret.ext.kt index fd8b4318..9480b773 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OtpSecret.ext.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/OtpSecret.ext.kt @@ -1,7 +1,9 @@ @file:UseContextualSerialization(Duration::class) +@file:OptIn(ExperimentalLightningServer::class) package com.lightningkite.lightningserver.auth.proof +import com.lightningkite.lightningdb.ExperimentalLightningServer import com.lightningkite.lightningserver.encryption.SecureHasher import dev.turingcomplete.kotlinonetimepassword.HmacAlgorithm import dev.turingcomplete.kotlinonetimepassword.OtpAuthUriBuilder diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/PasswordProofEndpoints.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/PasswordProofEndpoints.kt index a5ec8660..3bd2d99c 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/PasswordProofEndpoints.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/PasswordProofEndpoints.kt @@ -35,7 +35,7 @@ class PasswordProofEndpoints( val database: () -> Database, val cache: () -> Cache, val proofHasher: () -> SecureHasher = secretBasis.hasher("proof"), - val evaluatePassword: (String) -> Unit = { it } + val evaluatePassword: (String) -> Unit = { } ) : ServerPathGroup(path), Authentication.DirectProofMethod { init { path.docName = "PasswordProof" @@ -70,20 +70,22 @@ class PasswordProofEndpoints( serialization = ModelSerializationInfo(PasswordSecret.serializer(it.value.idSerializer as KSerializer>), it.value.idSerializer as KSerializer>), authOptions = Authentication.isAdmin as AuthOptions>, getBaseCollection = { table(it.value) }, - getCollection = { c -> c.withPermissions(ModelPermissions( - create = Condition.Always(), - read = Condition.Always(), - readMask = Mask( - listOf( - Condition.Never>>() to Modification.OnField( - PasswordSecret_hash(it.value.idSerializer as KSerializer>), - Modification.Assign("") + getCollection = { c -> + c.withPermissions(ModelPermissions( + create = Condition.Always(), + read = Condition.Always(), + readMask = Mask( + listOf( + Condition.Never>>() to Modification.OnField( + PasswordSecret_hash(it.value.idSerializer as KSerializer>), + Modification.Assign("") + ) ) - ) - ), - update = Condition.Always(), - delete = Condition.Always(), - )) as FieldCollection>> }, + ), + update = Condition.Always(), + delete = Condition.Always(), + )) + }, modelName = "PasswordSecret For ${it.value.name}" )) } @@ -111,11 +113,13 @@ class PasswordProofEndpoints( implementation = { value: EstablishPassword -> evaluatePassword(value.password) if(value.hint?.contains(value.password, true) == true) throw BadRequestException("Hint cannot contain the password itself!") + @Suppress("UNCHECKED_CAST") val secret = PasswordSecret( _id = auth.rawId as Comparable, hash = value.password.secureHash(), hint = value.hint, ) + @Suppress("UNCHECKED_CAST") table(auth.subject).deleteOneById(auth.rawId as Comparable) table(auth.subject).insertOne(secret) Unit @@ -131,6 +135,7 @@ class PasswordProofEndpoints( errorCases = listOf(), examples = listOf(), implementation = { _: Unit -> + @Suppress("UNCHECKED_CAST") table(auth.subject).deleteOneById(auth.rawId as Comparable) } ) @@ -144,6 +149,7 @@ class PasswordProofEndpoints( errorCases = listOf(), examples = listOf(), implementation = { _: Unit -> + @Suppress("UNCHECKED_CAST") table(auth.subject).get(auth.rawId as Comparable)?.let { SecretMetadata( establishedAt = it.establishedAt, @@ -178,7 +184,6 @@ class PasswordProofEndpoints( ), successCode = HttpStatus.OK, implementation = { input: IdentificationAndPassword -> - val postedAt = now() val cacheKey = "password-${input.property}-${input.value}" val ct = (cache().get(cacheKey) ?: 0) if (ct > 5) throw BadRequestException("Too many attempts; please wait five minutes.") diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/PinHandler.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/PinHandler.kt index d583571c..b2aca194 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/PinHandler.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/proof/PinHandler.kt @@ -42,7 +42,7 @@ open class PinHandler( fun generate(): String { val r = SecureRandom() - var pin = "" + var pin: String do { pin = String(CharArray(length) { availableCharacters.get(r.nextInt(availableCharacters.size)) }) } while (BadWordList.detectParanoid(pin)) diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/subject/AuthEndpointsForSubject.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/subject/AuthEndpointsForSubject.kt index 4e4305c4..ddc459d7 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/subject/AuthEndpointsForSubject.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/subject/AuthEndpointsForSubject.kt @@ -88,6 +88,7 @@ class AuthEndpointsForSubject, ID : Comparable>( requestAuth == null -> Condition.Never() else -> Condition.OnField( Session_subjectId(handler.subjectSerializer, handler.idSerializer), + @Suppress("UNCHECKED_CAST") Condition.Equal(requestAuth.rawId as ID) ) } @@ -198,7 +199,6 @@ class AuthEndpointsForSubject, ID : Comparable>( } } - @Suppress("UNREACHABLE_CODE") val login = path("login").post.api( authOptions = noAuth, inputType = ListSerializer(Proof.serializer()), @@ -255,7 +255,7 @@ class AuthEndpointsForSubject, ID : Comparable>( implementation = { futureSessionToken: String -> val future = FutureSession.fromToken(futureSessionToken) if (future.oauthClient != null) throw ForbiddenException("Please use the token endpoint for OAuth instead, so we can check your secret.") - val (s, secret) = newSessionPrivate( + val (_, secret) = newSessionPrivate( label = future.label, subjectId = future.subjectId, derivedFrom = future.originalSessionId, @@ -575,7 +575,7 @@ class AuthEndpointsForSubject, ID : Comparable>( val aapp = AuthAndPathParts?, TypedServerPath0>(null, request, arrayOf()) return when (method) { is Authentication.StartedProofMethod -> { - val key = method.start.implementation(aapp, input.value!!) + val key = method.start.implementation(aapp, input.value) HttpResponse( body = HttpContent.Text( string = HtmlDefaults.basePage( diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/token/JwtTokenFormat.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/token/JwtTokenFormat.kt index 1cffb93d..b8ffac34 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/token/JwtTokenFormat.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/auth/token/JwtTokenFormat.kt @@ -28,17 +28,16 @@ class JwtTokenFormat( handler: Authentication.SubjectHandler, auth: RequestAuth ): String { - @Suppress("UNCHECKED_CAST") return hasher().signJwt( JwtClaims( iss = issuer, sid = auth.sessionId, - sub = "${handler.name}|${Serialization.json.encodeUnwrappingString(handler.idSerializer, auth.id)}", + sub = "${handler.name}|${Serialization.json.encodeUnwrappingString(handler.idSerializer, auth.id)}", aud = audience, exp = now().plus(expiration).epochSeconds, iat = auth.issuedAt.epochSeconds, nbf = now().epochSeconds, - scope = auth.scopes?.joinToString(" "), + scope = auth.scopes.joinToString(" "), thp = auth.thirdParty, cache = Serialization.json.encodeToString(auth.cacheKeyMap()) ) diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/compression/engineCompression.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/compression/engineCompression.kt index a2ac238e..66e20a98 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/compression/engineCompression.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/compression/engineCompression.kt @@ -13,7 +13,7 @@ suspend fun HttpResponse.extensionForEngineCompression(request: HttpRequest): Ht "gzip" -> return copy(headers = HttpHeaders { set(headers) set(HttpHeader.ContentEncoding, "gzip") - }, body = body?.bytes()?.gzip()?.let { HttpContent.Binary(it, body!!.type) }) + }, body = body?.bytes()?.gzip()?.let { HttpContent.Binary(it, body.type) }) } } return this diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/DatabaseSettings.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/DatabaseSettings.kt index 66645d46..9b938d48 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/DatabaseSettings.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/DatabaseSettings.kt @@ -64,6 +64,7 @@ data class DatabaseSettings( class InMemoryDatabase(val premadeData: JsonObject? = null) : Database { val collections = HashMap, String>, FieldCollection<*>>() + @Suppress("UNCHECKED_CAST") override fun collection(serializer: KSerializer, name: String): FieldCollection = collections.getOrPut(serializer to name) { val made = InMemoryFieldCollection(serializer = serializer) premadeData?.get(name)?.let { @@ -96,6 +97,7 @@ class InMemoryUnsafePersistenceDatabase(val folder: File) : Database { val collections = HashMap, String>, FieldCollection<*>>() override fun collection(serializer: KSerializer, name: String): FieldCollection = synchronized(collections) { + @Suppress("UNCHECKED_CAST") collections.getOrPut(serializer to name) { val fileName = name.filter { it.isLetterOrDigit() } val oldStyle = folder.resolve(fileName) diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelDumpEndpoint.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelDumpEndpoint.kt index 3b117bce..e48aaf82 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelDumpEndpoint.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelDumpEndpoint.kt @@ -97,17 +97,17 @@ open class ModelDumpEndpoints?, T : HasId, ID : Comparable { - writer().use { out -> - val emit = Serialization.csv.beginEncodingToAppendable(info.serialization.serializer, out) + writer().use { out2 -> + val emit = Serialization.csv.beginEncodingToAppendable(info.serialization.serializer, out2) flow.collect { emit(it) } } } DumpType.JSON_LINES -> { - writer().use { out -> + writer().use { out2 -> flow.collect { - out.appendLine(Serialization.json.encodeToString(info.serialization.serializer, it)) + out2.appendLine(Serialization.json.encodeToString(info.serialization.serializer, it)) } } } diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelInfo.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelInfo.kt index 7e89108b..adcf2b54 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelInfo.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelInfo.kt @@ -7,6 +7,7 @@ import com.lightningkite.lightningserver.typed.AuthAccessor import kotlinx.serialization.KSerializer import kotlinx.serialization.serializer +@Suppress("DEPRECATION") @Deprecated("User newer version with auth accessor instead, as it enables more potential optimizations.") inline fun , reified T : HasId, reified ID : Comparable> ModelInfo( noinline getCollection: () -> FieldCollection, diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelInfoWithDefault.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelInfoWithDefault.kt index 4657d80c..b325e6d5 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelInfoWithDefault.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelInfoWithDefault.kt @@ -10,6 +10,7 @@ import com.lightningkite.lightningserver.serialization.Serialization import com.lightningkite.lightningserver.typed.AuthAccessor import kotlinx.serialization.serializer +@Suppress("DEPRECATION") @Deprecated("User newer version with auth accessor instead, as it enables more potential optimizations.") inline fun ?, reified T : HasId, reified ID : Comparable> ModelInfoWithDefault( noinline getCollection: () -> FieldCollection, @@ -51,6 +52,7 @@ fun ?, T : HasId, ID : Comparable> ModelInfoWithDefault( override suspend fun collection(auth: AuthAccessor): FieldCollection = forUser(collection(), auth.user()) override val collectionName: String = modelName + @Suppress("UNCHECKED_CAST") override suspend fun defaultItem(auth: RequestAuth?): T = defaultItem(auth?.get() as USER) override fun exampleItem(): T? = exampleItem() } diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelRestEndpoints.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelRestEndpoints.kt index eb9608b3..de23fd19 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelRestEndpoints.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/db/ModelRestEndpoints.kt @@ -73,10 +73,9 @@ open class ModelRestEndpoints?, T : HasId, ID : Comparable>> { return try { - val sample = exampleItem() ?: return emptyList() + if (exampleItem() == null) return emptyList() info.serialization.serializer.serializableProperties!! .filter { it.serializer.descriptor.kind is PrimitiveKind } .let { @@ -104,7 +103,7 @@ open class ModelRestEndpoints?, T : HasId, ID : Comparable + implementation = { _: Unit -> info.defaultItem(authOrNull) } ) @@ -207,7 +206,7 @@ open class ModelRestEndpoints?, T : HasId, ID : Comparable + implementation = { _: Unit -> info.collection(this) .get(path1) ?: throw NotFoundException() diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/email/Attachment.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/email/Attachment.kt index ad7b421c..cdabe1e9 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/email/Attachment.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/email/Attachment.kt @@ -11,6 +11,7 @@ import java.net.URL * Attachment is used by EmailClients for attaching files to an email, whether they be * a local file for uploading, or a remote file for embedding. */ +@Suppress("DEPRECATION") @Deprecated("Use Email.Attachment instead") sealed interface Attachment { val description: String diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/email/EmailClient.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/email/EmailClient.kt index 5bc35118..f93ed49b 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/email/EmailClient.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/email/EmailClient.kt @@ -7,6 +7,7 @@ import com.lightningkite.lightningserver.serverhealth.HealthStatus * An interface for sending emails. This is used directly by the EmailSettings to abstract the implementation of * sending emails away, so it can go to multiple places. */ +@Suppress("DEPRECATION") interface EmailClient : HealthCheckable { suspend fun send(email: Email) suspend fun sendBulk(template: Email, personalizations: List) = personalizations.forEach { diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/encryption/SecureHasher.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/encryption/SecureHasher.kt index 3cfd1408..9f9d9128 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/encryption/SecureHasher.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/encryption/SecureHasher.kt @@ -68,7 +68,7 @@ interface SecureHasher { ) val public = run { val s = (pk as BCECPrivateKey).parameters - val q = s.g.multiply((pk as BCECPrivateKey).d) + val q = s.g.multiply(pk.d) factory.generatePublic(org.bouncycastle.jce.spec.ECPublicKeySpec(q, s)) } @@ -122,7 +122,6 @@ fun SecureHasher.signJwt(claims: JwtClaims): String = buildString { })).toByteArray()) ) append('.') - @Suppress("UNCHECKED_CAST") append( Base64.getUrlEncoder().withoutPadding().encodeToString( withDefaults.encodeToString(claims).toByteArray() @@ -137,7 +136,7 @@ fun SecureHasher.verifyJwt(token: String, requiredAudience: String? = null): Jwt val parts = token.split('.') if (parts.size != 3) return null // It's not a JWT, so we'll ignore it. val signature = Base64.getUrlDecoder().decode(parts[2]) - val header: JwtHeader = Serialization.json.decodeFromString(Base64.getUrlDecoder().decode(parts[0]).toString(Charsets.UTF_8)) + @Suppress("UNUSED_VARIABLE") val header: JwtHeader = Serialization.json.decodeFromString(Base64.getUrlDecoder().decode(parts[0]).toString(Charsets.UTF_8)) val claims: JwtClaims = Serialization.json.decodeFromString(Base64.getUrlDecoder().decode(parts[1]).toString(Charsets.UTF_8)) requiredAudience?.let { if (claims.aud != it) return null } // It's for someone else. Ignore it. if (System.currentTimeMillis() / 1000L > claims.exp) throw JwtExpiredException("JWT has expired.") diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/engine/Engine.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/engine/Engine.kt index 98cdf87b..9548c9d4 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/engine/Engine.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/engine/Engine.kt @@ -6,11 +6,7 @@ import com.lightningkite.lightningserver.exceptions.report import com.lightningkite.lightningserver.metrics.Metrics import com.lightningkite.lightningserver.tasks.Task import com.lightningkite.lightningserver.websocket.WebSocketIdentifier -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.delay +import kotlinx.coroutines.* import org.slf4j.LoggerFactory import kotlin.time.Duration import kotlin.time.Duration.Companion.minutes @@ -21,6 +17,7 @@ import kotlin.time.Duration.Companion.minutes */ interface Engine { suspend fun launchTask(task: Task, input: Any?) + @OptIn(DelicateCoroutinesApi::class) fun backgroundReportingAction(action: suspend ()->Unit) { GlobalScope.launch { while (true) { @@ -48,6 +45,7 @@ interface Engine { */ class LocalEngine(val websocketCache: Cache) : Engine { val logger = LoggerFactory.getLogger(this::class.java) + @OptIn(DelicateCoroutinesApi::class) override suspend fun launchTask(task: Task, input: Any?) { GlobalScope.launch { Metrics.handlerPerformance(task) { diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/exceptions/GroupedDatabaseExceptionReporter.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/exceptions/GroupedDatabaseExceptionReporter.kt index 91e4f09d..64a03839 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/exceptions/GroupedDatabaseExceptionReporter.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/exceptions/GroupedDatabaseExceptionReporter.kt @@ -3,16 +3,14 @@ package com.lightningkite.lightningserver.exceptions import com.lightningkite.lightningdb.* import com.lightningkite.lightningserver.auth.AuthOptions import com.lightningkite.lightningserver.auth.Authentication -import com.lightningkite.lightningserver.auth.RequestAuth -import com.lightningkite.lightningserver.auth.oauth.OauthClient import com.lightningkite.lightningserver.core.ServerPath -import com.lightningkite.lightningserver.db.ModelInfoWithDefault import com.lightningkite.lightningserver.db.ModelRestEndpoints import com.lightningkite.lightningserver.db.ModelSerializationInfo import com.lightningkite.lightningserver.db.modelInfoWithDefault import com.lightningkite.lightningserver.serialization.Serialization -import com.lightningkite.lightningserver.typed.AuthAccessor import com.lightningkite.now +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import kotlinx.serialization.serializer import java.net.NetworkInterface @@ -31,7 +29,9 @@ class GroupedDatabaseExceptionReporter(val packageName: String, val database: Da } val contextString = context.toString() val server = System.getenv("AWS_LAMBDA_LOG_STREAM_NAME")?.takeUnless { it.isEmpty() } - ?: NetworkInterface.getNetworkInterfaces().toList().sortedBy { it.name } + ?: withContext(Dispatchers.IO) { + NetworkInterface.getNetworkInterfaces() + }.toList().sortedBy { it.name } .firstOrNull()?.hardwareAddress?.sumOf { it.hashCode() }?.toString(16) ?: "?" val message = t.message ?: "No message" val trace = t.stackTraceToString() @@ -62,6 +62,7 @@ class GroupedDatabaseExceptionReporter(val packageName: String, val database: Da } + @Suppress("UNCHECKED_CAST") val modelInfo = modelInfoWithDefault( serialization = ModelSerializationInfo( serializer = Serialization.module.serializer(), diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/exceptions/exceptions.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/exceptions/exceptions.kt index 62c34336..b50b02b0 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/exceptions/exceptions.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/exceptions/exceptions.kt @@ -44,7 +44,7 @@ open class HttpStatusException( return HttpResponse(body = HttpContent.Text(string = HtmlDefaults.basePage("""

${status.toString().escapeHTML()}

${message}

- ${detail.let { "" } ?: ""} + ${detail.let { "" }} ${if (generalSettings().debug) "" else ""} """.trimIndent()), type = ContentType.Text.Html), headers = headers) } diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/externalintegration/ExternalAsyncTaskIntegration.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/externalintegration/ExternalAsyncTaskIntegration.kt index 18df672f..3c23340f 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/externalintegration/ExternalAsyncTaskIntegration.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/externalintegration/ExternalAsyncTaskIntegration.kt @@ -48,6 +48,7 @@ class ExternalAsyncTaskIntegration, RESULT>( } // Collection exposed to admins only for tasks + @Suppress("UNCHECKED_CAST") val info = modelInfoWithDefault, ExternalAsyncTaskRequest, String>( authOptions = authOptions as AuthOptions>, serialization = ModelSerializationInfo( diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/files/FileObject.ext.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/files/FileObject.ext.kt index b0cee7df..3e14665e 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/files/FileObject.ext.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/files/FileObject.ext.kt @@ -16,10 +16,10 @@ fun FileObject.resolveRandom(prefix: String = "", extension: String) = suspend fun FileObject.exists() = head() != null -suspend fun FileObject.local(out: File = File.createTempFile("downloaded", ".temp")): File { - out.outputStream().use { out -> +suspend fun FileObject.local(@Suppress("BlockingMethodInNonBlockingContext") out: File = File.createTempFile("downloaded", ".temp")): File { + out.outputStream().use { outStream -> get()!!.stream().use { - it.copyTo(out) + it.copyTo(outStream) } } return out @@ -49,9 +49,5 @@ val FileObject.serverFile: ServerFile get() = ServerFile(url) suspend fun FileObject.toHttpContent(): HttpContent? = this.get() -suspend fun FileObject.copyTo(other: FileObject) { - other.put(this.toHttpContent() ?: throw IOException("File disappeared or changed during transfer")) -} - val FileObject.nameWithoutExtension: String get() = this.name.substringBeforeLast('.') val FileObject.extension: String get() = this.name.substringAfterLast('.', "") \ No newline at end of file diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/forms/FormSerialization.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/forms/FormSerialization.kt index bd18e86d..f462f73d 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/forms/FormSerialization.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/forms/FormSerialization.kt @@ -13,7 +13,7 @@ import kotlinx.serialization.serializer typealias HtmlRenderer = FlowContent.(inputKey: String, value: T) -> Unit -class HtmlSerializer(val serializersModule: SerializersModule = EmptySerializersModule, val module: Module) { +class HtmlSerializer(val serializersModule: SerializersModule = EmptySerializersModule(), val module: Module) { inline fun render(value: T, into: FlowContent) = render(Serialization.module.serializer(), value, into) fun render(serializer: SerializationStrategy, value: T, into: FlowContent) { HtmlEncoder(into).encodeSerializableValue(serializer, value) diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/Http.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/Http.kt index f4bbb4e6..b57a8eb4 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/Http.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/Http.kt @@ -47,7 +47,7 @@ object Http { HttpResponse(status = HttpStatus.InternalServerError) } } - var notFound: suspend (HttpEndpoint, HttpRequest) -> HttpResponse = { path, request -> + var notFound: suspend (HttpEndpoint, HttpRequest) -> HttpResponse = { path, _ -> HttpResponse.html( HttpStatus.NotFound, content = HtmlDefaults.basePage( """ diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/HttpHeaders.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/HttpHeaders.kt index aa93cb11..e7ce0679 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/HttpHeaders.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/HttpHeaders.kt @@ -2,7 +2,6 @@ package com.lightningkite.lightningserver.http import com.lightningkite.lightningserver.core.ContentType import kotlinx.datetime.Instant -import kotlinx.datetime.ZoneOffset import kotlinx.datetime.toJavaInstant import java.time.format.DateTimeFormatter diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/HttpResponse.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/HttpResponse.kt index 3ea76139..5f6ba22d 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/HttpResponse.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/http/HttpResponse.kt @@ -47,7 +47,7 @@ data class HttpResponse( headers: HttpHeaders.Builder.() -> Unit = {}, builder: HTML.() -> Unit ) = HttpResponse( - body = HttpContent.Html(builder), + body = HttpContent.html(builder), status = status, headers = headers ) @@ -77,7 +77,7 @@ data class HttpResponse( status: HttpStatus = HttpStatus.OK, headers: HttpHeaders.Builder.() -> Unit = {} ) = HttpResponse( - body = HttpContent.Json(value), + body = HttpContent.json(value), status = status, headers = HttpHeaders(headers) ) diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/jsonschema/JsonSchemaBuilder.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/jsonschema/JsonSchemaBuilder.kt index df02bf4e..cc5dc573 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/jsonschema/JsonSchemaBuilder.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/jsonschema/JsonSchemaBuilder.kt @@ -246,8 +246,8 @@ class JsonSchemaBuilder( annotation { it: ExpectedPattern -> copy(pattern = it.pattern) } annotation { it: JsonSchemaFormat -> copy(format = it.format) } annotation { it: DisplayName -> copy(title = it.text) } - annotation { it: AdminHidden -> copy(uiWidget = "hidden") } - annotation { it: Multiline -> copy(uiWidget = "textarea") } + annotation { _: AdminHidden -> copy(uiWidget = "hidden") } + annotation { _: Multiline -> copy(uiWidget = "textarea") } annotation { it: UiWidget -> copy(uiWidget = it.type) } annotation { it: References -> copy(references = key(json.serializersModule.serializer(it.references.java))) } annotation { it: MultipleReferences -> diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/jsonschema/OpenApi.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/jsonschema/OpenApi.kt index 393e5c53..6cec2680 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/jsonschema/OpenApi.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/jsonschema/OpenApi.kt @@ -166,7 +166,10 @@ private fun ApiEndpoint<*, *, *, *>.openApi(builder: JsonSchemaBuilder): OpenApi ContentType.Application.Json.toString() to OpenApiMediaType( schema = builder[this.inputType], example = examples.firstOrNull() - ?.let { example -> Serialization.json.encodeToJsonElement(inputType as KSerializer, example.input) } + ?.let { example -> + @Suppress("UNCHECKED_CAST") + Serialization.json.encodeToJsonElement(inputType as KSerializer, example.input) + } ?: JsonNull, // examples = examples.groupBy { it.name }.flatMap { // if (it.value.size == 1) it.value else it.value.mapIndexed { index, it -> @@ -194,7 +197,10 @@ private fun ApiEndpoint<*, *, *, *>.openApi(builder: JsonSchemaBuilder): OpenApi ContentType.Application.Json.toString() to OpenApiMediaType( schema = builder[this.outputType], example = examples.firstOrNull() - ?.let { example -> Serialization.json.encodeToJsonElement(outputType as KSerializer, example.output) } + ?.let { example -> + @Suppress("UNCHECKED_CAST") + Serialization.json.encodeToJsonElement(outputType as KSerializer, example.output) + } ?: JsonNull, // examples = examples.groupBy { it.name }.flatMap { // if (it.value.size == 1) it.value else it.value.mapIndexed { index, it -> diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/meta/MetaEndpoints.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/meta/MetaEndpoints.kt index 2d9c6f36..41224590 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/meta/MetaEndpoints.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/meta/MetaEndpoints.kt @@ -32,7 +32,7 @@ class MetaEndpoints( ) : ServerPathGroup(path) { val root = get.handler { - HttpResponse(body = HttpContent.Html { + HttpResponse(body = HttpContent.html { head { title("${generalSettings().projectName} - Meta Information") } body { ul { @@ -160,15 +160,15 @@ class MetaEndpoints( ) } val paths = get("paths").handler { - HttpResponse(body = HttpContent.Html { + HttpResponse(body = HttpContent.html { head { title("${generalSettings().projectName} - Path List") } body { ul { for (endpoint in Http.endpoints.keys.sortedBy { it.path.toString() }) { li { a(href = endpoint.path.fullUrl()) { +endpoint.toString() } } } - for (path in WebSockets.handlers.keys) { - li { a(href = wsTester.path.toString() + "?path=${path}") { +"WS $path" } } + for (wsPath in WebSockets.handlers.keys) { + li { a(href = wsTester.path.toString() + "?path=${wsPath}") { +"WS $wsPath" } } } for (schedule in Scheduler.schedules) { li { +"SCHEDULE ${schedule.key}: ${schedule.value.schedule}" } @@ -269,6 +269,7 @@ class MetaEndpoints( ) } +@Suppress("NOTHING_TO_INLINE") inline fun ServerPath.metaEndpoints( packageName: String = "com.mypackage" ): MetaEndpoints = MetaEndpoints(this, packageName) \ No newline at end of file diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/metrics/Metrics.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/metrics/Metrics.kt index 3ceecece..4391e1bc 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/metrics/Metrics.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/metrics/Metrics.kt @@ -79,7 +79,7 @@ interface Metrics: HealthCheckable { } suspend fun addToSumPerHandler(type: MetricType, value: Double) { - coroutineContext[ServerEntryPointElement.Key]?.metricSums?.compute(type) { key, it -> (it ?: 0.0) + value } + coroutineContext[ServerEntryPointElement.Key]?.metricSums?.compute(type) { _, it -> (it ?: 0.0) + value } } suspend fun addPerformanceToSumPerHandler(type: MetricType, countType: MetricType? = null, action: suspend () -> T): T { diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/CsvFormat.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/CsvFormat.kt index ecb8dd68..af8be6b4 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/CsvFormat.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/CsvFormat.kt @@ -126,7 +126,7 @@ class CsvFormat(val stringDeferringConfig: StringDeferringConfig, val csvConfig: ) ) - else -> decodeSequence(deserializer, string.iterator()).single() + else -> decodeToSequence(string.iterator(), deserializer).single() } } @@ -138,7 +138,7 @@ class CsvFormat(val stringDeferringConfig: StringDeferringConfig, val csvConfig: ) ) - else -> decodeSequence(deserializer, reader.iterator()).single() + else -> decodeToSequence(reader.iterator(), deserializer).single() } } diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/Serialization.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/Serialization.kt index cb89461d..222ecfb4 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/Serialization.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/Serialization.kt @@ -30,6 +30,8 @@ import nl.adaptivity.xmlutil.serialization.XML import java.math.BigDecimal import kotlinx.datetime.* import kotlinx.serialization.* +import nl.adaptivity.xmlutil.ExperimentalXmlUtilApi +import nl.adaptivity.xmlutil.serialization.XmlSerializationPolicy import java.util.* import kotlin.collections.HashMap @@ -98,9 +100,6 @@ abstract class Serialization { } var xml: XML by SetOnce { XML(module) { - this.unknownChildHandler = UnknownChildHandler { input, inputKind, descriptor, name, candidates -> - emptyList() - } this.xmlDeclMode = XmlDeclMode.Auto this.repairNamespaces = true } diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/StringDeferringDecoder.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/StringDeferringDecoder.kt index 546e888b..db3b3de0 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/StringDeferringDecoder.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/StringDeferringDecoder.kt @@ -11,7 +11,7 @@ import kotlinx.serialization.modules.SerializersModule @OptIn(InternalSerializationApi::class) -public class StringDeferringDecoder( +class StringDeferringDecoder( val config: StringDeferringConfig, val descriptor: SerialDescriptor, val map: Map, @@ -88,17 +88,13 @@ public class StringDeferringDecoder( val v = map[tag] return (v != config.nullMarker && v?.lowercase() != "false") || map.keys.any { it.startsWith(tag + ".") } } - fun decodeTaggedNull(tag: String): Nothing? = null - fun decodeTaggedInline(tag: String, inlineDescriptor: SerialDescriptor): Decoder = this.apply { pushTag(tag) } - - fun decodeSerializableValue(deserializer: DeserializationStrategy, previousValue: T?): T = - decodeSerializableValue(deserializer) + fun decodeTaggedInline(tag: String): Decoder = this.apply { pushTag(tag) } // ---- Implementation of low-level API ---- override fun decodeInline(descriptor: SerialDescriptor): Decoder = - decodeTaggedInline(popTag(), descriptor) + decodeTaggedInline(popTag()) override fun decodeNotNullMark(): Boolean { // String might be null for top-level deserialization @@ -150,7 +146,7 @@ public class StringDeferringDecoder( override fun decodeInlineElement( descriptor: SerialDescriptor, index: Int - ): Decoder = decodeTaggedInline(descriptor.getTag(index), descriptor.getElementDescriptor(index)) + ): Decoder = decodeTaggedInline(descriptor.getTag(index)) private fun useDefer( sub: String, @@ -176,7 +172,7 @@ public class StringDeferringDecoder( throw SerializationException("${errorContext()}Failed to parse key $sub '$withoutPrefix' as a ${descriptor.getElementDescriptor(index).serialName}: ${e.message}", e) } } else { - return tagBlock(descriptor.getTag(index)) { decodeSerializableValue(deserializer, previousValue) } + return tagBlock(descriptor.getTag(index)) { decodeSerializableValue(deserializer) } } } @@ -198,8 +194,7 @@ public class StringDeferringDecoder( return tagBlock(descriptor.getTag(index)) { val isNullabilitySupported = deserializer.descriptor.isNullable if (isNullabilitySupported || decodeNotNullMark()) decodeSerializableValue( - deserializer, - previousValue + deserializer ) else decodeNull() } } @@ -216,8 +211,6 @@ public class StringDeferringDecoder( } private val tagStack = arrayListOf() - private val currentTag: String - get() = tagStack.last() private val currentTagOrNull: String? get() = tagStack.lastOrNull() diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/StringDeferringEncoder.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/StringDeferringEncoder.kt index 61bc3a23..223a1962 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/StringDeferringEncoder.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/StringDeferringEncoder.kt @@ -23,7 +23,7 @@ public class StringDeferringEncoder( fun headers(root: SerialDescriptor): List = buildList { assert(steadyHeaders) - var visited = HashSet() + val visited = HashSet() fun sub(descriptor: SerialDescriptor, prefix: String = "") { if(!visited.add(descriptor.serialName.removeSuffix("?"))) return for (i in 0 until descriptor.elementsCount) { @@ -53,8 +53,7 @@ public class StringDeferringEncoder( sub(root) } - @Suppress("UNCHECKED_CAST") - final override fun encodeSerializableValue(serializer: SerializationStrategy, value: T) { + override fun encodeSerializableValue(serializer: SerializationStrategy, value: T) { when(serializer.descriptor.kind) { PolymorphicKind.SEALED, PolymorphicKind.OPEN, @@ -89,7 +88,7 @@ public class StringDeferringEncoder( // ---- API ---- - fun encodeTaggedNonNullMark(tag: String) {} + fun encodeTaggedNonNullMark() {} fun encodeTaggedInt(tag: String, value: Int): Unit = encodeTaggedValue(tag, value) fun encodeTaggedByte(tag: String, value: Byte): Unit = encodeTaggedValue(tag, value) fun encodeTaggedShort(tag: String, value: Short): Unit = encodeTaggedValue(tag, value) @@ -100,11 +99,11 @@ public class StringDeferringEncoder( fun encodeTaggedChar(tag: String, value: Char): Unit = encodeTaggedValue(tag, value) fun encodeTaggedString(tag: String, value: String): Unit = encodeTaggedValue(tag, if(value.startsWith(config.deferMarker)) config.deferMarker + config.deferredFormat.encodeToString(String.serializer(), value) else value) - fun encodeTaggedInline(tag: String, inlineDescriptor: SerialDescriptor): Encoder = + fun encodeTaggedInline(tag: String): Encoder = this.apply { pushTag(tag) } override fun encodeInline(descriptor: SerialDescriptor): Encoder = - encodeTaggedInline(popTag(), descriptor) + encodeTaggedInline(popTag()) // ---- Implementation of low-level API ---- @@ -114,7 +113,7 @@ public class StringDeferringEncoder( return true } - override fun encodeNotNullMark(): Unit = encodeTaggedNonNullMark(currentTag) + override fun encodeNotNullMark(): Unit = encodeTaggedNonNullMark() override fun encodeNull(): Unit = encodeTaggedNull(popTag()) override fun encodeBoolean(value: Boolean): Unit = encodeTaggedBoolean(popTag(), value) override fun encodeByte(value: Byte): Unit = encodeTaggedByte(popTag(), value) @@ -137,14 +136,8 @@ public class StringDeferringEncoder( if (tagStack.isNotEmpty()) { popTag() } - endEncode(descriptor) } - /** - * Format-specific replacement for [endStructure], because latter is overridden to manipulate tag stack. - */ - fun endEncode(descriptor: SerialDescriptor) {} - override fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean): Unit = encodeTaggedBoolean(descriptor.getTag(index), value) @@ -176,7 +169,7 @@ public class StringDeferringEncoder( descriptor: SerialDescriptor, index: Int ): Encoder { - return encodeTaggedInline(descriptor.getTag(index), descriptor.getElementDescriptor(index)) + return encodeTaggedInline(descriptor.getTag(index)) } override fun encodeSerializableElement( @@ -203,8 +196,6 @@ public class StringDeferringEncoder( private val seenStack = arrayListOf() private val tagStack = arrayListOf() - private val currentTag: String - get() = tagStack.last() private val currentTagOrNull: String? get() = tagStack.lastOrNull() diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/primitives.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/primitives.kt index 05a2da4b..d8052076 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/primitives.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/primitives.kt @@ -11,6 +11,7 @@ import kotlinx.serialization.json.decodeFromJsonElement import kotlinx.serialization.json.jsonPrimitive fun Json.encodeUnwrappingString(serializer: KSerializer, value: T): String { + @Suppress("UNCHECKED_CAST") val fullSerializer = if(serializer is ContextualSerializer<*>) serializersModule.getContextual(serializer.descriptor.capturedKClass!!) as KSerializer else serializer return when { fullSerializer.descriptor.kind == PrimitiveKind.STRING && !fullSerializer.descriptor.isNullable -> encodeToJsonElement( @@ -24,6 +25,7 @@ fun Json.encodeUnwrappingString(serializer: KSerializer, value: T): Strin @Suppress("UNCHECKED_CAST") fun Json.decodeUnwrappingString(serializer: KSerializer, value: String): T { + @Suppress("UNCHECKED_CAST") val fullSerializer = if(serializer is ContextualSerializer<*>) serializersModule.getContextual(serializer.descriptor.capturedKClass!!) as KSerializer else serializer return when { fullSerializer.descriptor.kind == PrimitiveKind.STRING && !fullSerializer.descriptor.isNullable -> decodeFromJsonElement( diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/transformations.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/transformations.kt index 97a883f7..e3e9b5c3 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/transformations.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/serialization/transformations.kt @@ -1,6 +1,5 @@ package com.lightningkite.lightningserver.serialization -import com.lightningkite.khrysalis.fatalError import com.lightningkite.lightningserver.core.ContentType import com.lightningkite.lightningserver.exceptions.BadRequestException import com.lightningkite.lightningserver.http.HttpContent diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/tasks/dsl.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/tasks/dsl.kt index a2aeb1f3..1c545882 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/tasks/dsl.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/tasks/dsl.kt @@ -67,7 +67,7 @@ suspend fun doOnce( name: String, database: () -> Database, maxDuration: Duration = 60.seconds, - priority: Double = 0.0, + @Suppress("UNUSED_PARAMETER") priority: Double = 0.0, action: suspend () -> Unit, ) { prepareModels() diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.kt index 2bef8754..90a17f86 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.kt @@ -40,7 +40,7 @@ data class ApiEndpoint?, PATH: TypedServerPath, INPUT, OUTPUT>( parts = route.path.serializers.mapIndexed { idx, ser -> val name = wildcards.get(idx).name val str = request.parts[name] ?: throw BadRequestException("Route segment $name not found") - str.parseUrlPartOrBadRequest(route.path.serializers[idx]) + str.parseUrlPartOrBadRequest(ser) }.toTypedArray() ).also { authOptions.assert(it.authOrNull) @@ -53,7 +53,7 @@ data class ApiEndpoint?, PATH: TypedServerPath, INPUT, OUTPUT>( else -> if (inputType == Unit.serializer()) Unit as INPUT else it.body?.parse(inputType) ?: throw BadRequestException("No request body provided") } Serialization.validateOrThrow(inputType, input) - @Suppress("UNCHECKED_CAST") val result = authAndPathParts(auth, it).implementation(input) + val result = authAndPathParts(auth, it).implementation(input) return HttpResponse( body = result.toHttpContent(it.headers.accept, outputType), status = successCode diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.old.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.old.kt index a3de95e4..0c7fc1e5 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.old.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.old.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.lightningkite.lightningserver.typed import kotlin.time.Duration @@ -28,7 +30,7 @@ inline fun HttpEndpoint.type successCode: HttpStatus = HttpStatus.OK, crossinline implementation: suspend (user: USER, input: INPUT) -> OUTPUT ) = typed( - authOptions = if (USER::class == kotlin.Unit::class) com.lightningkite.lightningserver.auth.noAuth else AuthOptions?>( + authOptions = if (USER::class == Unit::class) noAuth else AuthOptions?>( buildSet { val type = typeOf() if (type.isMarkedNullable) add(null) @@ -82,6 +84,7 @@ fun HttpEndpoint.typed( examples = examples, successCode = successCode, implementation = { input: INPUT -> + @Suppress("UNCHECKED_CAST") implementation(if(authOptions == noAuth) Unit as USER else this.user() as USER, input) } ) @@ -102,7 +105,7 @@ inline fun Htt successCode: HttpStatus = HttpStatus.OK, crossinline implementation: suspend (user: USER, route: PATH, input: INPUT) -> OUTPUT ) = typed( - authOptions = if (USER::class == kotlin.Unit::class) com.lightningkite.lightningserver.auth.noAuth else AuthOptions?>( + authOptions = if (USER::class == Unit::class) noAuth else AuthOptions( buildSet { val type = typeOf() if (type.isMarkedNullable) add(null) @@ -157,6 +160,7 @@ fun HttpEndpoint.typed( examples = examples, successCode = successCode, implementation = { input: INPUT -> + @Suppress("UNCHECKED_CAST") implementation(this.user() as USER, this.path1, input) } ) @@ -177,7 +181,7 @@ inline fun OUTPUT ) = typed( - authOptions = if (USER::class == kotlin.Unit::class) com.lightningkite.lightningserver.auth.noAuth else AuthOptions?>( + authOptions = if (USER::class == Unit::class) noAuth else AuthOptions?>( buildSet { val type = typeOf() if (type.isMarkedNullable) add(null) @@ -243,6 +247,7 @@ fun , USER : USERNN?, PATH, PATH2, INPUT : Any, OUTPUT> HttpEn examples = examples, successCode = successCode, implementation = { input -> + @Suppress("UNCHECKED_CAST") implementation(this.user() as USER, this.path1, path2, input) } ) \ No newline at end of file diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.testing.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.testing.kt index 20699945..7c79a9bd 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.testing.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiEndpoint.testing.kt @@ -7,25 +7,23 @@ suspend inline fun ?, reified INPUT, reified OUTPUT> ApiE authenticatedAs: USER, input: INPUT ): OUTPUT = implementation( - AuthAndPathParts.test(path as TypedServerPath0, user = authenticatedAs), + AuthAndPathParts.test(user = authenticatedAs), input ) -@Suppress("UNCHECKED_CAST") suspend inline fun ?, reified INPUT, reified OUTPUT, PATH1> ApiEndpoint, INPUT, OUTPUT>.test( authenticatedAs: USER, path1: PATH1, input: INPUT, ): OUTPUT = implementation( - AuthAndPathParts.test(path as TypedServerPath1, user = authenticatedAs, path1 = path1), + AuthAndPathParts.test(user = authenticatedAs, path1 = path1), input ) -@Suppress("UNCHECKED_CAST") suspend inline fun ?, reified INPUT, reified OUTPUT, PATH1, PATH2> ApiEndpoint, INPUT, OUTPUT>.test( authenticatedAs: USER, path1: PATH1, path2: PATH2, input: INPUT, ): OUTPUT = implementation( - AuthAndPathParts.test(path as TypedServerPath2, user = authenticatedAs, path1 = path1, path2 = path2), + AuthAndPathParts.test(user = authenticatedAs, path1 = path1, path2 = path2), input ) \ No newline at end of file diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiWebsocket.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiWebsocket.kt index ba660afe..14048e77 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiWebsocket.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/ApiWebsocket.kt @@ -45,7 +45,7 @@ data class ApiWebsocket?, PATH: TypedServerPath, INPUT, OUTPUT>( parts = path.serializers.mapIndexed { idx, ser -> val name = wildcards.get(idx).name val str = event.parts[name] ?: throw BadRequestException("Route segment $name not found") - str.parseUrlPartOrBadRequest(path.serializers[idx]) + str.parseUrlPartOrBadRequest(ser) }.toTypedArray(), event = event, outputSerializer = outputType, diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/AuthAndPathParts.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/AuthAndPathParts.kt index 866daa73..b837187e 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/AuthAndPathParts.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/AuthAndPathParts.kt @@ -28,9 +28,9 @@ open class AuthAndPathParts?, PATH: TypedServerPath>( val parts: Array ): AuthAccessor(authOrNull, rawRequest) { companion object { - fun ?> test(path: TypedServerPath0, user: USER, scopes: Set = setOf("*"), thirdParty: String? = null) = AuthAndPathParts(RequestAuth.test(user, scopes, thirdParty), null, arrayOf()) - fun ?, P1> test(path: TypedServerPath1, user: USER, path1: P1, scopes: Set = setOf("*"), thirdParty: String? = null) = AuthAndPathParts>(RequestAuth.test(user, scopes, thirdParty), null, arrayOf(path1)) - fun ?, P1, P2> test(path: TypedServerPath2, user: USER, path1: P1, path2: P2, scopes: Set = setOf("*"), thirdParty: String? = null) = AuthAndPathParts>(RequestAuth.test(user, scopes, thirdParty), null, arrayOf(path1, path2)) + fun ?> test(user: USER, scopes: Set = setOf("*"), thirdParty: String? = null) = AuthAndPathParts(RequestAuth.test(user, scopes, thirdParty), null, arrayOf()) + fun ?, P1> test(user: USER, path1: P1, scopes: Set = setOf("*"), thirdParty: String? = null) = AuthAndPathParts>(RequestAuth.test(user, scopes, thirdParty), null, arrayOf(path1)) + fun ?, P1, P2> test(user: USER, path1: P1, path2: P2, scopes: Set = setOf("*"), thirdParty: String? = null) = AuthAndPathParts>(RequestAuth.test(user, scopes, thirdParty), null, arrayOf(path1, path2)) } } diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/DartSdk.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/DartSdk.kt index 7bb7e294..835ddbf3 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/DartSdk.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/DartSdk.kt @@ -62,7 +62,7 @@ fun Documentable.Companion.dartSdk(fileName: String, out: Appendable) = with(out append(" ") it.write().let { out.append(it) } append("({") - (it as? GeneratedSerializer<*>)?.childSerializers()?.forEachIndexed { index, sub -> + (it as? GeneratedSerializer<*>)?.childSerializers()?.forEachIndexed { index, _ -> append("required this.") append(it.descriptor.getElementName(index).filter { it.isLetterOrDigit() }) append(",") diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/SDK.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/SDK.kt index 1d6fe6aa..9f1aafc6 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/SDK.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/SDK.kt @@ -270,7 +270,7 @@ private val Documentable.Companion.safeDocumentables .distinctBy { it.docGroupIdentifier.toString() + "/" + it.summary } private class CodeEmitter(val packageName: String, val body: StringBuilder = StringBuilder()) : Appendable by body { - val imports = mutableSetOf("com.lightningkite.khrysalis.SharedCode") + val imports = mutableSetOf() fun append(type: KType) { imports.add(type.toString().substringBefore('<').removeSuffix("?")) body.append((type.classifier as? KClass<*>)?.simpleName) @@ -287,7 +287,7 @@ private class CodeEmitter(val packageName: String, val body: StringBuilder = Str } fun dump(to: Appendable) = with(to) { - appendLine("@file:SharedCode") + appendLine("") appendLine("package $packageName") appendLine() imports diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/autodoc.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/autodoc.kt index 641f66b7..0ce199b6 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/autodoc.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/autodoc.kt @@ -56,9 +56,8 @@ fun ServerPath.apiDocs(packageName: String = "com.mypackage"): HttpEndpoint { ) ) } - return this.copy(after = ServerPath.Afterwards.TrailingSlash).get.handler { request -> - val rootRoute = this - HttpResponse(body = HttpContent.Html { + return this.copy(after = ServerPath.Afterwards.TrailingSlash).get.handler { _ -> + HttpResponse(body = HttpContent.html { head { title("${generalSettings().projectName} - Generated Documentation") } body { h1 { +"API Docs" } @@ -293,5 +292,3 @@ private fun FlowContent.type(type: KSerializer<*>) { } } } - -private fun FlowContent.type(type: KType) = type(Serialization.json.serializersModule.serializer(type)) \ No newline at end of file diff --git a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/autoform.kt b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/autoform.kt index fa7250e9..62defe8b 100644 --- a/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/autoform.kt +++ b/server-core/src/main/kotlin/com/lightningkite/lightningserver/typed/autoform.kt @@ -58,7 +58,7 @@ fun FORM.insideHtmlForm( serializer: KSerializer, defaultValue: T? = null, collapsed: Boolean = false, - uploadEarlyEndpoint: UploadEarlyEndpoint? = UploadEarlyEndpoint.default, + @Suppress("UNUSED_PARAMETER") uploadEarlyEndpoint: UploadEarlyEndpoint? = UploadEarlyEndpoint.default, ): Unit { this.encType = FormEncType.multipartFormData input(InputType.hidden, name = "__json") { diff --git a/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDatabase.kt b/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDatabase.kt index b26c611c..a5de00f1 100644 --- a/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDatabase.kt +++ b/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDatabase.kt @@ -16,6 +16,7 @@ import kotlin.reflect.KType class DynamoDatabase(val dynamo: DynamoDbAsyncClient): Database { private val collections = ConcurrentHashMap, String>, Lazy>>() + @Suppress("UNCHECKED_CAST") override fun collection(serializer: KSerializer, name: String): DynamoDbCollection = (collections.getOrPut(serializer to name) { lazy(LazyThreadSafetyMode.SYNCHRONIZED) { @@ -25,7 +26,6 @@ class DynamoDatabase(val dynamo: DynamoDbAsyncClient): Database { name ).also { runBlocking { - @Suppress("OPT_IN_USAGE") it.prepare() } } diff --git a/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbCache.kt b/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbCache.kt index 9499b327..a0b5a1a4 100644 --- a/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbCache.kt +++ b/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbCache.kt @@ -135,7 +135,7 @@ class DynamoDbCache(val makeClient: () -> DynamoDbAsyncClient, val tableName: St ): Boolean { ready.await() try { - val r = client.putItem { + client.putItem { it.tableName(tableName) it.expressionAttributeNames(mapOf("#k" to "key")) it.conditionExpression("attribute_not_exists(#k)") diff --git a/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbCollection.kt b/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbCollection.kt index 8df0a001..d1a878cc 100644 --- a/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbCollection.kt +++ b/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbCollection.kt @@ -18,6 +18,7 @@ class DynamoDbCollection( val tableName: String, ) : FieldCollection { + @Suppress("UNCHECKED_CAST") val idSerializer = serializer.serializableProperties!!.find { it.name == "_id" }!!.serializer as KSerializer suspend fun findRaw( @@ -108,7 +109,7 @@ class DynamoDbCollection( val c = condition.dynamo(serializer, "_id") if (c.never) return emptyFlow() val exactKey = condition.exactPrimaryKey() - if (exactKey != null && idSerializer != null) { + if (exactKey != null) { return flowOf(action(c, mapOf("_id" to idSerializer.toDynamo(exactKey)))) } else { return findRaw(condition = condition, limit = limit).map { @@ -169,7 +170,7 @@ class DynamoDbCollection( var changed = 0 val m = modification.dynamo(serializer) perKey(condition) { c, key -> - val result = client.updateItem { + client.updateItem { it.tableName(tableName) it.apply(c, m) it.key(key) @@ -218,7 +219,7 @@ class DynamoDbCollection( override suspend fun deleteManyIgnoringOld(condition: Condition): Int { var changed = 0 perKey(condition) { c, key -> - val result = client.deleteItem { + client.deleteItem { it.tableName(tableName) it.apply(c) it.key(key) diff --git a/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbQueryBuilder.kt b/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbQueryBuilder.kt index bd3394b3..b2c1bc67 100644 --- a/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbQueryBuilder.kt +++ b/server-dynamodb/src/main/kotlin/com/lightningkite/lightningserver/db/DynamoDbQueryBuilder.kt @@ -1,6 +1,5 @@ package com.lightningkite.lightningserver.db -import com.lightningkite.khrysalis.IsCodableAndHashable import com.lightningkite.lightningdb.* import kotlinx.serialization.KSerializer import kotlinx.serialization.builtins.ListSerializer @@ -263,7 +262,7 @@ fun Condition.dynamo(serializer: KSerializer, sortKey: String): Dynamo is Condition.OnField<*, *> -> { @Suppress("UNCHECKED_CAST") val inner = - (condition as Condition).dynamo(key.serializer as KSerializer, sortKey) + (condition as Condition).dynamo(key.serializer as KSerializer, sortKey) val indexed = key.name == sortKey if (indexed) { DynamoCondition( @@ -370,7 +369,7 @@ fun Modification.dynamo(serializer: KSerializer): DynamoModification -> { @Suppress("UNCHECKED_CAST") val inner = - (modification as Modification).dynamo(key.serializer as KSerializer) + (modification as Modification).dynamo(key.serializer as KSerializer) DynamoModification( local = (this as Modification).takeIf { inner.local != null }, set = inner.set.map { @@ -417,6 +416,7 @@ fun Modification.dynamo(serializer: KSerializer): DynamoModification>) filter.append(")") }) @@ -428,11 +428,13 @@ fun Modification.dynamo(serializer: KSerializer): DynamoModification -> DynamoModification(add = listOf { key(field) + @Suppress("UNCHECKED_CAST") value(this@dynamo.items, serializer as KSerializer>) }) is Modification.SetRemoveInstances<*> -> DynamoModification(delete = listOf { key(field) + @Suppress("UNCHECKED_CAST") value(this@dynamo.items, serializer as KSerializer>) }) diff --git a/server-firebase/src/main/kotlin/com/lightningkite/lightningserver/notifications/FcmNotificationClient.kt b/server-firebase/src/main/kotlin/com/lightningkite/lightningserver/notifications/FcmNotificationClient.kt index 83f86a3b..8d41387c 100644 --- a/server-firebase/src/main/kotlin/com/lightningkite/lightningserver/notifications/FcmNotificationClient.kt +++ b/server-firebase/src/main/kotlin/com/lightningkite/lightningserver/notifications/FcmNotificationClient.kt @@ -156,11 +156,11 @@ object FcmNotificationClient : NotificationClient { val result = FirebaseMessaging.getInstance().sendEachForMulticast(it) result.responses.forEachIndexed { index, sendResponse -> println("Send $index: ${sendResponse.messageId} / ${sendResponse.exception?.message} ${sendResponse.exception?.messagingErrorCode}") - results[targets[index]] = when(val it = sendResponse.exception?.messagingErrorCode) { + results[targets[index]] = when(val errorCode = sendResponse.exception?.messagingErrorCode) { null -> NotificationSendResult.Success MessagingErrorCode.UNREGISTERED -> NotificationSendResult.DeadToken else -> { - errorCodes.add(it) + errorCodes.add(errorCode) NotificationSendResult.Failure } } diff --git a/server-ktor/src/main/kotlin/com/lightningkite/lightningserver/ktor/ktor.kt b/server-ktor/src/main/kotlin/com/lightningkite/lightningserver/ktor/ktor.kt index 72473ed5..63c77d19 100644 --- a/server-ktor/src/main/kotlin/com/lightningkite/lightningserver/ktor/ktor.kt +++ b/server-ktor/src/main/kotlin/com/lightningkite/lightningserver/ktor/ktor.kt @@ -47,7 +47,6 @@ import kotlin.time.Duration.Companion.hours import com.lightningkite.lightningserver.core.ContentType as HttpContentType fun Application.lightningServer(pubSub: PubSub, cache: Cache) { - val logger = LoggerFactory.getLogger("com.lightningkite.lightningserver.ktor.lightningServer") val myEngine = LocalEngine(cache) engine = myEngine try { @@ -126,7 +125,7 @@ fun Application.lightningServer(pubSub: PubSub, cache: Cache) { queryParameters = call.request.queryParameters.flattenEntries(), id = id, headers = call.request.headers.adapt(), - domain = call.request.origin.host, + domain = call.request.origin.serverHost, protocol = call.request.origin.scheme, sourceIp = call.request.origin.remoteHost, cache = cache diff --git a/server-memcached/src/main/kotlin/com/lightningkite/lightningserver/cache/MemcachedCache.kt b/server-memcached/src/main/kotlin/com/lightningkite/lightningserver/cache/MemcachedCache.kt index bde12695..57ffdd8e 100644 --- a/server-memcached/src/main/kotlin/com/lightningkite/lightningserver/cache/MemcachedCache.kt +++ b/server-memcached/src/main/kotlin/com/lightningkite/lightningserver/cache/MemcachedCache.kt @@ -51,11 +51,11 @@ class MemcachedCache(val client: MemcachedClient) : Cache, HealthCheckable { override suspend fun set(key: String, value: T, serializer: KSerializer, timeToLive: Duration?) = withContext(Dispatchers.IO) { - val succeed = client.set( + if(!client.set( key, timeToLive?.inWholeSeconds?.toInt() ?: Int.MAX_VALUE, Serialization.Internal.json.encodeToString(serializer, value) - ) + )) throw IllegalStateException("Failed to set") Unit } diff --git a/server-mongo/src/main/kotlin/com/lightningkite/lightningdb/MongoDatabase.kt b/server-mongo/src/main/kotlin/com/lightningkite/lightningdb/MongoDatabase.kt index a62b065f..f7dc0a97 100644 --- a/server-mongo/src/main/kotlin/com/lightningkite/lightningdb/MongoDatabase.kt +++ b/server-mongo/src/main/kotlin/com/lightningkite/lightningdb/MongoDatabase.kt @@ -160,7 +160,6 @@ class MongoDatabase(val databaseName: String, private val makeClient: () -> Mong } catch(e: Exception) { throw e } - throw Exception() } }) } diff --git a/server-mongo/src/main/kotlin/com/lightningkite/lightningdb/bson.kt b/server-mongo/src/main/kotlin/com/lightningkite/lightningdb/bson.kt index 5a11577c..e917475a 100644 --- a/server-mongo/src/main/kotlin/com/lightningkite/lightningdb/bson.kt +++ b/server-mongo/src/main/kotlin/com/lightningkite/lightningdb/bson.kt @@ -3,7 +3,6 @@ package com.lightningkite.lightningdb import com.github.jershell.kbson.* import com.lightningkite.GeoCoordinate import com.lightningkite.GeoCoordinateGeoJsonSerializer -import com.lightningkite.khrysalis.IsCodableAndHashable import com.lightningkite.lightningdb.* import com.lightningkite.lightningserver.serialization.Serialization import com.mongodb.client.model.UpdateOptions @@ -52,6 +51,7 @@ fun KBson.stringifyAny(serializer: KSerializer, obj: T): BsonValue { } +@Suppress("UNCHECKED_CAST") private fun Condition.dump(serializer: KSerializer, into: Document = Document(), key: String?): Document { when (this) { is Condition.Always -> {} @@ -111,6 +111,7 @@ private fun Condition.dump(serializer: KSerializer, into: Document = D return into } +@Suppress("UNCHECKED_CAST") private fun Modification.dump(serializer: KSerializer, update: UpdateWithOptions = UpdateWithOptions(), key: String?): UpdateWithOptions { val into = update.document when(this) { diff --git a/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/ConditionMapping.kt b/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/ConditionMapping.kt index 72307dd9..4b007711 100644 --- a/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/ConditionMapping.kt +++ b/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/ConditionMapping.kt @@ -12,19 +12,25 @@ import com.lightningkite.lightningdb.SerializableProperty internal data class FieldSet2(val serializer: KSerializer, val fields: Map>) { constructor(serializer: KSerializer, table: SerialDescriptorTable) : this( serializer = serializer, - fields = table.col.mapValues { it.value as ExpressionWithColumnType } + fields = table.col.mapValues { + @Suppress("UNCHECKED_CAST") + it.value as ExpressionWithColumnType + } ) val single: ExpressionWithColumnType get() = fields[""] ?: throw IllegalStateException("No column found for ${serializer.descriptor.serialName}") fun single(value: V): Pair, Expression> = single to LiteralOp(single.columnType, formatSingle(value)) + @Suppress("UNCHECKED_CAST") fun sub(property: SerializableProperty) = FieldSet2( serializer = property.serializer as KSerializer, fields = fields.filter { it.key == property.name || it.key.startsWith(property.name + "__") } .mapKeys { it.key.substringAfter(property.name).removePrefix("__") } ) + @Suppress("UNCHECKED_CAST") val exists: Expression get() = fields["exists"]?.let { it as Expression } ?: IsNotNullOp(fields.values.first()) + @Suppress("UNCHECKED_CAST") val notExists: Expression get() = fields["exists"]?.let { NotOp(it as Expression) diff --git a/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/DbMapLikeFormat.kt b/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/DbMapLikeFormat.kt index e7f50cc1..66f640ee 100644 --- a/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/DbMapLikeFormat.kt +++ b/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/DbMapLikeFormat.kt @@ -30,7 +30,10 @@ import kotlin.time.toKotlinDuration class DbMapLikeFormat(val serializersModule: SerializersModule = Serialization.module) { fun encode(serializer: KSerializer, value: T, it: UpdateBuilder<*>, path: List = listOf("")) { - val columns = it.targets.flatMap { it.columns }.map { it as Column }.associateBy { it.name } + val columns = it.targets.flatMap { it.columns }.map { + @Suppress("UNCHECKED_CAST") + it as Column + }.associateBy { it.name } DbLikeMapEncoder( serializersModule, { k, v -> @@ -59,7 +62,10 @@ class DbMapLikeFormat(val serializersModule: SerializersModule = Serialization.m } fun decode(serializer: KSerializer, map: ResultRow, path: List = listOf("")): T { - val columns = map.fieldIndex.keys.mapNotNull { it as? Column }.associateBy { it.name } + val columns = map.fieldIndex.keys.mapNotNull { + @Suppress("UNCHECKED_CAST") + it as? Column + }.associateBy { it.name } return DbLikeMapDecoder( serializersModule, keys = columns.keys, @@ -150,7 +156,7 @@ class DbLikeMapDecoder( return CompositeDecoder.DECODE_DONE } - final override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder { + override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder { return when (descriptor.kind) { is StructureKind.CLASS -> DbLikeMapDecoder( serializersModule, @@ -205,6 +211,7 @@ class DbLikeMapDecoder( } override fun decodeSerializableValue(deserializer: DeserializationStrategy): T { + @Suppress("UNCHECKED_CAST") return when ((deserializer as? KSerializer)?.nullElement() ?: deserializer) { UUIDSerializer -> getter(popTag()) as T LocalDateIso8601Serializer -> getter(popTag()).let { it as LocalDate }.toKotlinLocalDate() as T @@ -424,7 +431,7 @@ class DbLikeMapEncoder( when ((serializer as? KSerializer)?.nullElement() ?: serializer) { UUIDSerializer -> writer(popTag(), value) LocalDateIso8601Serializer -> writer(popTag(), (value as kotlinx.datetime.LocalDate).toJavaLocalDate()) - InstantIso8601Serializer -> writer(popTag(), (value as kotlinx.datetime.Instant).toJavaInstant()) + InstantIso8601Serializer -> writer(popTag(), (value as Instant).toJavaInstant()) DurationSerializer -> writer(popTag(), (value as kotlin.time.Duration).toJavaDuration()) //LocalDateTimeSerializer -> writer(popTag(), value) LocalDateTimeIso8601Serializer -> writer(popTag(), (value as kotlinx.datetime.LocalDateTime).toJavaLocalDateTime()) diff --git a/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/PostgresCollection.kt b/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/PostgresCollection.kt index 6d4dc8a3..65ca5501 100644 --- a/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/PostgresCollection.kt +++ b/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/PostgresCollection.kt @@ -48,8 +48,15 @@ class PostgresCollection( prepare.await() val items = t { table - .select { condition(condition, serializer, table).asOp() } - .orderBy(*orderBy.map { (if (it.ignoreCase && it.field.serializerAny.descriptor.kind == PrimitiveKind.STRING) (table.col[it.field.colName]!! as Column).lowerCase() else table.col[it.field.colName]!!) to if (it.ascending) SortOrder.ASC else SortOrder.DESC } + .selectAll() + .where { condition(condition, serializer, table).asOp() } + .orderBy(*orderBy.map { + @Suppress("UNCHECKED_CAST") + ( + if (it.ignoreCase && it.field.serializerAny.descriptor.kind == PrimitiveKind.STRING) + (table.col[it.field.colName]!! as Column).lowerCase() + else table.col[it.field.colName]!! + ) to if (it.ascending) SortOrder.ASC else SortOrder.DESC } .toTypedArray()) .limit(limit, skip.toLong()) // .prep @@ -62,7 +69,7 @@ class PostgresCollection( prepare.await() return t { table - .select { condition(condition, serializer, table).asOp() } + .selectAll().where { condition(condition, serializer, table).asOp() } .count().toInt() } } @@ -70,10 +77,11 @@ class PostgresCollection( override suspend fun groupCount(condition: Condition, groupBy: DataClassPath): Map { prepare.await() return t { + @Suppress("UNCHECKED_CAST") val groupCol = table.col[groupBy.colName] as Column val count = Count(stringLiteral("*")) - table.slice(groupCol, count) - .select { condition(condition, serializer, table).asOp() } + table.select(groupCol, count) + .where { condition(condition, serializer, table).asOp() } .groupBy(table.col[groupBy.colName]!!).associate { it[groupCol] to it[count].toInt() } } } @@ -85,6 +93,7 @@ class PostgresCollection( ): Double? { prepare.await() return t { + @Suppress("UNCHECKED_CAST") val valueCol = table.col[property.colName] as Column val agg = when (aggregate) { Aggregate.Sum -> Sum(valueCol, DecimalColumnType(Int.MAX_VALUE, 8)) @@ -92,8 +101,8 @@ class PostgresCollection( Aggregate.StandardDeviationSample -> StdDevSamp(valueCol, 8) Aggregate.StandardDeviationPopulation -> StdDevPop(valueCol, 8) } - table.slice(agg) - .select { condition(condition, serializer, table).asOp() } + table.select(agg) + .where { condition(condition, serializer, table).asOp() } .firstOrNull()?.get(agg)?.toDouble() } } @@ -106,7 +115,9 @@ class PostgresCollection( ): Map { prepare.await() return t { + @Suppress("UNCHECKED_CAST") val groupCol = table.col[groupBy.colName] as Column + @Suppress("UNCHECKED_CAST") val valueCol = table.col[property.colName] as Column val agg = when (aggregate) { Aggregate.Sum -> Sum(valueCol, DoubleColumnType()) @@ -114,8 +125,8 @@ class PostgresCollection( Aggregate.StandardDeviationSample -> StdDevSamp(valueCol, 8) Aggregate.StandardDeviationPopulation -> StdDevPop(valueCol, 8) } - table.slice(groupCol, agg) - .select { condition(condition, serializer, table).asOp() } + table.select(groupCol, agg) + .where { condition(condition, serializer, table).asOp() } .groupBy(table.col[groupBy.colName]!!).associate { it[groupCol] to it[agg]?.toDouble() } } } diff --git a/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/arraySupport.kt b/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/arraySupport.kt index eb35cee5..9c582963 100644 --- a/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/arraySupport.kt +++ b/server-postgresql/src/main/kotlin/com/lightningkite/lightningserver/db/arraySupport.kt @@ -144,6 +144,7 @@ internal class MapOp( val filter: (FieldSet2) -> Expression = { Op.TRUE }, ): Op>() { override fun toQueryBuilder(queryBuilder: QueryBuilder) { + @Suppress("UNCHECKED_CAST") val fs = FieldSet2( sources.serializer.listElement()!! as KSerializer, fields = sources.fields.mapValues { diff --git a/server-testing/src/main/kotlin/com/lightningkite/lightningdb/test/ConditionTests.kt b/server-testing/src/main/kotlin/com/lightningkite/lightningdb/test/ConditionTests.kt index 91382c18..369eb5ff 100644 --- a/server-testing/src/main/kotlin/com/lightningkite/lightningdb/test/ConditionTests.kt +++ b/server-testing/src/main/kotlin/com/lightningkite/lightningdb/test/ConditionTests.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package com.lightningkite.lightningdb.test import com.lightningkite.GeoCoordinate @@ -22,7 +24,6 @@ abstract class ConditionTests() { val lk = GeoCoordinate(41.727019, -111.8443002) val lower = GeoTest(geo = lk) val higher = GeoTest(geo = lk.copy(latitude = lk.latitude - 1.0)) - val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) val condition = condition() { it.geo.distanceBetween(lk, lessThan = 50.0.kilometers) } @@ -36,7 +37,6 @@ abstract class ConditionTests() { val lk = GeoCoordinate(41.727019, -111.8443002) val lower = GeoTest(geo = lk) val higher = GeoTest(geo = lk.copy(latitude = lk.latitude - 1.0)) - val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) val condition = condition() { it.geo.distanceBetween(lk, greaterThan = 50.0.kilometers) } @@ -49,10 +49,9 @@ abstract class ConditionTests() { val collection = database.collection("LargeTestModel_test_and_3") val lower = LargeTestModel(int = 0) val higher = LargeTestModel(int = 1) - val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = condition() { (it.int ne 1) and (it.int ne 2) } + val condition = condition() { (it.int neq 1) and (it.int neq 2) } val results = collection.find(condition).toList() assertEquals(listOf(lower), results) Unit @@ -108,7 +107,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().boolean ne true + val condition = path().boolean neq true val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -167,7 +166,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().list ne listOf(7, 8, 9) + val condition = path().list neq listOf(7, 8, 9) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -226,7 +225,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().map ne mapOf("c" to 3) + val condition = path().map neq mapOf("c" to 3) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -285,7 +284,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().byte ne 3.toByte() + val condition = path().byte neq 3.toByte() val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -344,7 +343,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().short ne 3.toShort() + val condition = path().short neq 3.toShort() val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -403,7 +402,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().int ne 3 + val condition = path().int neq 3 val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -462,7 +461,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().long ne 3L + val condition = path().long neq 3L val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -521,7 +520,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().float ne 3f + val condition = path().float neq 3f val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -580,7 +579,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().double ne 3.0 + val condition = path().double neq 3.0 val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -639,7 +638,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().string ne "aca" + val condition = path().string neq "aca" val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -698,7 +697,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().instant ne Instant.fromEpochMilliseconds(15000L) + val condition = path().instant neq Instant.fromEpochMilliseconds(15000L) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -772,7 +771,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().boolean notIn listOf(true) + val condition = path().boolean notInside listOf(true) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -816,7 +815,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().byte notIn listOf(3.toByte()) + val condition = path().byte notInside listOf(3.toByte()) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -860,7 +859,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().short notIn listOf(3.toShort()) + val condition = path().short notInside listOf(3.toShort()) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -904,7 +903,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().int notIn listOf(3) + val condition = path().int notInside listOf(3) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -948,7 +947,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().long notIn listOf(3L) + val condition = path().long notInside listOf(3L) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -992,7 +991,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().float notIn listOf(3f) + val condition = path().float notInside listOf(3f) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -1036,7 +1035,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().double notIn listOf(3.0) + val condition = path().double notInside listOf(3.0) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -1080,7 +1079,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().string notIn listOf("aca") + val condition = path().string notInside listOf("aca") val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -1124,7 +1123,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().instant notIn listOf(Instant.fromEpochMilliseconds(15000L)) + val condition = path().instant notInside listOf(Instant.fromEpochMilliseconds(15000L)) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -2559,7 +2558,7 @@ abstract class ConditionTests() { val nullItem = LargeTestModel(stringNullable = null) collection.insertMany(listOf(notNullItem, nullItem)) - var condition = path().stringNullable ne null + var condition = path().stringNullable neq null var result = collection.find(condition).toList() assertEquals(1, result.size) assertEquals(notNullItem, result.first()) @@ -2598,7 +2597,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().uuid ne UUID(0L, 3L) + val condition = path().uuid neq UUID(0L, 3L) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) @@ -2672,7 +2671,7 @@ abstract class ConditionTests() { val manualList = listOf(lower, higher) collection.insertOne(lower) collection.insertOne(higher) - val condition = path().uuid notIn listOf(UUID(0L, 3L)) + val condition = path().uuid notInside listOf(UUID(0L, 3L)) val results = collection.find(condition).toList() assertContains(results, lower) assertTrue(higher !in results) diff --git a/server-testing/src/main/kotlin/com/lightningkite/lightningdb/test/MaskTest.kt b/server-testing/src/main/kotlin/com/lightningkite/lightningdb/test/MaskTest.kt index 98d13241..29362f6c 100644 --- a/server-testing/src/main/kotlin/com/lightningkite/lightningdb/test/MaskTest.kt +++ b/server-testing/src/main/kotlin/com/lightningkite/lightningdb/test/MaskTest.kt @@ -25,12 +25,12 @@ class MaskTest { it.float.mask(0f, it.string eq "test") } mask(model).also(::println) - val also = mask( + mask( partialOf{ it.byte.assign(1) it.byte assign 1.toByte() it.short assign 1.toShort() - it.int assign 1.toInt() + it.int assign 1 it.long assign 1.toLong() it.float assign 1f } @@ -86,7 +86,6 @@ class MaskTest { @Test fun sort() { - val matchingMod = modification { it.int assign 2 } val matchingSort = SortPart(path().int) val notMatchingSortA = SortPart(path().byte) val notMatchingSortV = SortPart(path().string) @@ -101,7 +100,6 @@ class MaskTest { @Test fun condition() { - val matchingMod = modification { it.int assign 2 } val matchingSort = condition { it.int eq 2 } val notMatchingSortA = condition { it.byte eq 2 } val notMatchingSortV = condition { it.string eq "" } diff --git a/server-testing/src/test/kotlin/com/lightningkite/lightningdb/test/ConditionSimplifyKtTest.kt b/server-testing/src/test/kotlin/com/lightningkite/lightningdb/test/ConditionSimplifyKtTest.kt index 2079cf24..c477beaf 100644 --- a/server-testing/src/test/kotlin/com/lightningkite/lightningdb/test/ConditionSimplifyKtTest.kt +++ b/server-testing/src/test/kotlin/com/lightningkite/lightningdb/test/ConditionSimplifyKtTest.kt @@ -42,11 +42,11 @@ class ConditionSimplifyKtTest { Condition.Always(), Condition.Never(), condition { it.int eq 2 }, - condition { it.int ne 2 }, + condition { it.int neq 2 }, condition { it.int gt 2 }, condition { it.int lt 2 }, condition { it.int eq 0 }, - condition { it.int ne 0 }, + condition { it.int neq 0 }, condition { it.int gt 0 }, condition { it.int lt 0 }, condition { it.int gte 2 }, @@ -60,11 +60,11 @@ class ConditionSimplifyKtTest { condition { it.int notIn listOf(2) }, condition { it.int notIn listOf(0, 2) }, condition { it.short eq 2 }, - condition { it.short ne 2 }, + condition { it.short neq 2 }, condition { it.short gt 2 }, condition { it.short lt 2 }, condition { it.short eq 0 }, - condition { it.short ne 0 }, + condition { it.short neq 0 }, condition { it.short gt 0 }, condition { it.short lt 0 }, condition { it.short gte 2 }, diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index cc888c0a..1b9283af 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -11,7 +11,6 @@ plugins { } val kotlinVersion: String by project -val khrysalisVersion: String by project val kotlinXSerialization: String by project ksp { diff --git a/shared/src/commonMain/kotlin/com/lightningkite/DefaultClock.kt b/shared/src/commonMain/kotlin/com/lightningkite/DefaultClock.kt index f0b3d4fa..7ff0d73e 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/DefaultClock.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/DefaultClock.kt @@ -6,4 +6,5 @@ private var DefaultClock: Clock = Clock.System var Clock.Companion.default: Clock get() = DefaultClock set(value) { DefaultClock = value } +@Suppress("NOTHING_TO_INLINE") inline fun now() = Clock.default.now() \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/lightningkite/GeoCoordinate.kt b/shared/src/commonMain/kotlin/com/lightningkite/GeoCoordinate.kt index beb540ab..94090bc7 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/GeoCoordinate.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/GeoCoordinate.kt @@ -1,12 +1,12 @@ package com.lightningkite -import kotlinx.serialization.InternalSerializationApi +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.DoubleArraySerializer -import kotlinx.serialization.builtins.IntArraySerializer import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.descriptors.* +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.encoding.* import kotlin.jvm.JvmInline import kotlin.math.PI @@ -78,6 +78,7 @@ object GeoCoordinateGeoJsonSerializer: KSerializer { } } +@OptIn(ExperimentalSerializationApi::class) object GeoCoordinateArraySerializer: KSerializer { val delegate = DoubleArraySerializer() diff --git a/shared/src/commonMain/kotlin/com/lightningkite/StringAlts.kt b/shared/src/commonMain/kotlin/com/lightningkite/StringAlts.kt index d979f518..c73882f8 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/StringAlts.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/StringAlts.kt @@ -46,7 +46,7 @@ value class TrimmedString @Deprecated("Use String.trimmed()") constructor(overri inline fun TrimmedString.map(action: (String) -> String): TrimmedString = raw.let(action).trimmed() -@Suppress("DEPRECATION") +@Suppress("DEPRECATION", "NOTHING_TO_INLINE") inline fun String.trimmed(): TrimmedString = TrimmedString(this.trim()) @@ -67,7 +67,7 @@ value class CaselessString @Deprecated("Use String.caseless()") constructor(over inline fun CaselessString.map(action: (String) -> String): CaselessString = raw.let(action).caseless() -@Suppress("DEPRECATION") +@Suppress("DEPRECATION", "NOTHING_TO_INLINE") inline fun String.caseless(): CaselessString = CaselessString(this.lowercase()) @@ -88,7 +88,7 @@ value class TrimmedCaselessString @Deprecated("Use String.trimmedCaseless()") co inline fun TrimmedCaselessString.map(action: (String) -> String): TrimmedCaselessString = raw.let(action).trimmedCaseless() -@Suppress("DEPRECATION") +@Suppress("DEPRECATION", "NOTHING_TO_INLINE") inline fun String.trimmedCaseless(): TrimmedCaselessString = TrimmedCaselessString(this.trim().lowercase()) diff --git a/shared/src/commonMain/kotlin/com/lightningkite/UUID.kt b/shared/src/commonMain/kotlin/com/lightningkite/UUID.kt index 9cfcef16..30b2263e 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/UUID.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/UUID.kt @@ -1,3 +1,5 @@ +@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") + package com.lightningkite import kotlinx.serialization.Contextual diff --git a/shared/src/commonMain/kotlin/com/lightningkite/ZonedDateTime.kt b/shared/src/commonMain/kotlin/com/lightningkite/ZonedDateTime.kt index 6c9ef34c..c54a110b 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/ZonedDateTime.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/ZonedDateTime.kt @@ -48,7 +48,9 @@ object ZonedDateTimeIso8601Serializer : KSerializer { override fun serialize(encoder: Encoder, value: ZonedDateTime) = encoder.encodeString(value.toString()) } +@Suppress("NOTHING_TO_INLINE") inline fun LocalDateTime.atZone(zone: TimeZone) = ZonedDateTime(this, zone) +@Suppress("NOTHING_TO_INLINE") inline fun Instant.atZone(zone: TimeZone) = ZonedDateTime(this.toLocalDateTime(zone), zone) fun nowLocal() = ZonedDateTime(now().toLocalDateTime(TimeZone.currentSystemDefault()), TimeZone.currentSystemDefault()) @@ -87,5 +89,7 @@ object OffsetDateTimeIso8601Serializer : KSerializer { override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("com.lightningkite.OffsetDateTime", PrimitiveKind.STRING) override fun serialize(encoder: Encoder, value: OffsetDateTime) = encoder.encodeString(value.toString()) } +@Suppress("NOTHING_TO_INLINE") inline fun LocalDateTime.atOffset(offset: UtcOffset) = OffsetDateTime(this, offset) +@Suppress("NOTHING_TO_INLINE") inline fun Instant.atOffset(offset: UtcOffset) = OffsetDateTime(this.toLocalDateTime(FixedOffsetTimeZone(offset)), offset) diff --git a/shared/src/commonMain/kotlin/com/lightningkite/khrycompat.kt b/shared/src/commonMain/kotlin/com/lightningkite/khrycompat.kt deleted file mode 100644 index 47b7e460..00000000 --- a/shared/src/commonMain/kotlin/com/lightningkite/khrycompat.kt +++ /dev/null @@ -1,127 +0,0 @@ -package com.lightningkite.khrysalis - -import kotlin.reflect.KClass -import kotlin.reflect.KProperty - - -typealias AnyObject = Any - -typealias IsEquatable = Any? -typealias IsHashable = Any? -typealias IsCodable = Any? -typealias IsCodableAndHashable = Any? -typealias IsCodableAndEquatable = Any? -typealias IsEquatableNotNull = Any -typealias IsHashableNotNull = Any -typealias IsCodableNotNull = Any -typealias IsCodableAndHashableNotNull = Any -typealias IsCodableAndEquatableNotNull = Any -typealias ComparableAndHashable = Comparable -typealias ComparableCodableAndHashable = Comparable - -interface Equatable {} -interface Hashable: Equatable {} -typealias SomeEnum = Enum<*> - -interface Codable -typealias UntypedList = List<*> -typealias UntypedMap = Map<*, *> - -@Target(AnnotationTarget.FILE) -annotation class SharedCode - -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -@Target( - AnnotationTarget.CLASS, - AnnotationTarget.ANNOTATION_CLASS, - AnnotationTarget.TYPE_PARAMETER, - AnnotationTarget.PROPERTY, - AnnotationTarget.FIELD, - AnnotationTarget.LOCAL_VARIABLE, - AnnotationTarget.VALUE_PARAMETER, - AnnotationTarget.CONSTRUCTOR, - AnnotationTarget.FUNCTION, - AnnotationTarget.PROPERTY_GETTER, - AnnotationTarget.PROPERTY_SETTER, - AnnotationTarget.TYPE, - AnnotationTarget.FILE, - AnnotationTarget.TYPEALIAS -) -annotation class JsName(val name: String) - -@Target(AnnotationTarget.TYPE) -annotation class Escaping - -@Target(AnnotationTarget.CLASS) -annotation class SwiftMustBeClass - -@Target(AnnotationTarget.PROPERTY) -annotation class Unowned - -@Target(AnnotationTarget.VALUE_PARAMETER) -annotation class Modifies - -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER) -@Retention(AnnotationRetention.BINARY) -annotation class SwiftName(val name: String) - -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER) -@Retention(AnnotationRetention.BINARY) -annotation class SwiftNameless() - -@Target(AnnotationTarget.FUNCTION) -@Retention(AnnotationRetention.BINARY) -annotation class UnownedSelf - -@Target(AnnotationTarget.FUNCTION) -@Retention(AnnotationRetention.BINARY) -annotation class WeakSelf - -@Target(AnnotationTarget.FUNCTION) -@Retention(AnnotationRetention.BINARY) -annotation class CaptureUnowned(vararg val keys: String) - -@Target(AnnotationTarget.FUNCTION) -@Retention(AnnotationRetention.BINARY) -annotation class CaptureWeak(vararg val keys: String) - -@Target(AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER) -annotation class SwiftExactly(val parameterName: String = "default") - -@Target(AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER) -annotation class SwiftDescendsFrom(val parameterName: String = "default") - -@Target(AnnotationTarget.CLASS) -annotation class SwiftProtocolExtends(vararg val names: String) - -@Target(AnnotationTarget.FUNCTION) -annotation class DiscardableResult - -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.EXPRESSION) -@Retention(AnnotationRetention.SOURCE) -annotation class SwiftReturnType(val text: String) - -@Target(AnnotationTarget.FUNCTION) -@Retention(AnnotationRetention.BINARY) -annotation class SwiftExtensionWhere(val text: String) - -@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE, AnnotationTarget.VALUE_PARAMETER) -@Retention(AnnotationRetention.BINARY) -annotation class Throws(vararg val exceptionTypes: KClass<*>) - -@Target( - AnnotationTarget.CLASS, - AnnotationTarget.ANNOTATION_CLASS, - AnnotationTarget.TYPE_PARAMETER, - AnnotationTarget.PROPERTY, - AnnotationTarget.FIELD, - AnnotationTarget.CONSTRUCTOR, - AnnotationTarget.FUNCTION, - AnnotationTarget.TYPE -) -annotation class PlatformSpecific - -fun fatalError(@SwiftNameless reason: String = ""): Nothing { - throw Error(reason) -} diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Aggregate.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Aggregate.kt index 1e155d77..834b7e9b 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Aggregate.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Aggregate.kt @@ -1,7 +1,7 @@ -@file:SharedCode + package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.SharedCode + import kotlin.math.sqrt enum class Aggregate { diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Annotations.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Annotations.kt index 5019d040..d2b597e8 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Annotations.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Annotations.kt @@ -8,7 +8,7 @@ import kotlinx.serialization.descriptors.SerialKind import kotlin.reflect.KClass import kotlin.time.ExperimentalTime -@Retention(AnnotationRetention.RUNTIME) +@Retention(AnnotationRetention.BINARY) @Target(AnnotationTarget.FUNCTION) annotation class CheckReturnValue @@ -104,7 +104,7 @@ annotation class ExpectedPattern(val pattern: String) * A display name of the item in question. */ @SerialInfo -@Retention(AnnotationRetention.RUNTIME) +@Retention(AnnotationRetention.BINARY) @Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FIELD) annotation class DisplayName(val text: String) @@ -112,17 +112,17 @@ annotation class DisplayName(val text: String) * Which mime types are valid */ @SerialInfo -@Retention(AnnotationRetention.RUNTIME) +@Retention(AnnotationRetention.BINARY) @Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD) annotation class MimeType(vararg val types: String, val maxSize: Long = Long.MAX_VALUE) @SerialInfo -@Retention(AnnotationRetention.RUNTIME) +@Retention(AnnotationRetention.BINARY) @Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD) annotation class MaxLength(val size: Int) @SerialInfo -@Retention(AnnotationRetention.RUNTIME) +@Retention(AnnotationRetention.BINARY) @Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD) annotation class MaxSize(val size: Int) @@ -130,7 +130,7 @@ annotation class MaxSize(val size: Int) * A description of the item in question. */ @SerialInfo -@Retention(AnnotationRetention.RUNTIME) +@Retention(AnnotationRetention.BINARY) @Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FIELD) annotation class Description(val text: String) diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/CollectionChanges.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/CollectionChanges.kt index 273b6915..83b97d32 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/CollectionChanges.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/CollectionChanges.kt @@ -1,19 +1,12 @@ -@file:SharedCode package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.Equatable -import com.lightningkite.khrysalis.IsCodableAndHashable -import com.lightningkite.khrysalis.JsName -import com.lightningkite.khrysalis.SharedCode import kotlinx.serialization.Serializable -// TODO: Deprecate @Serializable -data class CollectionChanges( +data class CollectionChanges( val changes: List> = listOf() ) { - @JsName("pair") constructor(old: T? = null, new: T? = null):this(changes = if(old != null || new != null) listOf(EntryChange(old, new)) else listOf()) } @@ -27,6 +20,6 @@ fun , ID: Comparable> List.apply(changes: CollectionChanges< } // This will not convert well. Manually add the type argument to the return EntryChange on the swift side. "EntryChange" -inline fun CollectionChanges.map(mapper: (T)->B): CollectionChanges { +inline fun CollectionChanges.map(mapper: (T)->B): CollectionChanges { return CollectionChanges(changes = changes.map { it.map(mapper) }) } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Condition.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Condition.kt index 3d7f8537..2bd2f223 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Condition.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Condition.kt @@ -1,25 +1,16 @@ -@file:SharedCode + package com.lightningkite.lightningdb import com.lightningkite.GeoCoordinate -import com.lightningkite.khrysalis.* import kotlinx.serialization.* import com.lightningkite.lightningdb.SerializableProperty @Serializable(ConditionSerializer::class) -sealed class Condition { - open override fun hashCode(): Int { - fatalError() - } - - open override fun equals(other: Any?): Boolean { - fatalError() - } - - open operator fun invoke(on: T): Boolean { - fatalError() - } +sealed class Condition { + open override fun hashCode(): Int = throw NotImplementedError() + open override fun equals(other: Any?): Boolean = throw NotImplementedError() + open operator fun invoke(on: T): Boolean = throw NotImplementedError() infix fun and(other: Condition): Condition.And = Condition.And(listOf(this, other)) infix fun or(other: Condition): Condition.Or = Condition.Or(listOf(this, other)) @@ -27,7 +18,7 @@ sealed class Condition { @Serializable(ConditionNeverSerializer::class) @SerialName("Never") - class Never : Condition() { + class Never : Condition() { override fun invoke(on: T): Boolean = false override fun hashCode(): Int = 0 @@ -37,7 +28,7 @@ sealed class Condition { @Serializable(ConditionAlwaysSerializer::class) @SerialName("Always") - class Always : Condition() { + class Always : Condition() { override fun invoke(on: T): Boolean = true override fun hashCode(): Int = 1 @@ -47,67 +38,67 @@ sealed class Condition { @Serializable(ConditionAndSerializer::class) @SerialName("And") - data class And(val conditions: List>) : Condition() { + data class And(val conditions: List>) : Condition() { override fun invoke(on: T): Boolean = conditions.all { it(on) } } @Serializable(ConditionOrSerializer::class) @SerialName("Or") - data class Or(val conditions: List>) : Condition() { + data class Or(val conditions: List>) : Condition() { override fun invoke(on: T): Boolean = conditions.any { it(on) } } @Serializable(ConditionNotSerializer::class) @SerialName("Not") - data class Not(val condition: Condition) : Condition() { + data class Not(val condition: Condition) : Condition() { override fun invoke(on: T): Boolean = !condition(on) } @Serializable(ConditionEqualSerializer::class) @SerialName("Equal") - data class Equal(val value: T) : Condition() { + data class Equal(val value: T) : Condition() { override fun invoke(on: T): Boolean = on == value } @Serializable(ConditionNotEqualSerializer::class) @SerialName("NotEqual") - data class NotEqual(val value: T) : Condition() { + data class NotEqual(val value: T) : Condition() { override fun invoke(on: T): Boolean = on != value } @Serializable(ConditionInsideSerializer::class) @SerialName("Inside") - data class Inside(val values: List) : Condition() { + data class Inside(val values: List) : Condition() { override fun invoke(on: T): Boolean = values.contains(on) } @Serializable(ConditionNotInsideSerializer::class) @SerialName("NotInside") - data class NotInside(val values: List) : Condition() { + data class NotInside(val values: List) : Condition() { override fun invoke(on: T): Boolean = !values.contains(on) } @Serializable(ConditionGreaterThanSerializer::class) @SerialName("GreaterThan") - data class GreaterThan>(val value: T) : Condition() { + data class GreaterThan>(val value: T) : Condition() { override fun invoke(on: T): Boolean = on > value } @Serializable(ConditionLessThanSerializer::class) @SerialName("LessThan") - data class LessThan>(val value: T) : Condition() { + data class LessThan>(val value: T) : Condition() { override fun invoke(on: T): Boolean = on < value } @Serializable(ConditionGreaterThanOrEqualSerializer::class) @SerialName("GreaterThanOrEqual") - data class GreaterThanOrEqual>(val value: T) : Condition() { + data class GreaterThanOrEqual>(val value: T) : Condition() { override fun invoke(on: T): Boolean = on >= value } @Serializable(ConditionLessThanOrEqualSerializer::class) @SerialName("LessThanOrEqual") - data class LessThanOrEqual>(val value: T) : Condition() { + data class LessThanOrEqual>(val value: T) : Condition() { override fun invoke(on: T): Boolean = on <= value } @@ -125,7 +116,7 @@ sealed class Condition { @Serializable @SerialName("FullTextSearch") - data class FullTextSearch(val value: String, val ignoreCase: Boolean = false) : + data class FullTextSearch(val value: String, val ignoreCase: Boolean = false) : Condition() { override fun invoke(on: T): Boolean { val asText = on.toString() @@ -168,58 +159,58 @@ sealed class Condition { // TODO: Merge collection operations once Khrysalis is fully deprecated @Serializable(ConditionListAllElementsSerializer::class) @SerialName("ListAllElements") - data class ListAllElements(val condition: Condition) : Condition>() { + data class ListAllElements(val condition: Condition) : Condition>() { override fun invoke(on: List): Boolean = on.all { condition(it) } } @Serializable(ConditionListAnyElementsSerializer::class) @SerialName("ListAnyElements") - data class ListAnyElements(val condition: Condition) : Condition>() { + data class ListAnyElements(val condition: Condition) : Condition>() { override fun invoke(on: List): Boolean = on.any { condition(it) } } // TODO: Change to empty check @Serializable(ConditionListSizesEqualsSerializer::class) @SerialName("ListSizesEquals") - data class ListSizesEquals(val count: Int) : Condition>() { + data class ListSizesEquals(val count: Int) : Condition>() { override fun invoke(on: List): Boolean = on.size == count } @Serializable(ConditionSetAllElementsSerializer::class) @SerialName("SetAllElements") - data class SetAllElements(val condition: Condition) : Condition>() { + data class SetAllElements(val condition: Condition) : Condition>() { override fun invoke(on: Set): Boolean = on.all { condition(it) } } @Serializable(ConditionSetAnyElementsSerializer::class) @SerialName("SetAnyElements") - data class SetAnyElements(val condition: Condition) : Condition>() { + data class SetAnyElements(val condition: Condition) : Condition>() { override fun invoke(on: Set): Boolean = on.any { condition(it) } } // TODO: Change to empty check @Serializable(ConditionSetSizesEqualsSerializer::class) @SerialName("SetSizesEquals") - data class SetSizesEquals(val count: Int) : Condition>() { + data class SetSizesEquals(val count: Int) : Condition>() { override fun invoke(on: Set): Boolean = on.size == count } // TODO: Allow alternate keys once Khrysalis is fully deprecated @Serializable(ConditionExistsSerializer::class) @SerialName("Exists") - data class Exists(val key: String) : Condition>() { + data class Exists(val key: String) : Condition>() { override fun invoke(on: Map): Boolean = on.containsKey(key) } @Serializable @SerialName("OnKey") - data class OnKey(val key: String, val condition: Condition) : + data class OnKey(val key: String, val condition: Condition) : Condition>() { @Suppress("UNCHECKED_CAST") override fun invoke(on: Map): Boolean = on.containsKey(key) && condition(on[key] as V) } - data class OnField( + data class OnField( val key: SerializableProperty, val condition: Condition, ) : Condition() { @@ -228,7 +219,7 @@ sealed class Condition { @Serializable(ConditionIfNotNullSerializer::class) @SerialName("IfNotNull") - data class IfNotNull(val condition: Condition) : Condition() { + data class IfNotNull(val condition: Condition) : Condition() { override fun invoke(on: T?): Boolean = on != null && condition(on) } } diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ConditionBuilder.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ConditionBuilder.kt index 54ea4408..362e4f1f 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ConditionBuilder.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ConditionBuilder.kt @@ -1,60 +1,58 @@ -@file:SharedCode - package com.lightningkite.lightningdb import com.lightningkite.Distance import com.lightningkite.GeoCoordinate -import com.lightningkite.khrysalis.* import com.lightningkite.lightningdb.SerializableProperty import com.lightningkite.miles +import kotlin.js.JsName import kotlin.jvm.JvmName -inline fun path(): DataClassPath = DataClassPathSelf(serializerOrContextual()) +inline fun path(): DataClassPath = DataClassPathSelf(serializerOrContextual()) -inline fun condition(setup: (DataClassPath) -> Condition): Condition = +inline fun condition(setup: (DataClassPath) -> Condition): Condition = path().let(setup) fun condition(boolean: Boolean): Condition = if(boolean) Condition.Always() else Condition.Never() -val DataClassPath.always: Condition get() = Condition.Always() -val DataClassPath.never: Condition get() = Condition.Never() +val DataClassPath.always: Condition get() = Condition.Always() +val DataClassPath.never: Condition get() = Condition.Never() -infix fun DataClassPath.eq(value: T) = mapCondition(Condition.Equal(value)) -infix fun DataClassPath.eqNn(value: T?) = if(value == null) Condition.Never() else mapCondition(Condition.Equal(value)) -infix fun DataClassPath.neq(value: T) = mapCondition(Condition.NotEqual(value)) -@JsName("xDataClassPathNotInSet") infix fun DataClassPath.notInside(values: Set) = mapCondition(Condition.NotInside(values.toList())) -infix fun DataClassPath.notInside(values: List) = mapCondition(Condition.NotInside(values)) -infix fun > DataClassPath.gt(value: T) = mapCondition(Condition.GreaterThan(value)) -infix fun > DataClassPath.lt(value: T) = mapCondition(Condition.LessThan(value)) -infix fun > DataClassPath.gte(value: T) = mapCondition(Condition.GreaterThanOrEqual(value)) -infix fun > DataClassPath.lte(value: T) = mapCondition(Condition.LessThanOrEqual(value)) -infix fun DataClassPath.allClear(mask: Int) = mapCondition(Condition.IntBitsClear(mask)) -infix fun DataClassPath.allSet(mask: Int) = mapCondition(Condition.IntBitsSet(mask)) -infix fun DataClassPath.anyClear(mask: Int) = mapCondition(Condition.IntBitsAnyClear(mask)) -infix fun DataClassPath.anySet(mask: Int) = mapCondition(Condition.IntBitsAnySet(mask)) -infix fun DataClassPath.contains(value: String) = mapCondition(Condition.StringContains(value, ignoreCase = true)) -fun DataClassPath.distanceBetween(value: GeoCoordinate, greaterThan: Distance = 0.0.miles, lessThan: Distance = 100_000.0.miles) = mapCondition(Condition.GeoDistance(value, greaterThan.kilometers, lessThan.kilometers)) -@JsName("xDataClassPathContainsCased") fun DataClassPath.contains(value: String, ignoreCase: Boolean) = mapCondition(Condition.StringContains(value, ignoreCase = ignoreCase)) -fun DataClassPath.fullTextSearch(value: String, ignoreCase: Boolean, ) = mapCondition(Condition.FullTextSearch(value, ignoreCase = ignoreCase)) -@JsName("xDataClassPathListAll") @JvmName("listAll") inline infix fun DataClassPath>.all(condition: (DataClassPath) -> Condition) = mapCondition(Condition.ListAllElements(path().let(condition))) -@JsName("xDataClassPathListAny") @JvmName("listAny") inline infix fun DataClassPath>.any(condition: (DataClassPath) -> Condition) = mapCondition(Condition.ListAnyElements(path().let(condition))) -@JsName("xDataClassPathSetAll") @JvmName("setAll") inline infix fun DataClassPath>.all(condition: (DataClassPath) -> Condition) = mapCondition(Condition.SetAllElements(path().let(condition))) -@JsName("xDataClassPathSetAny") @JvmName("setAny") inline infix fun DataClassPath>.any(condition: (DataClassPath) -> Condition) = mapCondition(Condition.SetAnyElements(path().let(condition))) -infix fun DataClassPath>.containsKey(key: String) = mapCondition(Condition.Exists(key)) -inline infix fun DataClassPath.condition(make: (DataClassPath) -> Condition): Condition = mapCondition(make(path())) +infix fun DataClassPath.eq(value: T) = mapCondition(Condition.Equal(value)) +infix fun DataClassPath.eqNn(value: T?) = if(value == null) Condition.Never() else mapCondition(Condition.Equal(value)) +infix fun DataClassPath.neq(value: T) = mapCondition(Condition.NotEqual(value)) +@JsName("xDataClassPathNotInSet") infix fun DataClassPath.notInside(values: Set) = mapCondition(Condition.NotInside(values.toList())) +infix fun DataClassPath.notInside(values: List) = mapCondition(Condition.NotInside(values)) +infix fun > DataClassPath.gt(value: T) = mapCondition(Condition.GreaterThan(value)) +infix fun > DataClassPath.lt(value: T) = mapCondition(Condition.LessThan(value)) +infix fun > DataClassPath.gte(value: T) = mapCondition(Condition.GreaterThanOrEqual(value)) +infix fun > DataClassPath.lte(value: T) = mapCondition(Condition.LessThanOrEqual(value)) +infix fun DataClassPath.allClear(mask: Int) = mapCondition(Condition.IntBitsClear(mask)) +infix fun DataClassPath.allSet(mask: Int) = mapCondition(Condition.IntBitsSet(mask)) +infix fun DataClassPath.anyClear(mask: Int) = mapCondition(Condition.IntBitsAnyClear(mask)) +infix fun DataClassPath.anySet(mask: Int) = mapCondition(Condition.IntBitsAnySet(mask)) +infix fun DataClassPath.contains(value: String) = mapCondition(Condition.StringContains(value, ignoreCase = true)) +fun DataClassPath.distanceBetween(value: GeoCoordinate, greaterThan: Distance = 0.0.miles, lessThan: Distance = 100_000.0.miles) = mapCondition(Condition.GeoDistance(value, greaterThan.kilometers, lessThan.kilometers)) +@JsName("xDataClassPathContainsCased") fun DataClassPath.contains(value: String, ignoreCase: Boolean) = mapCondition(Condition.StringContains(value, ignoreCase = ignoreCase)) +fun DataClassPath.fullTextSearch(value: String, ignoreCase: Boolean, ) = mapCondition(Condition.FullTextSearch(value, ignoreCase = ignoreCase)) +@JsName("xDataClassPathListAll") @JvmName("listAll") inline infix fun DataClassPath>.all(condition: (DataClassPath) -> Condition) = mapCondition(Condition.ListAllElements(path().let(condition))) +@JsName("xDataClassPathListAny") @JvmName("listAny") inline infix fun DataClassPath>.any(condition: (DataClassPath) -> Condition) = mapCondition(Condition.ListAnyElements(path().let(condition))) +@JsName("xDataClassPathSetAll") @JvmName("setAll") inline infix fun DataClassPath>.all(condition: (DataClassPath) -> Condition) = mapCondition(Condition.SetAllElements(path().let(condition))) +@JsName("xDataClassPathSetAny") @JvmName("setAny") inline infix fun DataClassPath>.any(condition: (DataClassPath) -> Condition) = mapCondition(Condition.SetAnyElements(path().let(condition))) +infix fun DataClassPath>.containsKey(key: String) = mapCondition(Condition.Exists(key)) +inline infix fun DataClassPath.condition(make: (DataClassPath) -> Condition): Condition = mapCondition(make(path())) @Deprecated("Use neq instead", ReplaceWith("this.neq(value)", "com.lightningkite.lightningdb.neq")) -infix fun DataClassPath.ne(value: T) = mapCondition(Condition.NotEqual(value)) -@JsName("xDataClassPathInsideSet") infix fun DataClassPath.inside(values: Set) = mapCondition(Condition.Inside(values.toList())) -infix fun DataClassPath.inside(values: List) = mapCondition(Condition.Inside(values)) -@Deprecated("Use notInside instead", ReplaceWith("this.notInside(value)", "com.lightningkite.lightningdb.notInside")) -@JsName("xDataClassPathNinSet") infix fun DataClassPath.nin(values: Set) = mapCondition(Condition.NotInside(values.toList())) +infix fun DataClassPath.ne(value: T) = mapCondition(Condition.NotEqual(value)) +@JsName("xDataClassPathInsideSet") infix fun DataClassPath.inside(values: Set) = mapCondition(Condition.Inside(values.toList())) +infix fun DataClassPath.inside(values: List) = mapCondition(Condition.Inside(values)) @Deprecated("Use notInside instead", ReplaceWith("this.notInside(value)", "com.lightningkite.lightningdb.notInside")) -infix fun DataClassPath.nin(values: List) = mapCondition(Condition.NotInside(values)) +@JsName("xDataClassPathNinSet") infix fun DataClassPath.nin(values: Set) = mapCondition(Condition.NotInside(values.toList())) @Deprecated("Use notInside instead", ReplaceWith("this.notInside(value)", "com.lightningkite.lightningdb.notInside")) -@JsName("xDataClassPathNotInSet") infix fun DataClassPath.notIn(values: Set) = mapCondition(Condition.NotInside(values.toList())) +infix fun DataClassPath.nin(values: List) = mapCondition(Condition.NotInside(values)) @Deprecated("Use notInside instead", ReplaceWith("this.notInside(value)", "com.lightningkite.lightningdb.notInside")) -infix fun DataClassPath.notIn(values: List) = mapCondition(Condition.NotInside(values)) +@JsName("xDataClassPathNotInSet2") infix fun DataClassPath.notIn(values: Set) = mapCondition(Condition.NotInside(values.toList())) +@Deprecated("Use notInside instead", ReplaceWith("this.notInside(values)", "com.lightningkite.lightningdb.notInside")) +infix fun DataClassPath.notIn(values: List) = mapCondition(Condition.NotInside(values)) @Deprecated("Size equals will be removed in the future in favor of something that detects empty specifically") -@JsName("xDataClassPathListSizedEqual") @JvmName("listSizedEqual") infix fun DataClassPath>.sizesEquals(count: Int) = mapCondition(Condition.ListSizesEquals(count)) +@JsName("xDataClassPathListSizedEqual") @JvmName("listSizedEqual") infix fun DataClassPath>.sizesEquals(count: Int) = mapCondition(Condition.ListSizesEquals(count)) @Deprecated("Size equals will be removed in the future in favor of something that detects empty specifically") -@JsName("xDataClassPathSetSizedEqual") @JvmName("setSizedEqual") infix fun DataClassPath>.sizesEquals(count: Int) = mapCondition(Condition.SetSizesEquals(count)) \ No newline at end of file +@JsName("xDataClassPathSetSizedEqual") @JvmName("setSizedEqual") infix fun DataClassPath>.sizesEquals(count: Int) = mapCondition(Condition.SetSizesEquals(count)) \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ConditionSerialization.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ConditionSerialization.kt index eb25829a..615a62ac 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ConditionSerialization.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ConditionSerialization.kt @@ -3,8 +3,6 @@ package com.lightningkite.lightningdb import com.lightningkite.GeoCoordinate -import com.lightningkite.khrysalis.IsEquatable -import com.lightningkite.khrysalis.fatalError import kotlinx.serialization.* import kotlinx.serialization.builtins.* import kotlin.reflect.KClass @@ -64,11 +62,12 @@ private val stringOptions: List private fun classOptionsReflective(inner: KSerializer): List, *>> = (commonOptions(inner) + inner.serializableProperties!!.let { it.mapIndexed { index, ser -> + @Suppress("UNCHECKED_CAST") MySealedClassSerializer.Option, Condition.OnField>(ConditionOnFieldSerializer( ser as SerializableProperty )) { it is Condition.OnField<*, *> && it.key.name == inner.descriptor.getElementName(index) } } - } + MySealedClassSerializer.Option, Condition.FullTextSearch>(Condition.FullTextSearch.serializer(inner)) { it is Condition.FullTextSearch<*> }) as List, *>> + } + MySealedClassSerializer.Option(Condition.FullTextSearch.serializer(inner)) { it is Condition.FullTextSearch<*> }) private val cache = HashMap>() @Suppress("UNCHECKED_CAST") @@ -99,6 +98,7 @@ class ConditionOnFieldSerializer( override fun outer(it: Condition): Condition.OnField = Condition.OnField(field, it) } +@OptIn(ExperimentalSerializationApi::class) class LazyRenamedSerialDescriptor(override val serialName: String, val getter: () -> SerialDescriptor) : SerialDescriptor { override val elementsCount: Int get() = getter().elementsCount @@ -145,28 +145,28 @@ class ConditionNotSerializer(val inner: KSerializer) : WrappingSerializer< override fun outer(it: Condition): Condition.Not = Condition.Not(it) } -class ConditionEqualSerializer(val inner: KSerializer) : +class ConditionEqualSerializer(val inner: KSerializer) : WrappingSerializer, T>("Equal") { override fun getDeferred(): KSerializer = inner override fun inner(it: Condition.Equal): T = it.value override fun outer(it: T): Condition.Equal = Condition.Equal(it) } -class ConditionNotEqualSerializer(val inner: KSerializer) : +class ConditionNotEqualSerializer(val inner: KSerializer) : WrappingSerializer, T>("NotEqual") { override fun getDeferred(): KSerializer = inner override fun inner(it: Condition.NotEqual): T = it.value override fun outer(it: T): Condition.NotEqual = Condition.NotEqual(it) } -class ConditionInsideSerializer(val inner: KSerializer) : +class ConditionInsideSerializer(val inner: KSerializer) : WrappingSerializer, List>("Inside") { override fun getDeferred() = ListSerializer(inner) override fun inner(it: Condition.Inside): List = it.values override fun outer(it: List) = Condition.Inside(it) } -class ConditionNotInsideSerializer(val inner: KSerializer) : +class ConditionNotInsideSerializer(val inner: KSerializer) : WrappingSerializer, List>("NotInside") { override fun getDeferred() = ListSerializer(inner) override fun inner(it: Condition.NotInside): List = it.values diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/DataClassPath.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/DataClassPath.kt index 39606192..4957de69 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/DataClassPath.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/DataClassPath.kt @@ -1,9 +1,7 @@ -@file:SharedCode @file:OptIn(ExperimentalSerializationApi::class) package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.* import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable @@ -14,10 +12,11 @@ import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.internal.GeneratedSerializer import com.lightningkite.lightningdb.SerializableProperty +import kotlin.js.JsName import kotlin.jvm.JvmName @Serializable(DataClassPathSerializer::class) -abstract class DataClassPathPartial : Hashable { +abstract class DataClassPathPartial { abstract fun getAny(key: K): Any? abstract fun setAny(key: K, any: Any?): K abstract val properties: List> @@ -28,11 +27,10 @@ abstract class DataClassPathPartial : Hashable { abstract val serializerAny: KSerializer<*> } -abstract class DataClassPath : DataClassPathPartial() { +abstract class DataClassPath : DataClassPathPartial() { abstract fun get(key: K): V? abstract fun set(key: K, value: V): K - @Suppress("UNCHECKED_CAST") override fun getAny(key: K): Any? = get(key) @Suppress("UNCHECKED_CAST") @@ -47,7 +45,7 @@ abstract class DataClassPath abstract val serializer: KSerializer } -class DataClassPathSelf(override val serializer: KSerializer) : DataClassPath() { +class DataClassPathSelf(override val serializer: KSerializer) : DataClassPath() { override fun get(key: K): K? = key override fun set(key: K, value: K): K = value override fun toString(): String = "this" @@ -58,7 +56,7 @@ class DataClassPathSelf(override val serializer: KSeri override fun mapModification(modification: Modification): Modification = modification } -data class DataClassPathAccess( +data class DataClassPathAccess( val first: DataClassPath, val second: SerializableProperty ) : DataClassPath() { @@ -82,7 +80,7 @@ data class DataClassPathAccess get() = second.serializer } -data class DataClassPathNotNull(val wraps: DataClassPath) : +data class DataClassPathNotNull(val wraps: DataClassPath) : DataClassPath() { override val properties: List> get() = wraps.properties @@ -100,7 +98,7 @@ data class DataClassPathNotNull get() = wraps.serializer.nullElement()!! as KSerializer } -data class DataClassPathList(val wraps: DataClassPath>) : +data class DataClassPathList(val wraps: DataClassPath>) : DataClassPath() { override val properties: List> get() = wraps.properties @@ -118,7 +116,7 @@ data class DataClassPathList override val serializer: KSerializer get() = wraps.serializer.listElement()!! as KSerializer } -data class DataClassPathSet(val wraps: DataClassPath>) : +data class DataClassPathSet(val wraps: DataClassPath>) : DataClassPath() { override val properties: List> get() = wraps.properties @@ -136,22 +134,15 @@ data class DataClassPathSet( override val serializer: KSerializer get() = wraps.serializer.listElement()!! as KSerializer } -@JsName("notNull") -val DataClassPath.notNull: DataClassPathNotNull +val DataClassPath.notNull: DataClassPathNotNull get() = DataClassPathNotNull( this ) -@JsName("listElements") @get:JvmName("getListElements") -val DataClassPath>.elements: DataClassPathList - get() = DataClassPathList( - this - ) +val DataClassPath>.elements: DataClassPathList + get() = DataClassPathList(this) -@JsName("setElements") @get:JvmName("getSetElements") -val DataClassPath>.elements: DataClassPathSet - get() = DataClassPathSet( - this - ) +val DataClassPath>.elements: DataClassPathSet + get() = DataClassPathSet(this) diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/DataClassPathSerializer.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/DataClassPathSerializer.kt index 8598d329..544d3924 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/DataClassPathSerializer.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/DataClassPathSerializer.kt @@ -70,6 +70,7 @@ class DataClassPathSerializer(val inner: KSerializer): KSerializer(inner), prop as SerializableProperty) else DataClassPathAccess(c as DataClassPath, prop as SerializableProperty) if(part.endsWith('?')) { + @Suppress("UNCHECKED_CAST") current = DataClassPathNotNull(current as DataClassPath) currentSerializer = currentSerializer.nullElement()!! } diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/EntryChange.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/EntryChange.kt index 5b83cde6..f55fb869 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/EntryChange.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/EntryChange.kt @@ -1,21 +1,18 @@ -@file:SharedCode + package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.Equatable -import com.lightningkite.khrysalis.IsCodableAndHashable -import com.lightningkite.khrysalis.JsName -import com.lightningkite.khrysalis.SharedCode + import kotlinx.serialization.Serializable @Serializable -data class EntryChange( +data class EntryChange( val old: T? = null, val new: T? = null ) { } // This will not convert well. Manually add the type argument to the return EntryChange on the swift side. "EntryChange" -inline fun EntryChange.map(mapper: (T)->B): EntryChange { +inline fun EntryChange.map(mapper: (T)->B): EntryChange { return EntryChange(old?.let(mapper), new?.let(mapper)) } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/GroupCountQuery.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/GroupCountQuery.kt index 56d910d9..26aa9d67 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/GroupCountQuery.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/GroupCountQuery.kt @@ -1,25 +1,23 @@ -@file:SharedCode + package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.IsCodableAndHashable -import com.lightningkite.khrysalis.SharedCode import kotlinx.serialization.Serializable @Serializable -data class GroupCountQuery( +data class GroupCountQuery( val condition: Condition = Condition.Always(), val groupBy: DataClassPathPartial ) @Serializable -data class AggregateQuery( +data class AggregateQuery( val aggregate: Aggregate, val condition: Condition = Condition.Always(), val property: DataClassPathPartial ) @Serializable -data class GroupAggregateQuery( +data class GroupAggregateQuery( val aggregate: Aggregate, val condition: Condition = Condition.Always(), val groupBy: DataClassPathPartial, diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/HasId.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/HasId.kt index fee27de0..e98cff53 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/HasId.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/HasId.kt @@ -1,37 +1,30 @@ -@file:SharedCode + package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.* import kotlinx.serialization.Serializable import com.lightningkite.lightningdb.SerializableProperty -@SwiftProtocolExtends("Codable", "Hashable") interface HasId> { val _id: ID } -@SwiftProtocolExtends("Codable", "Hashable") interface HasEmail { val email: String } -@SwiftProtocolExtends("Codable", "Hashable") interface HasPhoneNumber { val phoneNumber: String } -@SwiftProtocolExtends("Codable", "Hashable") interface HasMaybeEmail { val email: String? } -@SwiftProtocolExtends("Codable", "Hashable") interface HasMaybePhoneNumber { val phoneNumber: String? } -@SwiftProtocolExtends("Codable", "Hashable") interface HasPassword { val hashedPassword: String } diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/HasIdFields.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/HasIdFields.kt index 923d0142..c572d333 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/HasIdFields.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/HasIdFields.kt @@ -1,6 +1,5 @@ package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.JsName import com.lightningkite.lightningdb.SerializableProperty import kotlinx.serialization.KSerializer import kotlin.jvm.JvmName @@ -15,12 +14,10 @@ fun KSerializer.email() = serializableProperties!!.find fun KSerializer.phoneNumber() = serializableProperties!!.find { it.name == "phoneNumber" }!! as SerializableProperty @JvmName("emailMaybe") -@JsName("emailMaybe") @Suppress("UNCHECKED_CAST") fun KSerializer.email() = serializableProperties!!.find { it.name == "email" }!! as SerializableProperty @JvmName("phoneNumberMaybe") -@JsName("phoneNumberMaybe") @Suppress("UNCHECKED_CAST") fun KSerializer.phoneNumber() = serializableProperties!!.find { it.name == "phoneNumber" }!! as SerializableProperty diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ListChange.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ListChange.kt index 96cd1df3..a1cff29b 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ListChange.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ListChange.kt @@ -1,12 +1,9 @@ -@file:SharedCode package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.IsCodableAndHashable -import com.lightningkite.khrysalis.SharedCode import kotlinx.serialization.Serializable @Serializable -data class ListChange( +data class ListChange( val wholeList: List? = null, val old: T? = null, val new: T? = null diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MassModification.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MassModification.kt index 9d5490b0..a1324eb0 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MassModification.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MassModification.kt @@ -1,12 +1,10 @@ -@file:SharedCode package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.IsCodableAndHashable -import com.lightningkite.khrysalis.SharedCode + import kotlinx.serialization.Serializable @Serializable -data class MassModification( +data class MassModification( val condition: Condition, val modification: Modification ) diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Modification.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Modification.kt index c070b786..e6f44c2f 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Modification.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Modification.kt @@ -1,24 +1,23 @@ -@file:SharedCode + package com.lightningkite.lightningdb import com.lightningkite.ShouldValidateSub -import com.lightningkite.khrysalis.* import kotlinx.serialization.* import com.lightningkite.lightningdb.SerializableProperty @Serializable(ModificationSerializer::class) -sealed class Modification { - open override fun hashCode(): Int { fatalError() } - open override fun equals(other: Any?): Boolean { fatalError() } - open operator fun invoke(on: T): T { fatalError() } - open fun invokeDefault(): T { fatalError() } +sealed class Modification { + open override fun hashCode(): Int { throw NotImplementedError() } + open override fun equals(other: Any?): Boolean { throw NotImplementedError() } + open operator fun invoke(on: T): T { throw NotImplementedError() } + open fun invokeDefault(): T { throw NotImplementedError() } @Deprecated("Use the modification {} builder instead") infix fun then(other: Modification): Modification.Chain = Modification.Chain(listOf(this, other)) @Serializable(ModificationChainSerializer::class) - data class Chain(val modifications: List>): Modification() { + data class Chain(val modifications: List>): Modification() { override fun invoke(on: T): T = modifications.fold(on) { item, mod -> mod(item) } override fun invokeDefault(): T { val on = modifications[0].invokeDefault() @@ -27,25 +26,25 @@ sealed class Modification { } @Serializable(ModificationIfNotNullSerializer::class) - data class IfNotNull(val modification: Modification): Modification() { + data class IfNotNull(val modification: Modification): Modification() { override fun invoke(on: T?): T? = on?.let { modification(it) } override fun invokeDefault(): T? = null } @Serializable(ModificationAssignSerializer::class) - data class Assign(val value: T): Modification() { + data class Assign(val value: T): Modification() { override fun invoke(on: T): T = value override fun invokeDefault(): T = value } @Serializable(ModificationCoerceAtMostSerializer::class) - data class CoerceAtMost>(val value: T): Modification() { + data class CoerceAtMost>(val value: T): Modification() { override fun invoke(on: T): T = on.coerceAtMost(value) override fun invokeDefault(): T = value } @Serializable(ModificationCoerceAtLeastSerializer::class) - data class CoerceAtLeast>(val value: T): Modification() { + data class CoerceAtLeast>(val value: T): Modification() { override fun invoke(on: T): T = on.coerceAtLeast(value) override fun invokeDefault(): T = value } @@ -67,7 +66,7 @@ sealed class Modification { is Long -> 0L as T is Float -> 0f as T is Double -> 0.0 as T - else -> fatalError() + else -> throw NotImplementedError() } } @@ -78,25 +77,25 @@ sealed class Modification { } @Serializable(ModificationListAppendSerializer::class) - data class ListAppend(val items: List): Modification>() { + data class ListAppend(val items: List): Modification>() { override fun invoke(on: List): List = on + items override fun invokeDefault(): List = items } @Serializable(ModificationListRemoveSerializer::class) - data class ListRemove(val condition: Condition): Modification>() { + data class ListRemove(val condition: Condition): Modification>() { override fun invoke(on: List): List = on.filter { !condition(it) } override fun invokeDefault(): List = listOf() } @Serializable(ModificationListRemoveInstancesSerializer::class) - data class ListRemoveInstances(val items: List): Modification>() { + data class ListRemoveInstances(val items: List): Modification>() { override fun invoke(on: List): List = on - items override fun invokeDefault(): List = listOf() } @Serializable(ModificationListDropFirstSerializer::class) - class ListDropFirst: Modification>() { + class ListDropFirst: Modification>() { override fun invoke(on: List): List = on.drop(1) override fun invokeDefault(): List = listOf() override fun hashCode(): Int = 1 @@ -105,7 +104,7 @@ sealed class Modification { } @Serializable(ModificationListDropLastSerializer::class) - class ListDropLast: Modification>() { + class ListDropLast: Modification>() { override fun invoke(on: List): List = on.dropLast(1) override fun invokeDefault(): List = listOf() override fun hashCode(): Int = 1 @@ -115,31 +114,31 @@ sealed class Modification { @Serializable() @SerialName("ListPerElement") - data class ListPerElement(val condition: Condition, val modification: Modification): Modification>() { + data class ListPerElement(val condition: Condition, val modification: Modification): Modification>() { override fun invoke(on: List): List = on.map { if(condition(it)) modification(it) else it } override fun invokeDefault(): List = listOf() } @Serializable(ModificationSetAppendSerializer::class) - data class SetAppend(val items: Set): Modification>() { + data class SetAppend(val items: Set): Modification>() { override fun invoke(on: Set): Set = (on + items) override fun invokeDefault(): Set = items } @Serializable(ModificationSetRemoveSerializer::class) - data class SetRemove(val condition: Condition): Modification>() { + data class SetRemove(val condition: Condition): Modification>() { override fun invoke(on: Set): Set = on.filter { !condition(it) }.toSet() override fun invokeDefault(): Set = setOf() } @Serializable(ModificationSetRemoveInstancesSerializer::class) - data class SetRemoveInstances(val items: Set): Modification>() { + data class SetRemoveInstances(val items: Set): Modification>() { override fun invoke(on: Set): Set = on - items override fun invokeDefault(): Set = setOf() } @Serializable(ModificationSetDropFirstSerializer::class) - class SetDropFirst: Modification>() { + class SetDropFirst: Modification>() { override fun invoke(on: Set): Set = on.drop(1).toSet() override fun invokeDefault(): Set = setOf() override fun hashCode(): Int = 1 @@ -148,7 +147,7 @@ sealed class Modification { } @Serializable(ModificationSetDropLastSerializer::class) - class SetDropLast: Modification>() { + class SetDropLast: Modification>() { override fun invoke(on: Set): Set = on.toList().dropLast(1).toSet() override fun invokeDefault(): Set = setOf() override fun hashCode(): Int = 1 @@ -158,33 +157,33 @@ sealed class Modification { @Serializable() @SerialName("SetPerElement") - data class SetPerElement(val condition: Condition, val modification: Modification): Modification>() { + data class SetPerElement(val condition: Condition, val modification: Modification): Modification>() { override fun invoke(on: Set): Set = on.map { if(condition(it)) modification(it) else it }.toSet() override fun invokeDefault(): Set = setOf() } @Serializable(ModificationCombineSerializer::class) - data class Combine(val map: Map): Modification>() { + data class Combine(val map: Map): Modification>() { override fun invoke(on: Map): Map = on + map override fun invokeDefault(): Map = map } @Serializable(ModificationModifyByKeySerializer::class) - data class ModifyByKey(val map: Map>): Modification>() { + data class ModifyByKey(val map: Map>): Modification>() { override fun invoke(on: Map): Map = on + map.mapValues { (on[it.key]?.let { e -> it.value(e) } ?: it.value.invokeDefault()) } override fun invokeDefault(): Map = map.mapValues { it.value.invokeDefault() } } @Serializable(ModificationRemoveKeysSerializer::class) - data class RemoveKeys(val fields: Set): Modification>() { + data class RemoveKeys(val fields: Set): Modification>() { override fun invoke(on: Map): Map = on.filterKeys { it !in fields } override fun invokeDefault(): Map = mapOf() } - data class OnField(val key: SerializableProperty, val modification: Modification): Modification() { + data class OnField(val key: SerializableProperty, val modification: Modification): Modification() { override fun invoke(on: K): K = key.setCopy(on, modification(key.get(on))) override fun invokeDefault(): K { - fatalError("Cannot mutate a field that doesn't exist") + throw IllegalStateException("Cannot mutate a field that doesn't exist") } } } diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ModificationBuilder.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ModificationBuilder.kt index 49708115..9554d558 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ModificationBuilder.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/ModificationBuilder.kt @@ -1,31 +1,27 @@ -@file:SharedCode package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.IsCodableAndHashable -import com.lightningkite.khrysalis.JsName -import com.lightningkite.khrysalis.SharedCode import kotlin.jvm.JvmName -inline fun modification(setup: ModificationBuilder.(DataClassPath) -> Unit): Modification { +inline fun modification(setup: ModificationBuilder.(DataClassPath) -> Unit): Modification { return ModificationBuilder().apply { setup(this, path()) }.build() } -inline fun modification(path: DataClassPath, setup: ModificationBuilder.(DataClassPath) -> Unit): Modification { +inline fun modification(path: DataClassPath, setup: ModificationBuilder.(DataClassPath) -> Unit): Modification { return ModificationBuilder().apply { setup(this, path) }.build() } -inline fun Modification.and(setup: ModificationBuilder.(DataClassPath) -> Unit): Modification { +inline fun Modification.and(setup: ModificationBuilder.(DataClassPath) -> Unit): Modification { return ModificationBuilder().apply { this.modifications.add(this@and) setup(this, path()) }.build() } -class ModificationBuilder() { +class ModificationBuilder() { val modifications = ArrayList>() fun add(modification: Modification) { modifications.add(modification) } fun build(): Modification { @@ -33,117 +29,96 @@ class ModificationBuilder() { else return Modification.Chain(modifications) } - @JsName("assign") - infix fun DataClassPath.assign(value: T) { + infix fun DataClassPath.assign(value: T) { modifications.add(mapModification(Modification.Assign(value))) } - @JsName("coerceAtMost") infix fun > DataClassPath.coerceAtMost(value: T) { modifications.add(mapModification(Modification.CoerceAtMost(value))) } - @JsName("coerceAtLeast") infix fun > DataClassPath.coerceAtLeast(value: T) { modifications.add(mapModification(Modification.CoerceAtLeast(value))) } - @JsName("plusAssignNumber") infix operator fun DataClassPath.plusAssign(by: T) { modifications.add(mapModification(Modification.Increment(by))) } - @JsName("timesAssign") infix operator fun DataClassPath.timesAssign(by: T) { modifications.add(mapModification(Modification.Multiply(by))) } - @JsName("plusAssignString") infix operator fun DataClassPath.plusAssign(value: String) { modifications.add(mapModification(Modification.AppendString(value))) } - @JsName("plusAssignList") infix operator fun DataClassPath>.plusAssign(items: List) { modifications.add(mapModification(Modification.ListAppend(items))) } - @JsName("plusAssignSet") infix operator fun DataClassPath>.plusAssign(items: Set) { modifications.add(mapModification(Modification.SetAppend(items))) } - @JsName("plusAssignItemList") @JvmName("plusList") infix operator fun DataClassPath>.plusAssign(item: T) { modifications.add(mapModification(Modification.ListAppend(listOf(item)))) } - @JsName("plusAssignItemSet") @JvmName("plusSet") infix operator fun DataClassPath>.plusAssign(item: T) { modifications.add(mapModification(Modification.SetAppend(setOf(item)))) } - @JsName("plusAssignListAddAll") - infix fun DataClassPath>.addAll(items: List) { + infix fun DataClassPath>.addAll(items: List) { modifications.add(mapModification(Modification.ListAppend(items))) } - @JsName("plusAssignSetAddAll") - infix fun DataClassPath>.addAll(items: Set) { + infix fun DataClassPath>.addAll(items: Set) { modifications.add(mapModification(Modification.SetAppend(items))) } - @JsName("removeAllList") @JvmName("removeAllList") - inline infix fun DataClassPath>.removeAll(condition: (DataClassPath) -> Condition) { + inline infix fun DataClassPath>.removeAll(condition: (DataClassPath) -> Condition) { modifications.add(mapModification(Modification.ListRemove(path().let(condition)))) } - @JsName("removeAllSet") @JvmName("removeAllSet") - inline infix fun DataClassPath>.removeAll(condition: (DataClassPath) -> Condition) { + inline infix fun DataClassPath>.removeAll(condition: (DataClassPath) -> Condition) { modifications.add(mapModification(Modification.SetRemove(path().let(condition)))) } - @JsName("removeAllItemsList") - infix fun DataClassPath>.removeAll(items: List) { + infix fun DataClassPath>.removeAll(items: List) { modifications.add(mapModification(Modification.ListRemoveInstances(items))) } - @JsName("removeAllItemsSet") - infix fun DataClassPath>.removeAll(items: Set) { + infix fun DataClassPath>.removeAll(items: Set) { modifications.add(mapModification(Modification.SetRemoveInstances(items))) } - @JsName("dropLastList") @JvmName("dropLastList") - fun DataClassPath>.dropLast() { + fun DataClassPath>.dropLast() { modifications.add(mapModification(Modification.ListDropLast())) } - @JsName("dropLastSet") @JvmName("dropLastSet") - fun DataClassPath>.dropLast() { + fun DataClassPath>.dropLast() { modifications.add(mapModification(Modification.SetDropLast())) } - @JsName("dropFirstList") @JvmName("dropFirstList") - fun DataClassPath>.dropFirst() { + fun DataClassPath>.dropFirst() { modifications.add(mapModification(Modification.ListDropFirst())) } - @JsName("dropFirstSet") @JvmName("dropFirstSet") - fun DataClassPath>.dropFirst() { + fun DataClassPath>.dropFirst() { modifications.add(mapModification(Modification.SetDropFirst())) } - @JsName("forEachList") @JvmName("forEachList") - inline infix fun DataClassPath>.forEach(modification: ModificationBuilder.(DataClassPath) -> Unit) { + inline infix fun DataClassPath>.forEach(modification: ModificationBuilder.(DataClassPath) -> Unit) { val builder = ModificationBuilder() modification(builder, path()) modifications.add( @@ -156,9 +131,8 @@ class ModificationBuilder() { ) } - @JsName("forEachSet") @JvmName("forEachSet") - inline infix fun DataClassPath>.forEach(modification: ModificationBuilder.(DataClassPath) -> Unit) { + inline infix fun DataClassPath>.forEach(modification: ModificationBuilder.(DataClassPath) -> Unit) { val builder = ModificationBuilder() modification(builder, path()) modifications.add( @@ -171,9 +145,8 @@ class ModificationBuilder() { ) } - @JsName("forEachIfList") @JvmName("forEachIfList") - inline fun DataClassPath>.forEachIf( + inline fun DataClassPath>.forEachIf( condition: (DataClassPath) -> Condition, modification: ModificationBuilder.(DataClassPath) -> Unit, ) { @@ -189,9 +162,8 @@ class ModificationBuilder() { ) } - @JsName("forEachIfSet") @JvmName("forEachIfSet") - inline fun DataClassPath>.forEachIf( + inline fun DataClassPath>.forEachIf( condition: (DataClassPath) -> Condition, modification: ModificationBuilder.(DataClassPath) -> Unit, ) { @@ -207,18 +179,15 @@ class ModificationBuilder() { ) } - @JsName("plusAssignMap") - infix operator fun DataClassPath>.plusAssign(map: Map) { + infix operator fun DataClassPath>.plusAssign(map: Map) { modifications.add(mapModification(Modification.Combine(map))) } - @JsName("modifyByKey") - inline infix fun DataClassPath>.modifyByKey(byKey: Map.(DataClassPath) -> Unit>) { + inline infix fun DataClassPath>.modifyByKey(byKey: Map.(DataClassPath) -> Unit>) { modifications.add(mapModification(Modification.ModifyByKey(byKey.mapValues { modification(it.value) }))) } - @JsName("removeKeys") - infix fun DataClassPath>.removeKeys(fields: Set) { + infix fun DataClassPath>.removeKeys(fields: Set) { modifications.add(mapModification(Modification.RemoveKeys(fields))) } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MultiplexMessage.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MultiplexMessage.kt index ae5917c6..b4f53a7e 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MultiplexMessage.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MultiplexMessage.kt @@ -1,7 +1,7 @@ -@file:SharedCode + package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.SharedCode + import kotlinx.serialization.Serializable @Serializable diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MySealedClassSerializer.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MySealedClassSerializer.kt index b7555d1e..ac89944b 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MySealedClassSerializer.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/MySealedClassSerializer.kt @@ -52,7 +52,7 @@ class MySealedClassSerializer( s.serializer.descriptor, isOptional = true, annotations = listOfNotNull(this@MySealedClassSerializer.options[index].alternativeNames - ?.let { JsonNames(*it.toTypedArray()) }) + s.annotations + .let { JsonNames(*it.toTypedArray()) }) + s.annotations ) } } diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Partial.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Partial.kt index 2f0f8cca..4b1f5f85 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Partial.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Partial.kt @@ -1,13 +1,6 @@ package com.lightningkite.lightningdb -import com.lightningkite.UUID -import com.lightningkite.lightningdb.SerializableProperty -import kotlinx.datetime.Instant -import kotlinx.datetime.LocalDate -import kotlinx.datetime.LocalDateTime -import kotlinx.datetime.LocalTime import kotlinx.serialization.KSerializer -import kotlin.time.Duration data class Partial(val parts: MutableMap, Any?> = mutableMapOf()) { constructor(item: T, paths: Set>) : this() { @@ -15,6 +8,7 @@ data class Partial(val parts: MutableMap, Any?> = } } +@Suppress("UNCHECKED_CAST") class PartialBuilder(val parts: MutableMap, Any?> = mutableMapOf()) { inline operator fun DataClassPath.invoke(setup: PartialBuilder.(DataClassPathSelf) -> Unit) { if(this !is DataClassPathAccess<*, *, *>) throw IllegalArgumentException() @@ -25,11 +19,13 @@ class PartialBuilder(val parts: MutableMap, Any?> parts[this.second as SerializableProperty] = PartialBuilder().apply { setup(DataClassPathSelf(second.serializer as KSerializer)) }.let { Partial(it.parts) } } + @Suppress("NOTHING_TO_INLINE") inline infix fun DataClassPath.assign(value: Partial) { if(this !is DataClassPathAccess<*, *, *>) throw IllegalArgumentException() parts[this.second as SerializableProperty] = value } + @Suppress("NOTHING_TO_INLINE") inline infix fun DataClassPath.assign(value: A) { if(this !is DataClassPathAccess<*, *, *>) throw IllegalArgumentException() parts[this.second as SerializableProperty] = value diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/PartialSerializer.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/PartialSerializer.kt index 6770df7c..55aee950 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/PartialSerializer.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/PartialSerializer.kt @@ -70,22 +70,27 @@ class PartialSerializer(val source: KSerializer): KSerializer> override fun serialize(encoder: Encoder, value: Partial) = encoder.encodeStructure(descriptor) { for((key, v) in value.parts) { val index = descriptor.getElementIndex(key.name) + @Suppress("UNCHECKED_CAST") encodeSerializableElement(descriptor, index, childSerializers[index] as KSerializer, v) } } } fun DataClassPathPartial.setMap(key: K, out: Partial) { - if(properties.isEmpty()) throw IllegalStateException("Path ${this} cannot be set for partial") + if(properties.isEmpty()) throw IllegalStateException("Path $this cannot be set for partial") + @Suppress("UNCHECKED_CAST") var current = out as Partial var value: Any? = key for (prop in properties.dropLast(1)) { + @Suppress("UNCHECKED_CAST") value = (prop as SerializableProperty).get(value) if(value == null) { current.parts[prop] = null return } + @Suppress("UNCHECKED_CAST") current = current.parts.getOrPut(prop as SerializableProperty) { Partial() } as Partial } + @Suppress("UNCHECKED_CAST") current.parts[properties.last() as SerializableProperty] = getAny(key) } diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Query.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Query.kt index d1f4c3f0..66d53ec2 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Query.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/Query.kt @@ -1,13 +1,9 @@ -@file:SharedCode - package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.IsCodableAndHashable -import com.lightningkite.khrysalis.SharedCode import kotlinx.serialization.Serializable @Serializable -data class Query( +data class Query( val condition: Condition = Condition.Always(), val orderBy: List> = listOf(), val skip: Int = 0, @@ -16,7 +12,7 @@ data class Query( } -inline fun Query( +inline fun Query( orderBy: List> = listOf(), skip: Int = 0, limit: Int = 100, diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/QueryPartial.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/QueryPartial.kt index de979454..e4ddacc6 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/QueryPartial.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/QueryPartial.kt @@ -1,10 +1,9 @@ package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.IsCodableAndHashable import kotlinx.serialization.Serializable @Serializable -data class QueryPartial( +data class QueryPartial( val fields: Set>, val condition: Condition = Condition.Always(), val orderBy: List> = listOf(), diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SerializableProperty.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SerializableProperty.kt index 5bf3819d..ef37fffd 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SerializableProperty.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SerializableProperty.kt @@ -1,5 +1,6 @@ package com.lightningkite.lightningdb +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.KSerializer import kotlinx.serialization.builtins.serializer import kotlinx.serialization.encoding.CompositeDecoder @@ -15,6 +16,7 @@ interface SerializableProperty { companion object { } } +@OptIn(ExperimentalSerializationApi::class) fun KSerializer.tryFindAnnotations(propertyName: String): List { val i = descriptor.getElementIndex(propertyName) if (i < 0) return listOf() diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SerializationHelpers.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SerializationHelpers.kt index 197ceea7..0c41e2ab 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SerializationHelpers.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SerializationHelpers.kt @@ -80,9 +80,17 @@ class KSerializerKey(val kSerializer: KSerializer<*>, val nullable: Boolean) { override fun toString(): String = kSerializer.toString() } + +@Suppress("NOTHING_TO_INLINE") private inline infix fun Int.hashWith(other: Int): Int = this * 31 + other + +@Suppress("NOTHING_TO_INLINE") private inline infix fun Int.hashWith(other: Any): Int = this * 31 + other.hashCode() + +@Suppress("NOTHING_TO_INLINE") private inline infix fun Any.hashWith(other: Int): Int = this.hashCode() * 31 + other + +@Suppress("NOTHING_TO_INLINE") private inline infix fun Any.hashWith(other: Any): Int = this.hashCode() * 31 + other.hashCode() diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SortBuilder.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SortBuilder.kt index 01438215..251e96ad 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SortBuilder.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SortBuilder.kt @@ -1,23 +1,20 @@ -@file:SharedCode - package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.* import com.lightningkite.lightningdb.SerializableProperty import kotlinx.serialization.KSerializer -inline fun sort(setup: SortBuilder.(DataClassPath) -> Unit): List> { +inline fun sort(setup: SortBuilder.(DataClassPath) -> Unit): List> { return SortBuilder().apply { setup(this, path()) }.build() } -class SortBuilder() { +class SortBuilder() { val sortParts = ArrayList>() fun add(sort: SortPart) { sortParts.add(sort) } fun build(): List> = sortParts.toList() - @JsName("ascending") fun DataClassPath.ascending() = add(SortPart(this, true)) - @JsName("descending") fun DataClassPath.descending() = add(SortPart(this, false)) - @JsName("ascendingString") fun DataClassPath.ascending(ignoreCase: Boolean) = add(SortPart(this, true, ignoreCase)) - @JsName("descendingString") fun DataClassPath.descending(ignoreCase: Boolean) = add(SortPart(this, false, ignoreCase)) + fun DataClassPath.ascending() = add(SortPart(this, true)) + fun DataClassPath.descending() = add(SortPart(this, false)) + fun DataClassPath.ascending(ignoreCase: Boolean) = add(SortPart(this, true, ignoreCase)) + fun DataClassPath.descending(ignoreCase: Boolean) = add(SortPart(this, false, ignoreCase)) } diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SortPart.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SortPart.kt index 72cf60bd..7d36ab34 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SortPart.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningdb/SortPart.kt @@ -1,21 +1,21 @@ -@file:SharedCode package com.lightningkite.lightningdb -import com.lightningkite.khrysalis.IsCodableAndHashable -import com.lightningkite.khrysalis.SharedCode + +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable import kotlinx.serialization.descriptors.PrimitiveKind import kotlin.reflect.KProperty1 @Serializable(SortPartSerializer::class) @Description("The name of the property to sort by. Prepend a '-' if you wish to sort descending.") -data class SortPart( +data class SortPart( val field: DataClassPathPartial, val ascending: Boolean = true, val ignoreCase: Boolean = false ) -val List>.comparator: Comparator? get() { +@OptIn(ExperimentalSerializationApi::class) +val List>.comparator: Comparator? get() { if(this.isEmpty()) return null return Comparator { a, b -> for(part in this) { diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/LSError.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/LSError.kt index 21a73616..633c96fe 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/LSError.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/LSError.kt @@ -1,7 +1,7 @@ -@file:SharedCode + package com.lightningkite.lightningserver -import com.lightningkite.khrysalis.SharedCode + import kotlinx.serialization.Serializable @Serializable diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/StringArrayFormat.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/StringArrayFormat.kt index 539ebfd5..7181bb69 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/StringArrayFormat.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/StringArrayFormat.kt @@ -11,6 +11,7 @@ import kotlinx.serialization.modules.SerializersModule class StringArrayFormat(override val serializersModule: SerializersModule) : StringFormat { + @OptIn(ExperimentalSerializationApi::class) private inner class DataOutputEncoder(val output: (String)->Unit) : AbstractEncoder() { override val serializersModule: SerializersModule get() = this@StringArrayFormat.serializersModule override fun encodeBoolean(value: Boolean) { output(value.toString()) } @@ -56,6 +57,7 @@ class StringArrayFormat(override val serializersModule: SerializersModule) : Str } } + @OptIn(ExperimentalSerializationApi::class) private inner class DataInputDecoder(val input: () -> String, var elementsCount: Int = 0, val seq: Boolean = false) : AbstractDecoder() { private var elementIndex = 0 override val serializersModule: SerializersModule get() = this@StringArrayFormat.serializersModule diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/auth/old/EmailPinLogin.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/auth/old/EmailPinLogin.kt index f730bf9b..8fdd840f 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/auth/old/EmailPinLogin.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/auth/old/EmailPinLogin.kt @@ -1,7 +1,7 @@ -@file:SharedCode + package com.lightningkite.lightningserver.auth.old -import com.lightningkite.khrysalis.SharedCode + import kotlinx.serialization.Serializable @Serializable diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/files/UploadEarlyEndpointModels.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/files/UploadEarlyEndpointModels.kt index 1f588802..57e1f1b8 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/files/UploadEarlyEndpointModels.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/files/UploadEarlyEndpointModels.kt @@ -1,10 +1,10 @@ -@file:SharedCode + @file:UseContextualSerialization(UUID::class, ServerFile::class, Instant::class) package com.lightningkite.lightningserver.files import com.lightningkite.UUID -import com.lightningkite.khrysalis.SharedCode + import com.lightningkite.lightningdb.GenerateDataClassPaths import com.lightningkite.lightningdb.HasId import com.lightningkite.lightningdb.ServerFile diff --git a/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/serverhealth/HealthStatus.kt b/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/serverhealth/HealthStatus.kt index f066be40..7469a4eb 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/serverhealth/HealthStatus.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/lightningserver/serverhealth/HealthStatus.kt @@ -1,8 +1,8 @@ -@file:SharedCode + @file:UseContextualSerialization(Instant::class) package com.lightningkite.lightningserver.serverhealth -import com.lightningkite.khrysalis.SharedCode + import kotlinx.datetime.Clock import com.lightningkite.now import kotlinx.serialization.Serializable diff --git a/shared/src/commonMain/kotlin/com/lightningkite/validate.kt b/shared/src/commonMain/kotlin/com/lightningkite/validate.kt index 3a01c366..3a9749fd 100644 --- a/shared/src/commonMain/kotlin/com/lightningkite/validate.kt +++ b/shared/src/commonMain/kotlin/com/lightningkite/validate.kt @@ -1,6 +1,7 @@ package com.lightningkite import com.lightningkite.lightningdb.* +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationStrategy @@ -49,6 +50,7 @@ object Validators { inline fun processor(crossinline action: (T, V) -> ValidationIssuePart?) { directProcessor(T::class) { a, b -> if (a is T) { + @Suppress("UNCHECKED_CAST") if(b is Collection<*>) b.asSequence().mapNotNull { action(a, it as V) }.firstOrNull() else if(b is Map<*, *>) @@ -60,10 +62,13 @@ object Validators { } inline fun directProcessor(crossinline action: (T, V) -> ValidationIssuePart?) { - directProcessor(T::class) { a, b -> if (a is T) action(a, b as V) else null } + directProcessor(T::class) { a, b -> + @Suppress("UNCHECKED_CAST") + if (a is T) action(a, b as V) else null + } } - fun directProcessor(type: KClass, action: (Annotation, Any?) -> ValidationIssuePart?) { + fun directProcessor(@Suppress("UNUSED_PARAMETER") type: KClass, action: (Annotation, Any?) -> ValidationIssuePart?) { processors.add(action) } @@ -71,6 +76,7 @@ object Validators { inline fun suspendProcessor(crossinline action: suspend (T, V) -> ValidationIssuePart?) { directSuspendProcessor(T::class) { a, b -> if (a is T) { + @Suppress("UNCHECKED_CAST") if(b is Collection<*>) b.mapNotNull { action(a, it as V) }.firstOrNull() else if(b is Map<*, *>) @@ -81,9 +87,12 @@ object Validators { } } inline fun directSuspendProcessor(crossinline action: suspend (T, V) -> ValidationIssuePart?) { - directSuspendProcessor(T::class) { a, b -> if (a is T) action(a, b as V) else null } + directSuspendProcessor(T::class) { a, b -> + @Suppress("UNCHECKED_CAST") + if (a is T) action(a, b as V) else null + } } - fun directSuspendProcessor(type: KClass, action: suspend (Annotation, Any?) -> ValidationIssuePart?) { + fun directSuspendProcessor(@Suppress("UNUSED_PARAMETER") type: KClass, action: suspend (Annotation, Any?) -> ValidationIssuePart?) { suspendProcessors.add(action) } @@ -196,6 +205,7 @@ object Validators { } } +@OptIn(ExperimentalSerializationApi::class) private class ValidationEncoder(override val serializersModule: SerializersModule, val out: ValidationOut) : AbstractEncoder() { diff --git a/shared/src/commonTest/kotlin/models.kt b/shared/src/commonTest/kotlin/models.kt index 8cd6e040..c326d7c8 100644 --- a/shared/src/commonTest/kotlin/models.kt +++ b/shared/src/commonTest/kotlin/models.kt @@ -1,11 +1,11 @@ -@file:SharedCode + @file:UseContextualSerialization(UUID::class, Instant::class) package com.lightningkite.lightningdb import com.lightningkite.TrimmedCaselessString import com.lightningkite.UUID import com.lightningkite.ZonedDateTime -import com.lightningkite.khrysalis.SharedCode + import com.lightningkite.uuid import kotlinx.serialization.Contextual import kotlinx.serialization.Serializable diff --git a/shared/src/iosMain/kotlin/com/lightningkite/UUID.ios.kt b/shared/src/iosMain/kotlin/com/lightningkite/UUID.ios.kt index 5dab63e1..0dd9be42 100644 --- a/shared/src/iosMain/kotlin/com/lightningkite/UUID.ios.kt +++ b/shared/src/iosMain/kotlin/com/lightningkite/UUID.ios.kt @@ -2,6 +2,7 @@ package com.lightningkite import platform.Foundation.NSUUID +@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") actual class UUIDRaw(val ns: NSUUID): Comparable { actual override fun compareTo(other: UUIDRaw): Int = ns.compare(other.ns).toInt() override fun hashCode(): Int = ns.hashCode() diff --git a/shared/src/jsMain/kotlin/UUID.js.kt b/shared/src/jsMain/kotlin/UUID.js.kt index a37d18be..60512054 100644 --- a/shared/src/jsMain/kotlin/UUID.js.kt +++ b/shared/src/jsMain/kotlin/UUID.js.kt @@ -2,6 +2,7 @@ package com.lightningkite import kotlinx.browser.window +@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") actual data class UUIDRaw(val string: String): Comparable { init { if(!uuidRegex.matches(string)) throw IllegalArgumentException("Invalid UUID string: $string") diff --git a/shared/src/jvmMain/kotlin/com/lightningkite/UUID.jvm.kt b/shared/src/jvmMain/kotlin/com/lightningkite/UUID.jvm.kt index f77f63d8..246f54c4 100644 --- a/shared/src/jvmMain/kotlin/com/lightningkite/UUID.jvm.kt +++ b/shared/src/jvmMain/kotlin/com/lightningkite/UUID.jvm.kt @@ -1,3 +1,5 @@ +@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") + package com.lightningkite actual typealias UUIDRaw = java.util.UUID diff --git a/web-alt/package-lock.json b/web-alt/package-lock.json index f68580cf..80f148a6 100644 --- a/web-alt/package-lock.json +++ b/web-alt/package-lock.json @@ -10,8 +10,6 @@ "license": "MIT", "dependencies": { "@js-joda/core": "^4.3.1", - "@lightningkite/khrysalis-runtime": "1.0.1", - "@lightningkite/rxjs-plus": "1.0.0", "@types/mersenne-twister": "1.x", "@types/sprintf-js": "1.1.x", "@types/uuid": "8.x", diff --git a/web-alt/package.json b/web-alt/package.json index 04fc1fd8..291854b0 100644 --- a/web-alt/package.json +++ b/web-alt/package.json @@ -13,9 +13,7 @@ "sprintf-js": "1.1.x", "@types/sprintf-js": "1.1.x", "mersenne-twister": "1.x", - "@types/mersenne-twister": "1.x", - "@lightningkite/khrysalis-runtime": "1.0.1", - "@lightningkite/rxjs-plus": "1.0.0" + "@types/mersenne-twister": "1.x" }, "devDependencies": { "typescript": "^4.5.2",
Click here to login