diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e8ae886..1cc927d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -73,13 +73,13 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-33 + key: avd-34 - name: Create AVD and Generate Snapshot for Caching if: steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@v2 with: - api-level: 33 + api-level: 34 target: google_apis arch: x86_64 profile: pixel_6 @@ -88,10 +88,10 @@ jobs: disable-animations: false script: echo "Generated AVD snapshot for caching." - - name: Run Android 13 Instrumented Tests + - name: Run Android 14 Instrumented Tests uses: reactivecircus/android-emulator-runner@v2 with: - api-level: 33 + api-level: 34 target: google_apis arch: x86_64 profile: pixel_6 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 72a7caa..2e0cec0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -68,13 +68,13 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-33 + key: avd-34 - name: Create AVD and Generate Snapshot for Caching if: steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@v2 with: - api-level: 33 + api-level: 34 target: google_apis arch: x86_64 profile: pixel_6 @@ -83,10 +83,10 @@ jobs: disable-animations: false script: echo "Generated AVD snapshot for caching." - - name: Run Android 13 Instrumented Tests + - name: Run Android 14 Instrumented Tests uses: reactivecircus/android-emulator-runner@v2 with: - api-level: 33 + api-level: 34 target: google_apis arch: x86_64 profile: pixel_6 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3edceeb..6bbf68f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ - Date format: YYYY-MM-dd -## v1.3.0 / 2024-04-16 +## v1.3.0 / 2024-04-21 ### All @@ -13,7 +13,8 @@ * Update `kotlinx.coroutines`'s version to `1.8.0` * Update `kotlinx.serialization`'s version to `1.6.3` * Modify the SQL statements' splicing method, that fixed the [issue#77](https://github.com/ctripcorp/SQLlin/issues/77) that users can't read/write special symbols as the values in SQL statements. -* Performance optimization, use `ArrayDeque` to replace the LinkedList for SQL statements management (self-implemented) +* Performance optimization, use `ArrayDeque` to replace the LinkedList for SQL statements management (self-implemented). +* The parameter `enableSimpleSQLLog` of the `Database`'s constructors of is `false` by default. ### sqllin-driver diff --git a/sample/src/commonMain/kotlin/com/ctrip/sqllin/sample/Sample.kt b/sample/src/commonMain/kotlin/com/ctrip/sqllin/sample/Sample.kt index 3e71d6f..5371001 100644 --- a/sample/src/commonMain/kotlin/com/ctrip/sqllin/sample/Sample.kt +++ b/sample/src/commonMain/kotlin/com/ctrip/sqllin/sample/Sample.kt @@ -49,7 +49,8 @@ object Sample { upgrade = { _, _, _ -> // You must write SQL to String when the database is created or upgraded } - ) + ), + enableSimpleSQLLog = true, ) } diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/Database.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/Database.kt index 17de530..2a1c4bc 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/Database.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/Database.kt @@ -29,14 +29,14 @@ import kotlinx.coroutines.sync.withLock public class Database( configuration: DatabaseConfiguration, - private val enableSimpleSQLLog: Boolean = true, + private val enableSimpleSQLLog: Boolean = false, ) { public constructor( name: String, path: DatabasePath, version: Int, - enableSimpleSQLLog: Boolean = true, + enableSimpleSQLLog: Boolean = false, ) : this( DatabaseConfiguration( name = name, diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt index 3b1c00d..3b89967 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt @@ -37,9 +37,9 @@ public class ClauseBoolean( } append(valueName) if (bool) - append(" > ") + append('>') else - append(" <= ") + append("<=") append(0) } return SelectCondition(sql, null) diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt index ad7dfa4..e569583 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt @@ -106,9 +106,7 @@ public class ClauseNumber( append('.') } append(valueName) - append(' ') append(symbol) - append(' ') append(number) } return SelectCondition(sql, null) @@ -121,10 +119,14 @@ public class ClauseNumber( append('.') } append(valueName) - append(' ') - append(if (number == null) nullSymbol else notNullSymbol) - append(' ') - append(number ?: "NULL") + if (number == null){ + append(nullSymbol) + append(" NULL") + + } else { + append(notNullSymbol) + append(number) + } } return SelectCondition(sql, null) } @@ -134,9 +136,7 @@ public class ClauseNumber( append(table.tableName) append('.') append(valueName) - append(' ') append(symbol) - append(' ') append(clauseNumber.table.tableName) append('.') append(clauseNumber.valueName) diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt index 095a6d8..b897a20 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt @@ -52,9 +52,8 @@ public class ClauseString( append('.') } append(valueName) - append(' ') append(symbol) - append(" ?") + append('?') } return SelectCondition(sql, mutableListOf(regex)) } @@ -66,14 +65,13 @@ public class ClauseString( append('.') } append(valueName) - append(' ') val isNull = str == null val symbol = if (isNull) nullSymbol else notNullSymbol append(symbol) if (str == null) append(" NULL") else - append(" ?") + append('?') } return SelectCondition(sql, if (str == null) null else mutableListOf(str)) } diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt index 1100ff5..b443404 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt @@ -39,8 +39,8 @@ internal class CompleteOrderByClause(private val column2WayMap: Map(private val columns: Iterable ORDER_BY(vararg elements: ClauseElement): OrderByClause = SimpleOrderByClause(elements.toList()) -@Suppress("NOTHING_TO_INLINE") public inline infix fun WhereSelectStatement.ORDER_BY(column: ClauseElement): OrderBySelectStatement = ORDER_BY(listOf(column)) @@ -115,7 +113,6 @@ public infix fun WhereSelectStatement.ORDER_BY(columns: Iterable HavingSelectStatement.ORDER_BY(column: ClauseElement): OrderBySelectStatement = ORDER_BY(listOf(column)) @@ -124,7 +121,6 @@ public infix fun HavingSelectStatement.ORDER_BY(columns: Iterable GroupBySelectStatement.ORDER_BY(column: ClauseElement): OrderBySelectStatement = ORDER_BY(listOf(column)) @@ -133,7 +129,6 @@ public infix fun GroupBySelectStatement.ORDER_BY(columns: Iterable JoinSelectStatement.ORDER_BY(column: ClauseElement): OrderBySelectStatement = ORDER_BY(listOf(column)) diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt index 8768481..69e37e8 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt @@ -51,7 +51,7 @@ internal object Select : Operation { connection: DatabaseConnection, container: StatementContainer, ): OrderBySelectStatement = - OrderBySelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, mutableListOf()) + OrderBySelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, null) fun select( table: Table, diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt index dd98d59..3eda9eb 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt @@ -45,7 +45,7 @@ internal class DatabaseExecuteEngine( when (it) { is SingleStatement -> { if (enableSimpleSQLLog) - println("SQL String: ${it.sqlStr}") + it.printlnSQL() it.execute() } is TransactionStatementsGroup -> it.execute() diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SingleStatement.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SingleStatement.kt index 3463fd9..9e90463 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SingleStatement.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SingleStatement.kt @@ -29,4 +29,11 @@ public sealed class SingleStatement( internal val params: Array? get() = parameters?.toTypedArray() + + internal fun printlnSQL() { + print("SQL String: $sqlStr") + parameters?.let { + println("; Parameters: $it") + } ?: println() + } } \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/TransactionStatementsGroup.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/TransactionStatementsGroup.kt index ce04053..3d78389 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/TransactionStatementsGroup.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/TransactionStatementsGroup.kt @@ -38,7 +38,7 @@ internal class TransactionStatementsGroup( override fun execute() = databaseConnection.withTransaction { statementList.forEach { if (enableSimpleSQLLog) - println("SQL String: ${it.sqlStr}") + it.printlnSQL() it.execute() } } diff --git a/sqllin-dsl/src/commonTest/kotlin/com/ctrip/sqllin/dsl/CommonBasicTest.kt b/sqllin-dsl/src/commonTest/kotlin/com/ctrip/sqllin/dsl/CommonBasicTest.kt index ae2fbfa..b2a63bf 100644 --- a/sqllin-dsl/src/commonTest/kotlin/com/ctrip/sqllin/dsl/CommonBasicTest.kt +++ b/sqllin-dsl/src/commonTest/kotlin/com/ctrip/sqllin/dsl/CommonBasicTest.kt @@ -49,7 +49,7 @@ class CommonBasicTest(private val path: DatabasePath) { close() } - fun testInsert() = Database(getDefaultDBConfig()).databaseAutoClose { database -> + fun testInsert() = Database(getDefaultDBConfig(), true).databaseAutoClose { database -> val book = Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96) database { BookTable { bookTable -> @@ -65,7 +65,7 @@ class CommonBasicTest(private val path: DatabasePath) { assertEquals(book, statement?.getResults()?.firstOrNull()) } - fun testDelete() = Database(getDefaultDBConfig()).databaseAutoClose { database -> + fun testDelete() = Database(getDefaultDBConfig(), true).databaseAutoClose { database -> val book1 = Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96) val book2 = Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95) var statement: SelectStatement? = null @@ -92,7 +92,7 @@ class CommonBasicTest(private val path: DatabasePath) { assertEquals(true, statement2!!.getResults().isEmpty()) } - fun testUpdate() = Database(getDefaultDBConfig()).databaseAutoClose { database -> + fun testUpdate() = Database(getDefaultDBConfig(), true).databaseAutoClose { database -> val book1 = Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96) val book2 = Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95) var statement: SelectStatement? = null @@ -126,7 +126,7 @@ class CommonBasicTest(private val path: DatabasePath) { assertEquals(true, newResult!!.getResults().any { it == newBook2 }) } - fun testSelectWhereClause() = Database(getDefaultDBConfig()).databaseAutoClose { database -> + fun testSelectWhereClause() = Database(getDefaultDBConfig(), true).databaseAutoClose { database -> val book0 = Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96) val book1 = Book(name = "Kotlin Cookbook", author = "Ken Kousen", pages = 251, price = 37.72) val book2 = Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95) @@ -149,7 +149,7 @@ class CommonBasicTest(private val path: DatabasePath) { assertEquals(book1, statementOfWhere2?.getResults()?.firstOrNull()) } - fun testSelectOrderByClause() = Database(getDefaultDBConfig()).databaseAutoClose { database -> + fun testSelectOrderByClause() = Database(getDefaultDBConfig(), true).databaseAutoClose { database -> val book0 = Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96) val book1 = Book(name = "Kotlin Cookbook", author = "Ken Kousen", pages = 251, price = 37.72) val book2 = Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95) @@ -209,7 +209,7 @@ class CommonBasicTest(private val path: DatabasePath) { } } - fun testSelectLimitAndOffsetClause() = Database(getDefaultDBConfig()).databaseAutoClose { database -> + fun testSelectLimitAndOffsetClause() = Database(getDefaultDBConfig(), true).databaseAutoClose { database -> val book0 = Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96) val book1 = Book(name = "Kotlin Cookbook", author = "Ken Kousen", pages = 251, price = 37.72) val book2 = Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95) @@ -229,7 +229,7 @@ class CommonBasicTest(private val path: DatabasePath) { assertEquals(1, statementOfLimitAndOffset?.getResults()?.size) } - fun testGroupByAndHavingClause() = Database(getDefaultDBConfig()).databaseAutoClose { database -> + fun testGroupByAndHavingClause() = Database(getDefaultDBConfig(), true).databaseAutoClose { database -> val book0 = Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96) val book1 = Book(name = "Kotlin Cookbook", author = "Ken Kousen", pages = 251, price = 37.72) val book2 = Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95) @@ -261,7 +261,7 @@ class CommonBasicTest(private val path: DatabasePath) { assertEquals("Ken Kousen", resultOfGroupByAndHaving.first().author) } - fun testUnionSelect() = Database(getDefaultDBConfig()).databaseAutoClose { database -> + fun testUnionSelect() = Database(getDefaultDBConfig(), true).databaseAutoClose { database -> val book0 = Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96) val book1 = Book(name = "Kotlin Cookbook", author = "Ken Kousen", pages = 251, price = 37.72) val book2 = Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95) @@ -286,7 +286,7 @@ class CommonBasicTest(private val path: DatabasePath) { assertEquals(2, statement!!.getResults().count { it == book3 }) } - fun testFunction() = Database(getDefaultDBConfig()).databaseAutoClose { database -> + fun testFunction() = Database(getDefaultDBConfig(), true).databaseAutoClose { database -> val book0 = Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96) val book1 = Book(name = "Kotlin Cookbook", author = "Ken Kousen", pages = 251, price = 37.72) val book2 = Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95) @@ -326,7 +326,7 @@ class CommonBasicTest(private val path: DatabasePath) { assertEquals(book0.author, selectStatement8?.getResults()?.first()?.author) } - fun testJoinClause() = Database(getDefaultDBConfig()).databaseAutoClose { database -> + fun testJoinClause() = Database(getDefaultDBConfig(), true).databaseAutoClose { database -> var crossJoinStatement: SelectStatement? = null var innerJoinStatement: SelectStatement? = null var naturalInnerJoinStatement: SelectStatement? = null @@ -372,7 +372,7 @@ class CommonBasicTest(private val path: DatabasePath) { fun testConcurrency() = runBlocking(Dispatchers.Default) { val book1 = Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96) val book2 = Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95) - val database = Database(getDefaultDBConfig()) + val database = Database(getDefaultDBConfig(), true) launch { var statement: SelectStatement? = null database suspendedScope { diff --git a/sqllin-processor/src/main/kotlin/com/ctrip/sqllin/processor/ClauseProcessor.kt b/sqllin-processor/src/main/kotlin/com/ctrip/sqllin/processor/ClauseProcessor.kt index d6d0d5c..222b9a1 100644 --- a/sqllin-processor/src/main/kotlin/com/ctrip/sqllin/processor/ClauseProcessor.kt +++ b/sqllin-processor/src/main/kotlin/com/ctrip/sqllin/processor/ClauseProcessor.kt @@ -95,7 +95,7 @@ class ClauseProcessor( val nullableSymbol = if (isNotNull) "\n" else "?\n" writer.write(nullableSymbol) writer.write(" get() = ${getSetClauseGetterValue(property)}\n") - writer.write(" set(value) = ${appendFunction(elementName, property)}\n\n") + writer.write(" set(value) = ${appendFunction(elementName, property, isNotNull)}\n\n") } writer.write("}") } @@ -146,11 +146,23 @@ class ClauseProcessor( else -> null } - private fun appendFunction(elementName: String, property: KSPropertyDeclaration): String = when (property.typeName) { - Char::class.qualifiedName -> "appendString($elementName, value?.toString())" + private fun appendFunction(elementName: String, property: KSPropertyDeclaration, isNotNull: Boolean): String? = when (property.typeName) { + Int::class.qualifiedName, + Long::class.qualifiedName, + Short::class.qualifiedName, + Byte::class.qualifiedName, + Float::class.qualifiedName, + Double::class.qualifiedName, + UInt::class.qualifiedName, + ULong::class.qualifiedName, + UShort::class.qualifiedName, + UByte::class.qualifiedName, -> "appendAny($elementName, value)" + + Char::class.qualifiedName -> "appendString($elementName, value${if (isNotNull) "" else "?"}.toString())" String::class.qualifiedName -> "appendString($elementName, value)" - Boolean::class.qualifiedName -> "appendAny($elementName, value?.let { if (it) 1 else 0 })" - else -> "appendAny($elementName, value)" + + Boolean::class.qualifiedName -> "appendAny($elementName, value${if (isNotNull) "" else "?"}.let { if (it) 1 else 0 })" + else -> null } private inline val KSPropertyDeclaration.typeName