From 7404e5eb32b5d246693e33ddb529cb49e6346c2e Mon Sep 17 00:00:00 2001 From: tamimattafi <35191844+tamimattafi@users.noreply.github.com> Date: Thu, 23 May 2024 03:25:19 +0700 Subject: [PATCH] fix: paramters count and binding issues, bump kotlin (#23) --- README.md | 15 ++-- .../kabin/publish/PublishConventions.kt | 2 +- gradle/libs.versions.toml | 10 +-- .../sql/generator/queries/QueriesGenerator.kt | 78 ++++++------------- .../kabin/compiler/sql/syntax/SQLQuery.kt | 1 + .../utils/poet/dao/PoetDaoFunctionUtils.kt | 20 ++++- .../poet/sqldelight/PoetSqlDelightUtils.kt | 10 +-- .../sql/utils/sql/dao/SQLDaoActionUtils.kt | 15 ++-- .../attafitamim/kabin/local/dao/UserDao.kt | 4 + 9 files changed, 74 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 2e134ef..9ce6ae3 100644 --- a/README.md +++ b/README.md @@ -312,10 +312,11 @@ This list shows Room features, which are already supported by Kabin, or under de - `@Junction` inside a compound is automatically created and inserted as well ## Plans and Priorities -1. [ ] Clean and refactor `compiler` and `processor` logic, make it more flexible and maintainable -2. [ ] Generate more optimized code -3. [ ] Fix bugs and issues -4. [ ] Implement more **Room** features, especially the essential ones for basic and simple apps -5. [ ] Add more features to make working with SQL easier and more interesting -6. [ ] Add multiplatform sample with UI -7. [ ] Make a stable release +1. [ ] Add Tests +2. [ ] Clean and refactor `compiler` and `processor` logic, make it more flexible and maintainable +3. [ ] Generate more optimized code +4. [ ] Fix bugs and issues +5. [ ] Implement more **Room** features, especially the essential ones for basic and simple apps +6. [ ] Add more features to make working with SQL easier and more interesting +7. [ ] Add multiplatform sample with UI +8. [ ] Make a stable release diff --git a/convention/publishing/src/main/kotlin/com/attafitamim/kabin/publish/PublishConventions.kt b/convention/publishing/src/main/kotlin/com/attafitamim/kabin/publish/PublishConventions.kt index 18fbeb1..5fcdb0f 100644 --- a/convention/publishing/src/main/kotlin/com/attafitamim/kabin/publish/PublishConventions.kt +++ b/convention/publishing/src/main/kotlin/com/attafitamim/kabin/publish/PublishConventions.kt @@ -10,7 +10,7 @@ import org.gradle.api.publish.maven.MavenPomScm class PublishConventions : Plugin { - private val version = "0.1.0-alpha09" + private val version = "0.1.0-alpha10" private val group = "com.attafitamim.kabin" override fun apply(project: Project) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ad3ff40..4970ef9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] # Android -android-gradle-plugin = "8.3.1" -core-ktx = "1.12.0" +android-gradle-plugin = "8.3.2" +core-ktx = "1.13.1" junit = "4.13.2" androidx-test-ext-junit = "1.1.5" espresso-core = "3.5.1" @@ -9,13 +9,13 @@ appcompat = "1.6.1" material = "1.11.0" # Kotlin -kotlin = "1.9.23" +kotlin = "1.9.24" kotlin-poet = "1.16.0" kotlin-coroutines = "1.8.0" -kotlin-ksp = "1.9.23-1.0.19" +kotlin-ksp = "1.9.24-1.0.20" # Docs -dokka = "1.9.10" +dokka = "1.9.20" # Publishing maven-publish = "0.28.0" diff --git a/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/generator/queries/QueriesGenerator.kt b/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/generator/queries/QueriesGenerator.kt index b522fb6..58ad7d0 100644 --- a/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/generator/queries/QueriesGenerator.kt +++ b/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/generator/queries/QueriesGenerator.kt @@ -14,6 +14,7 @@ import com.attafitamim.kabin.compiler.sql.syntax.SQLQuery import com.attafitamim.kabin.compiler.sql.utils.poet.SYMBOL_ACCESS_SIGN import com.attafitamim.kabin.compiler.sql.utils.poet.asSpecs import com.attafitamim.kabin.compiler.sql.utils.poet.buildSpec +import com.attafitamim.kabin.compiler.sql.utils.poet.dao.getAccessChain import com.attafitamim.kabin.compiler.sql.utils.poet.dao.getAdapterReference import com.attafitamim.kabin.compiler.sql.utils.poet.dao.getColumnAccessChain import com.attafitamim.kabin.compiler.sql.utils.poet.dao.supportedBinders @@ -552,7 +553,7 @@ class QueriesGenerator( EXECUTE_FUNCTION, ) { val requiredAdapters = addQueryEntityBinding( - query.columns, + query, parameterName ) @@ -708,7 +709,7 @@ class QueriesGenerator( EXECUTE_FUNCTION ) { val junctionAdapters = addQueryEntityBinding( - query.columns, + query, junctionName ) @@ -815,7 +816,7 @@ class QueriesGenerator( EXECUTE_QUERY_FUNCTION ) { val bindingAdapters = addQueryEntityBinding( - query.columns, + query, entityParameter.name ) @@ -901,16 +902,16 @@ class QueriesGenerator( } private fun CodeBlock.Builder.addQueryEntityBinding( - columns: Collection, + query: SQLQuery.Columns, parent: String? = null ): Set { - if (columns.isEmpty()) { + if (query.columns.isEmpty()) { return emptySet() } beginControlFlow("") val adapters = addQueryEntityColumnsBinding( - columns, + query, parent ) @@ -921,13 +922,13 @@ class QueriesGenerator( private fun CodeBlock.Builder.addQueryBinding( query: SQLQuery ): Set = when (query) { - is SQLQuery.Columns -> addQueryEntityBinding(query.columns) + is SQLQuery.Columns -> addQueryEntityBinding(query) is SQLQuery.Parameters -> addQueryParametersBinding(query.queryParameters) is SQLQuery.Raw -> emptySet() } private fun CodeBlock.Builder.addQueryEntityColumnsBinding( - columns: Collection, + query: SQLQuery.Columns, parent: String? = null, initialIndex: Int = 0, isParentNullable: Boolean = false @@ -935,55 +936,27 @@ class QueriesGenerator( val adapters = HashSet() var currentIndex = initialIndex - columns.forEach { columnSpec -> + query.parameters.forEach { parameter -> + val columnAccessChain = query.columns + .getAccessChain(parameter) + + val columnAccess = columnAccessChain.toParameterAccess(parent, isParentNullable) + val columnSpec = columnAccessChain.last() val isNullable = isParentNullable || columnSpec.typeSpec.isNullable - val propertyName = columnSpec.declaration.simpleName.asString() - val propertyAccess = if (parent.isNullOrBlank()) { - propertyName - } else { - buildString { - append(parent) - if (isParentNullable) { - append("?") - } + val adapter = addQueryParameterBinding( + isNullable, + columnAccess, + currentIndex.toString(), + columnSpec.typeAffinity, + columnSpec.typeSpec.type + ) - append( - SYMBOL_ACCESS_SIGN, - propertyName - ) - } + if (adapter != null) { + adapters.add(adapter) } - when (val dataType = columnSpec.typeSpec.dataType) { - is ColumnTypeSpec.DataType.Class -> { - val adapter = addQueryParameterBinding( - isNullable, - propertyAccess, - currentIndex.toString(), - columnSpec.typeAffinity, - columnSpec.typeSpec.type - ) - - if (adapter != null) { - adapters.add(adapter) - } - - currentIndex++ - } - - is ColumnTypeSpec.DataType.Embedded -> { - val requiredAdapters = addQueryEntityColumnsBinding( - dataType.columns, - propertyAccess, - currentIndex, - isNullable - ) - - adapters.addAll(requiredAdapters) - currentIndex += getFlatColumns(dataType.columns).size - } - } + currentIndex++ } return adapters @@ -1014,7 +987,6 @@ class QueriesGenerator( "$dynamicSizes + $previousSimpleParametersCount" } - when (queryParameter.spec.typeSpec.dataType) { is DataTypeSpec.DataType.Entity, is DataTypeSpec.DataType.Stream, diff --git a/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/syntax/SQLQuery.kt b/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/syntax/SQLQuery.kt index 9727728..3d3897f 100644 --- a/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/syntax/SQLQuery.kt +++ b/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/syntax/SQLQuery.kt @@ -27,6 +27,7 @@ sealed interface SQLQuery { override val value: String, override val parametersSize: Int, val columns: Collection, + val parameters: Collection, val mutatedKeys: Set, override val queriedKeys: Set ): SQLQuery diff --git a/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/poet/dao/PoetDaoFunctionUtils.kt b/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/poet/dao/PoetDaoFunctionUtils.kt index 45cd29e..90ce6c1 100644 --- a/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/poet/dao/PoetDaoFunctionUtils.kt +++ b/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/poet/dao/PoetDaoFunctionUtils.kt @@ -101,13 +101,27 @@ fun EntitySpec.getColumnParameterAccess(columnName: String): String { return chain.toParameterAccess() } -fun List.toParameterAccess(): String { +fun List.toParameterAccess( + parent: String? = null, + isParentNullable: Boolean = false +): String { val stringBuilder = StringBuilder() + + if (!parent.isNullOrBlank()) { + stringBuilder.append(parent) + + if (isParentNullable) { + stringBuilder.append("?") + } + + stringBuilder.append(SYMBOL_ACCESS_SIGN) + } + for (columnIndex in 0 until lastIndex) { val column = this[columnIndex] stringBuilder.append(column.declaration.simpleNameString) - if (column.typeSpec.isNullable) { + if (column.typeSpec.isNullable || isParentNullable) { stringBuilder.append("?") } @@ -149,7 +163,7 @@ fun ColumnSpec.getAccessChain(columnName: String): List { return chain } -fun List.getAccessChain(columnName: String): List { +fun Collection.getAccessChain(columnName: String): List { forEach { columnSpec -> val chain = columnSpec.getAccessChain(columnName) if (chain.isNotEmpty()) { diff --git a/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/poet/sqldelight/PoetSqlDelightUtils.kt b/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/poet/sqldelight/PoetSqlDelightUtils.kt index f05c53f..e582533 100644 --- a/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/poet/sqldelight/PoetSqlDelightUtils.kt +++ b/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/poet/sqldelight/PoetSqlDelightUtils.kt @@ -56,7 +56,7 @@ fun FunSpec.Builder.addDriverRawQueryCode( function: String, binderCode: (CodeBlock.Builder.() -> Unit)? = null ): FunSpec.Builder = apply { - val logic = if (function == "executeQuery") { + val logic = if (function == EXECUTE_QUERY_FUNCTION) { """ |val result = driver.executeQuery( | null, @@ -82,7 +82,7 @@ fun FunSpec.Builder.addDriverRawQueryCode( codeBlockBuilder.binderCode() } - if (function == "executeQuery") { + if (function == EXECUTE_QUERY_FUNCTION) { codeBlockBuilder.addStatement("return result") } @@ -201,13 +201,13 @@ fun FunSpec.Builder.addDriverQueryCode( val codeBlockBuilder = CodeBlock.builder() val identifier = query.hashCode() - val logic = if (function == "executeQuery") { + val logic = if (function == EXECUTE_QUERY_FUNCTION) { """ |val result = driver.executeQuery( | $identifier, | %P, | mapper, - | ${parameters.size} + | ${query.parametersSize} |) """.trimMargin() } else { @@ -215,7 +215,7 @@ fun FunSpec.Builder.addDriverQueryCode( |driver.execute( | $identifier, | %P, - | ${parameters.size} + | ${query.parametersSize} |) """.trimMargin() } diff --git a/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/sql/dao/SQLDaoActionUtils.kt b/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/sql/dao/SQLDaoActionUtils.kt index 2f8649d..ee274e4 100644 --- a/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/sql/dao/SQLDaoActionUtils.kt +++ b/library/compiler/src/jvmMain/kotlin/com/attafitamim/kabin/compiler/sql/utils/sql/dao/SQLDaoActionUtils.kt @@ -244,6 +244,7 @@ fun getSelectSQLQuery( query, parameters.size, columns, + parameters, mutatedKeys = emptySet(), queriedKeys = setOf(entitySpec.tableName) ) @@ -258,14 +259,11 @@ fun DaoActionSpec.Delete.getSQLQuery( DELETE; FROM(entity.tableName); WHERE.equalParameters(parameters) } - val columns = entity.columns.filter { columnSpec -> - parameters.contains(columnSpec.name) - } - return SQLQuery.Columns( query, parameters.size, - columns, + entity.columns, + parameters, mutatedKeys = setOf(entity.tableName), queriedKeys = emptySet() ) @@ -286,6 +284,7 @@ fun DaoActionSpec.Insert.getSQLQuery( query, parameters.size, entity.columns, + parameters, mutatedKeys = setOf(entity.tableName), queriedKeys = emptySet() ) @@ -304,11 +303,12 @@ fun DaoActionSpec.Update.getSQLQuery( WHERE.equalParameters(entity.primaryKeys) } - val parametersSize = parameters.size + primaryKeys.size + val totalParameters = parameters + primaryKeys return SQLQuery.Columns( query, - parametersSize, + totalParameters.size, entity.columns, + totalParameters, mutatedKeys = setOf(entity.tableName), queriedKeys = emptySet() ) @@ -329,6 +329,7 @@ fun DaoActionSpec.Upsert.getSQLQuery( query, parameters.size, actualEntitySpec.columns, + parameters, mutatedKeys = setOf(entity.tableName), queriedKeys = emptySet() ) diff --git a/sample/shared/src/commonMain/kotlin/com/attafitamim/kabin/local/dao/UserDao.kt b/sample/shared/src/commonMain/kotlin/com/attafitamim/kabin/local/dao/UserDao.kt index 73ccabb..cde400a 100644 --- a/sample/shared/src/commonMain/kotlin/com/attafitamim/kabin/local/dao/UserDao.kt +++ b/sample/shared/src/commonMain/kotlin/com/attafitamim/kabin/local/dao/UserDao.kt @@ -9,6 +9,7 @@ import com.attafitamim.kabin.annotations.RawQuery import com.attafitamim.kabin.annotations.Transaction import com.attafitamim.kabin.annotations.Update import com.attafitamim.kabin.local.entities.bank.BankEntity +import com.attafitamim.kabin.local.entities.bank.CardEntity import com.attafitamim.kabin.local.entities.user.MarriedCount import com.attafitamim.kabin.local.entities.user.UserEntity import kotlinx.coroutines.flow.Flow @@ -34,6 +35,9 @@ interface UserDao { @Update suspend fun update(entity: UserEntity) + @Update + suspend fun update(entity: CardEntity) + @Delete @Transaction suspend fun delete(entity: UserEntity)