From b5afa116618a83c5571345d74a029c1555390633 Mon Sep 17 00:00:00 2001 From: Mike Dawson Date: Sun, 14 Jul 2024 21:53:30 +0400 Subject: [PATCH] Update handling of missing server side parameters. When a query parameter is not sent by the client (e.g. older version of client, newer version of server) this would have thrown an exception before. Query parameter will now use the default value for type if not sent by client (e.g. 0, false, null). --- build.gradle | 2 +- .../core/DoorHttpServerProcessor.kt | 19 +++++++++++++++---- .../ustadmobile/door/http/DoorJsonRequest.kt | 4 ++++ .../door/ktor/KtorDoorJsonRequestAdapter.kt | 9 +++++++++ .../kotlin/db3/DiscussionPostDao.kt | 13 +++++++++++++ 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 328025c4..39e4ecc5 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ plugins { group 'com.github.UstadMobile.door' -version '0.79.11' +version '0.79.12' ext.localProperties = new Properties() diff --git a/door-compiler/src/main/kotlin/com/ustadmobile/lib/annotationprocessor/core/DoorHttpServerProcessor.kt b/door-compiler/src/main/kotlin/com/ustadmobile/lib/annotationprocessor/core/DoorHttpServerProcessor.kt index 252d509d..cf382968 100644 --- a/door-compiler/src/main/kotlin/com/ustadmobile/lib/annotationprocessor/core/DoorHttpServerProcessor.kt +++ b/door-compiler/src/main/kotlin/com/ustadmobile/lib/annotationprocessor/core/DoorHttpServerProcessor.kt @@ -612,13 +612,24 @@ fun FileSpec.Builder.addHttpServerExtensionFun( .apply { daoFunDecl.parameters.forEachIndexed { index, param -> add("val _arg_${param.name?.asString()} : %T = ", funAsMemberOfDao.parameterTypes[index]?.toTypeName()) - add("json.decodeFromString(") - addKotlinxSerializationStrategy(funAsMemberOfDao.parameterTypes[index]!!, resolver) + if(param.hasAnnotation(RepoHttpBodyParam::class)) { - add(", request.requireBodyAsString())\n") + add("request.bodyAsStringOrNull()") }else { - add(", request.requireParam(%S))\n", param.name?.asString()) + add("request.queryParam(%S)", param.name?.asString()) + } + beginControlFlow("?.let") + add("json.decodeFromString(") + addKotlinxSerializationStrategy(funAsMemberOfDao.parameterTypes[index]!!, resolver) + add(", it)\n") + unindent().add("}") + + val paramTypeResolved = param.type.resolve() + if(!paramTypeResolved.isMarkedNullable) { + add(" ?: ") + add(param.type.resolve().defaultTypeValueCode(resolver)) } + add("\n") } if(daoFunDecl.returnType?.resolve()?.isPagingSource() == true) { diff --git a/door-runtime/src/commonMain/kotlin/com/ustadmobile/door/http/DoorJsonRequest.kt b/door-runtime/src/commonMain/kotlin/com/ustadmobile/door/http/DoorJsonRequest.kt index 65ea7121..ec5e20ab 100644 --- a/door-runtime/src/commonMain/kotlin/com/ustadmobile/door/http/DoorJsonRequest.kt +++ b/door-runtime/src/commonMain/kotlin/com/ustadmobile/door/http/DoorJsonRequest.kt @@ -9,10 +9,14 @@ interface DoorJsonRequest { */ val db: RoomDatabase + fun queryParam(paramName: String): String? + fun requireParam(paramName: String): String suspend fun requireBodyAsString(): String + suspend fun bodyAsStringOrNull(): String? + fun requireHeader(header: String): String fun requireNodeId(): Long diff --git a/door-runtime/src/jvmMain/kotlin/com/ustadmobile/door/ktor/KtorDoorJsonRequestAdapter.kt b/door-runtime/src/jvmMain/kotlin/com/ustadmobile/door/ktor/KtorDoorJsonRequestAdapter.kt index 1e759da2..d9095554 100644 --- a/door-runtime/src/jvmMain/kotlin/com/ustadmobile/door/ktor/KtorDoorJsonRequestAdapter.kt +++ b/door-runtime/src/jvmMain/kotlin/com/ustadmobile/door/ktor/KtorDoorJsonRequestAdapter.kt @@ -11,6 +11,10 @@ class KtorDoorJsonRequestAdapter( override val db: RoomDatabase, ) : DoorJsonRequest { + override fun queryParam(paramName: String): String? { + return call.request.queryParameters[paramName] + } + override fun requireParam(paramName: String): String { return call.request.queryParameters[paramName] ?: throw IllegalStateException("requireStringParam: $paramName not found") @@ -20,6 +24,11 @@ class KtorDoorJsonRequestAdapter( return call.receiveText() } + @Suppress("RedundantNullableReturnType") + override suspend fun bodyAsStringOrNull(): String? { + return requireBodyAsString() + } + override fun requireHeader(header: String): String { return call.request.header(header) ?: throw IllegalStateException("requireHeader: $header not found") } diff --git a/door-testdb/src/commonMain/kotlin/db3/DiscussionPostDao.kt b/door-testdb/src/commonMain/kotlin/db3/DiscussionPostDao.kt index ca179c4d..89afb341 100644 --- a/door-testdb/src/commonMain/kotlin/db3/DiscussionPostDao.kt +++ b/door-testdb/src/commonMain/kotlin/db3/DiscussionPostDao.kt @@ -317,4 +317,17 @@ expect abstract class DiscussionPostDao : RepositoryFlowLoadingStatusProvider { @Update abstract suspend fun update(post: DiscussionPost) + @HttpAccessible + @Query(""" + SELECT DiscussionPost.*, + Member.firstName AS firstName, + Member.lastName AS lastName + FROM DiscussionPost + LEFT JOIN Member + ON Member.memberUid = DiscussionPost.posterMemberUid + WHERE Member.firstName = :firstName + """) + abstract suspend fun findByName(firstName: String?): List + + } \ No newline at end of file