Skip to content
Open
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* Fix: the default `lookasideSlotSize` and `lookasideSlotCount` of `DSLDBConfiguration` disabled SQLite's lookaside memory allocator on Kotlin/Native and on Android 9 and higher, as those of `DatabaseConfiguration` did; they are now -1, see sqllin-driver
* Fix: on the JVM and Kotlin/Native, a blocking `database { }` scope on another thread could take the TEMP table and triggers that count the changes of observed queries with it, as its transaction can be open while they are created, the connection being locked for each statement rather than for a transaction: its rollback removed them, so the next write failed with "no such table", and once another table was observed, the changes of the table they belonged to were no longer counted. The tracker now creates them again where they are gone, and counts a change of their tables. A failure to tell the observed queries of a change no longer takes the place of the failure of the statement that made it. The guide to observed queries and the documentation of `Database#invoke` and `Database#observe` now say to write through `suspendedScope` while queries are observed, as they run on another thread, and that a blocking scope isn't serialized with them
* Fix documentation: the example of the guide to concurrency safety called `database suspendScope { }`, which doesn't exist, in a function that wasn't a `suspend` one; it is `database suspendedScope { }`, in a `suspend` function
* Fix: `INSERT` failed with `near ")": syntax error` when the primary key that the database assigns, a `Long?` property annotated with `@PrimaryKey`, was the last property of the class: as `INSERT` leaves such a key out, the column list kept a trailing comma, and the `VALUES` tuple was never closed. A key declared before another property wasn't affected, and neither were `INSERT_WITH_ID`, `INSERT_OR_IGNORE` and `INSERT_OR_REPLACE`, which write the key
* Fix documentation: examples that didn't compile. The READMEs and the query guide called `SelectStatement.getResult()`, which doesn't exist, rather than `getResults()`; the guide to getting started imported `DSLDBConfiguration` from `com.ctrip.sqllin.driver` rather than `com.ctrip.sqllin.dsl`, and, in English, the annotation `NoCase`, which doesn't exist, rather than `CollateNoCase`; and the guide to modifying the database declared an `autoIncrement` primary key as `Long = 0`, which the processor rejects, rather than `Long? = null`

