Skip to content

Commit 45f91b5

Browse files
committed
Fix compilation of grouped statements with returns
1 parent 92c0591 commit 45f91b5

File tree

5 files changed

+121
-2
lines changed

5 files changed

+121
-2
lines changed

sqldelight-compiler/src/main/kotlin/app/cash/sqldelight/core/compiler/QueriesTypeGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class QueriesTypeGenerator(
6161
type.addFunction(generator.defaultResultTypeFunction())
6262
}
6363

64-
if (query.arguments.isNotEmpty()) {
64+
if (query.needsQuerySubType()) {
6565
type.addType(generator.querySubtype())
6666
}
6767
}

sqldelight-compiler/src/main/kotlin/app/cash/sqldelight/core/compiler/SelectQueryGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class SelectQueryGenerator(
223223
}
224224
mapperLambda.unindent().add("}\n")
225225

226-
if (query.arguments.isEmpty()) {
226+
if (!query.needsQuerySubType()) {
227227
// No need for a custom query type, return an instance of Query:
228228
// return Query(statement, selectForId) { resultSet -> ... }
229229
val tablesObserved = query.tablesObserved

sqldelight-compiler/src/main/kotlin/app/cash/sqldelight/core/compiler/model/NamedQuery.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import app.cash.sqldelight.core.lang.util.name
2727
import app.cash.sqldelight.core.lang.util.sqFile
2828
import app.cash.sqldelight.core.lang.util.tablesObserved
2929
import app.cash.sqldelight.core.lang.util.type
30+
import app.cash.sqldelight.core.psi.SqlDelightStmtClojureStmtList
3031
import app.cash.sqldelight.dialect.api.IntermediateType
3132
import app.cash.sqldelight.dialect.api.PrimitiveType.ARGUMENT
3233
import app.cash.sqldelight.dialect.api.PrimitiveType.BLOB
@@ -141,6 +142,8 @@ data class NamedQuery(
141142

142143
internal fun needsWrapper() = (resultColumns.size > 1 || resultColumns[0].javaType.isNullable)
143144

145+
internal fun needsQuerySubType() = arguments.isNotEmpty() || statement is SqlDelightStmtClojureStmtList
146+
144147
internal val tablesObserved: List<TableNameElement>? by lazy {
145148
if (queryable is SelectQueryable && queryable.select == queryable.statement) {
146149
queryable.select.tablesObserved()

sqldelight-compiler/src/test/kotlin/app/cash/sqldelight/core/QueriesTypeTest.kt

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,4 +846,68 @@ class QueriesTypeTest {
846846
""".trimMargin(),
847847
)
848848
}
849+
850+
@Test fun `grouped statement with return and no arguments gets a query type`() {
851+
val result = FixtureCompiler.compileSql(
852+
"""
853+
|CREATE TABLE data (
854+
| id INTEGER PRIMARY KEY,
855+
| value TEXT
856+
|);
857+
|
858+
|insertAndReturn {
859+
| INSERT INTO data (value)
860+
| VALUES (NULL)
861+
| ;
862+
| SELECT last_insert_rowid();
863+
|}
864+
""".trimMargin(),
865+
temporaryFolder,
866+
fileName = "Data.sq",
867+
)
868+
869+
val query = result.compiledFile.namedQueries.first()
870+
assertThat(result.errors).isEmpty()
871+
872+
val dataQueries = File(result.outputDirectory, "com/example/DataQueries.kt")
873+
assertThat(result.compilerOutput).containsKey(dataQueries)
874+
assertThat(result.compilerOutput[dataQueries].toString()).isEqualTo(
875+
"""
876+
|package com.example
877+
|
878+
|import app.cash.sqldelight.ExecutableQuery
879+
|import app.cash.sqldelight.TransacterImpl
880+
|import app.cash.sqldelight.db.QueryResult
881+
|import app.cash.sqldelight.db.SqlCursor
882+
|import app.cash.sqldelight.db.SqlDriver
883+
|import kotlin.Any
884+
|import kotlin.Long
885+
|import kotlin.String
886+
|
887+
|public class DataQueries(
888+
| driver: SqlDriver,
889+
|) : TransacterImpl(driver) {
890+
| public fun insertAndReturn(): ExecutableQuery<Long> = InsertAndReturnQuery() { cursor ->
891+
| cursor.getLong(0)!!
892+
| }
893+
|
894+
| private inner class InsertAndReturnQuery<out T : Any>(
895+
| mapper: (SqlCursor) -> T,
896+
| ) : ExecutableQuery<T>(mapper) {
897+
| override fun <R> execute(mapper: (SqlCursor) -> QueryResult<R>): QueryResult<R> =
898+
| transactionWithResult {
899+
| driver.execute(${query.idForIndex(0).withUnderscores}, ""${'"'}
900+
| |INSERT INTO data (value)
901+
| | VALUES (NULL)
902+
| ""${'"'}.trimMargin(), 0)
903+
| driver.executeQuery(${query.idForIndex(1).withUnderscores}, ""${'"'}SELECT last_insert_rowid()""${'"'}, mapper, 0)
904+
| }
905+
|
906+
| override fun toString(): String = "Data.sq:insertAndReturn"
907+
| }
908+
|}
909+
|
910+
""".trimMargin(),
911+
)
912+
}
849913
}

sqldelight-compiler/src/test/kotlin/app/cash/sqldelight/core/queries/SelectQueryTypeTest.kt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,58 @@ class SelectQueryTypeTest {
16921692
)
16931693
}
16941694

1695+
@Test
1696+
fun `grouped statements with return and no parameters`() {
1697+
val file = FixtureCompiler.parseSql(
1698+
"""
1699+
|CREATE TABLE data (
1700+
| id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
1701+
| value INTEGER NOT NULL
1702+
|);
1703+
|
1704+
|insertAndReturn {
1705+
| INSERT INTO data (value)
1706+
| VALUES (NULL)
1707+
| ;
1708+
| SELECT last_insert_rowid();
1709+
|}
1710+
|
1711+
""".trimMargin(),
1712+
tempFolder,
1713+
)
1714+
1715+
val query = file.namedQueries.first()
1716+
val generator = SelectQueryGenerator(query)
1717+
1718+
println(generator.defaultResultTypeFunction().toString())
1719+
1720+
assertThat(generator.querySubtype().toString()).isEqualTo(
1721+
"""
1722+
|private inner class InsertAndReturnQuery<out T : kotlin.Any>(
1723+
| public val value_: kotlin.Long,
1724+
| mapper: (app.cash.sqldelight.db.SqlCursor) -> T,
1725+
|) : app.cash.sqldelight.ExecutableQuery<T>(mapper) {
1726+
| override fun <R> execute(mapper: (app.cash.sqldelight.db.SqlCursor) -> app.cash.sqldelight.db.QueryResult<R>): app.cash.sqldelight.db.QueryResult<R> = transactionWithResult {
1727+
| driver.execute(${query.idForIndex(0).withUnderscores}, ""${'"'}
1728+
| |INSERT INTO data (value)
1729+
| | VALUES (?)
1730+
| ""${'"'}.trimMargin(), 1) {
1731+
| bindLong(0, value_)
1732+
| }
1733+
| driver.executeQuery(${query.idForIndex(1).withUnderscores}, ""${'"'}
1734+
| |SELECT value
1735+
| | FROM data
1736+
| | WHERE id = last_insert_rowid()
1737+
| ""${'"'}.trimMargin(), mapper, 0)
1738+
| }
1739+
|
1740+
| override fun toString(): kotlin.String = "Test.sq:insertAndReturn"
1741+
|}
1742+
|
1743+
""".trimMargin(),
1744+
)
1745+
}
1746+
16951747
@Test
16961748
fun `proper exposure of case arguments function`() {
16971749
val file = FixtureCompiler.parseSql(

0 commit comments

Comments
 (0)