### sqllin-driver

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fun sample() {
table SELECT WHERE (age LTE 5) GROUP_BY age HAVING (upper(name) EQ "TOM") ORDER_BY (age to DESC) LIMIT 2 OFFSET 1
}
}
selectStatement.getResult().forEach { person ->
selectStatement.getResults().forEach { person ->
println(person.name)
}
}
Expand Down
2 changes: 1 addition & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fun sample() {
table SELECT WHERE (age LTE 5) GROUP_BY age HAVING (upper(name) EQ "TOM") ORDER_BY (age to DESC) LIMIT 2 OFFSET 1
}
}
selectStatement.getResult().forEach { person ->
selectStatement.getResults().forEach { person ->
println(person.name)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class AndroidTest {
@Test
fun testInsert() = commonTest.testInsert()

@Test
fun testInsertGeneratedKeyLast() = commonTest.testInsertGeneratedKeyLast()

@Test
fun testDelete() = commonTest.testDelete()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ class CommonBasicTest(private val path: DatabasePath) {
assertEquals(book, statement?.getResults()?.firstOrNull())
}

fun testInsertGeneratedKeyLast() = Database(getDefaultDBConfig()).databaseAutoClose { database ->
val result = database {
CREATE(GeneratedKeyLastTable)
GeneratedKeyLastTable INSERT listOf(GeneratedKeyLast("first"), GeneratedKeyLast("second"))
GeneratedKeyLastTable SELECT ORDER_BY(GeneratedKeyLastTable.id)
}
assertEquals(listOf(GeneratedKeyLast("first", 1L), GeneratedKeyLast("second", 2L)), result.getResults())
}

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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ data class PersonWithId(
val age: Age,
)

@DBRow("generated_key_last")
@Serializable
data class GeneratedKeyLast(
val name: String,
@PrimaryKey val id: Long? = null,
)

@DBRow("product")
@Serializable
data class Product(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JvmTest {
@Test
fun testInsert() = commonTest.testInsert()

@Test
fun testInsertGeneratedKeyLast() = commonTest.testInsertGeneratedKeyLast()

@Test
fun testDelete() = commonTest.testDelete()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class NativeTest {
@Test
fun testInsert() = commonTest.testInsert()

@Test
fun testInsertGeneratedKeyLast() = commonTest.testInsertGeneratedKeyLast()

@Test
fun testDelete() = commonTest.testDelete()

Expand Down
2 changes: 1 addition & 1 deletion sqllin-dsl/doc/getting-start-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ val database = Database(
除此之外,你还可以使用 `DSLDBConfiguration`,它允许你在 `create` 和 `upgrade` 回调中使用类型安全的 SQL DSL,而不是原始的 SQL 字符串:

```kotlin
import com.ctrip.sqllin.driver.DSLDBConfiguration
import com.ctrip.sqllin.dsl.DSLDBConfiguration
import com.ctrip.sqllin.dsl.Database

val database = Database(
Expand Down
4 changes: 2 additions & 2 deletions sqllin-dsl/doc/getting-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ only work on Android 9 and higher. And, because [sqlite-jdbc](https://github.com
Alternatively, you can use `DSLDBConfiguration` which allows you to use the type-safe SQL DSL in the `create` and `upgrade` callbacks instead of raw SQL strings:

```kotlin
import com.ctrip.sqllin.driver.DSLDBConfiguration
import com.ctrip.sqllin.dsl.DSLDBConfiguration
import com.ctrip.sqllin.dsl.Database

val database = Database(
Expand Down Expand Up @@ -399,7 +399,7 @@ Use `@CollateNoCase` to make string comparisons case-insensitive:
```kotlin
import com.ctrip.sqllin.dsl.annotation.DBRow
import com.ctrip.sqllin.dsl.annotation.PrimaryKey
import com.ctrip.sqllin.dsl.annotation.NoCase
import com.ctrip.sqllin.dsl.annotation.CollateNoCase
import com.ctrip.sqllin.dsl.annotation.Unique
import kotlinx.serialization.Serializable

Expand Down
2 changes: 1 addition & 1 deletion sqllin-dsl/doc/modify-database-and-transaction-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import kotlinx.serialization.Serializable
@Serializable
data class Person(
@PrimaryKey(autoIncrement = true)
val id: Long = 0,
val id: Long? = null,
val name: String,
val age: Int,
)
Expand Down
2 changes: 1 addition & 1 deletion sqllin-dsl/doc/modify-database-and-transaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import kotlinx.serialization.Serializable
@Serializable
data class Person(
@PrimaryKey(autoIncrement = true)
val id: Long = 0,
val id: Long? = null,
val name: String,
val age: Int,
)
Expand Down
4 changes: 2 additions & 2 deletions sqllin-dsl/doc/query-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fun sample() {
selectStatement = table SELECT X
}
}
selectStatement.getResult().forEach { person ->
selectStatement.getResults().forEach { person ->
println(person)
}
}
Expand Down Expand Up @@ -76,7 +76,7 @@ fun sample() {
selectStatement = table SELECT WHERE (age LTE 5) GROUP_BY age HAVING (upper(name) EQ "TOM") ORDER_BY (age to DESC) LIMIT 2 OFFSET 1
}
}
selectStatement.getResult().forEach { person ->
selectStatement.getResults().forEach { person ->
println(person)
}
}
Expand Down
4 changes: 2 additions & 2 deletions sqllin-dsl/doc/query.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fun sample() {
selectStatement = table SELECT X
}
}
selectStatement.getResult().forEach { person ->
selectStatement.getResults().forEach { person ->
println(person)
}
}
Expand Down Expand Up @@ -78,7 +78,7 @@ fun sample() {
selectStatement = table SELECT WHERE (age LTE 5) GROUP_BY age HAVING (upper(name) EQ "TOM") ORDER_BY (age to DESC) LIMIT 2 OFFSET 1
}
}
selectStatement.getResult().forEach { person ->
selectStatement.getResults().forEach { person ->
println(person)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,10 @@ internal fun StringBuilder.appendDBColumnName(
if (isInsertId) {
appendDBColumnName(descriptor)
} else {
val lastIndex = descriptor.elementsCount - 1
for (i in 0 ..< lastIndex) {
val elementName = descriptor.getElementName(i)
if (elementName != primaryKeyName) {
append(elementName)
append(',')
}
}
val elementName = descriptor.getElementName(lastIndex)
if (elementName != primaryKeyName)
append(elementName)
val columnNames = (0 ..< descriptor.elementsCount)
.map(descriptor::getElementName)
.filter { it != primaryKeyName }
append(columnNames.joinToString(","))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,49 +50,33 @@ internal class InsertValuesEncoder(

override val serializersModule: SerializersModule = EmptySerializersModule()

private var elementsIndex = 0
private var elementsCount = 0
private var encodedElements = 0

/**
* StringBuilder accumulating the SQL VALUES clause.
*/
private val sqlStrBuilder = StringBuilder("(")

/**
* Appends comma between values or closing parenthesis after the last value.
*
* Format: `?, ?, ?)`
*/
private fun appendTail() {
val symbol = if (elementsIndex < elementsCount - 1)
','
else
')'
sqlStrBuilder.append(symbol)
}

/**
* Appends a parameter placeholder and records the value.
*
* @param value The parameter value (any type including null)
*/
private fun appendAny(value: Any?) {
if (encodedElements++ > 0)
sqlStrBuilder.append(',')
sqlStrBuilder.append('?')
parameters.add(value)
appendTail()
}

/**
* The complete SQL VALUES clause generated by this encoder.
*/
val valuesSQL
get() = sqlStrBuilder.toString()
get() = "$sqlStrBuilder)"

override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean {
elementsCount = descriptor.elementsCount
elementsIndex = index
return isInsertId || descriptor.getElementName(index) != primaryKeyName
}
override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean =
isInsertId || descriptor.getElementName(index) != primaryKeyName

/**
* Encodes any non-null value as a parameter placeholder.
Expand Down
Loading