Skip to content

Commit 463dc8a

Browse files
kotlin: add Query class to support timeout and cancellation (#368)
There's now a `sqlc.runtime` package containing a few abstract classes implemented by the each query method. The query methods now return these intermediate classes rather than executing the query directly. You have to now explicitly call `.execute()` on the return value. I don't really like this level of indirection, but it now makes it possible to set timeouts at the per-query level, and allows queries to be canceled. It also opens up the possibility of "interceptors" for query objects that can be used to apply additional common code. Co-authored-by: Kyle Conroy <kyle@conroy.org>
1 parent b14fcd6 commit 463dc8a

File tree

18 files changed

+733
-502
lines changed

18 files changed

+733
-502
lines changed

examples/kotlin/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ This is a Kotlin gradle project configured to compile and test all examples. Cur
55
To run tests:
66

77
```shell script
8+
docker run --name dinosql-postgres -d -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=mysecretpassword -e POSTGRES_DB=postgres -p 5432:5432 postgres:11
89
./gradlew clean test
910
```
1011

examples/kotlin/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ repositories {
1212
dependencies {
1313
implementation 'org.postgresql:postgresql:42.2.9'
1414
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
15-
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
16-
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
15+
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
16+
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0'
1717
}
1818

1919
test {

examples/kotlin/gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#Sat Jan 25 10:45:34 EST 2020
2-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
2+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.1-all.zip
33
distributionBase=GRADLE_USER_HOME
44
distributionPath=wrapper/dists
55
zipStorePath=wrapper/dists

examples/kotlin/src/main/kotlin/com/example/authors/Queries.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,22 @@ package com.example.authors
55
import java.sql.Connection
66
import java.sql.SQLException
77

8+
import sqlc.runtime.ExecuteQuery
9+
import sqlc.runtime.ListQuery
10+
import sqlc.runtime.RowQuery
11+
812
interface Queries {
913
@Throws(SQLException::class)
10-
fun createAuthor(name: String, bio: String?): Author
14+
fun createAuthor(name: String, bio: String?): RowQuery<Author>
1115

1216
@Throws(SQLException::class)
13-
fun deleteAuthor(id: Long)
17+
fun deleteAuthor(id: Long): ExecuteQuery
1418

1519
@Throws(SQLException::class)
16-
fun getAuthor(id: Long): Author
20+
fun getAuthor(id: Long): RowQuery<Author>
1721

1822
@Throws(SQLException::class)
19-
fun listAuthors(): List<Author>
23+
fun listAuthors(): ListQuery<Author>
2024

2125
}
2226

examples/kotlin/src/main/kotlin/com/example/authors/QueriesImpl.kt

Lines changed: 74 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ package com.example.authors
55
import java.sql.Connection
66
import java.sql.SQLException
77

8+
import sqlc.runtime.ExecuteQuery
9+
import sqlc.runtime.ListQuery
10+
import sqlc.runtime.RowQuery
11+
812
const val createAuthor = """-- name: createAuthor :one
913
INSERT INTO authors (
1014
name, bio
@@ -32,71 +36,91 @@ ORDER BY name
3236
class QueriesImpl(private val conn: Connection) : Queries {
3337

3438
@Throws(SQLException::class)
35-
override fun createAuthor(name: String, bio: String?): Author {
36-
return conn.prepareStatement(createAuthor).use { stmt ->
37-
stmt.setString(1, name)
38-
stmt.setString(2, bio)
39-
40-
val results = stmt.executeQuery()
41-
if (!results.next()) {
42-
throw SQLException("no rows in result set")
43-
}
44-
val ret = Author(
45-
results.getLong(1),
46-
results.getString(2),
47-
results.getString(3)
48-
)
49-
if (results.next()) {
50-
throw SQLException("expected one row in result set, but got many")
39+
override fun createAuthor(name: String, bio: String?): RowQuery<Author> {
40+
return object : RowQuery<Author>() {
41+
override fun execute(): Author {
42+
return conn.prepareStatement(createAuthor).use { stmt ->
43+
this.statement = stmt
44+
stmt.setString(1, name)
45+
stmt.setString(2, bio)
46+
47+
val results = stmt.executeQuery()
48+
if (!results.next()) {
49+
throw SQLException("no rows in result set")
50+
}
51+
val ret = Author(
52+
results.getLong(1),
53+
results.getString(2),
54+
results.getString(3)
55+
)
56+
if (results.next()) {
57+
throw SQLException("expected one row in result set, but got many")
58+
}
59+
ret
60+
}
5161
}
52-
ret
5362
}
5463
}
5564

5665
@Throws(SQLException::class)
57-
override fun deleteAuthor(id: Long) {
58-
conn.prepareStatement(deleteAuthor).use { stmt ->
59-
stmt.setLong(1, id)
60-
61-
stmt.execute()
66+
override fun deleteAuthor(id: Long): ExecuteQuery {
67+
return object : ExecuteQuery() {
68+
override fun execute() {
69+
conn.prepareStatement(deleteAuthor).use { stmt ->
70+
this.statement = stmt
71+
stmt.setLong(1, id)
72+
73+
stmt.execute()
74+
}
75+
}
6276
}
6377
}
6478

6579
@Throws(SQLException::class)
66-
override fun getAuthor(id: Long): Author {
67-
return conn.prepareStatement(getAuthor).use { stmt ->
68-
stmt.setLong(1, id)
69-
70-
val results = stmt.executeQuery()
71-
if (!results.next()) {
72-
throw SQLException("no rows in result set")
73-
}
74-
val ret = Author(
75-
results.getLong(1),
76-
results.getString(2),
77-
results.getString(3)
78-
)
79-
if (results.next()) {
80-
throw SQLException("expected one row in result set, but got many")
80+
override fun getAuthor(id: Long): RowQuery<Author> {
81+
return object : RowQuery<Author>() {
82+
override fun execute(): Author {
83+
return conn.prepareStatement(getAuthor).use { stmt ->
84+
this.statement = stmt
85+
stmt.setLong(1, id)
86+
87+
val results = stmt.executeQuery()
88+
if (!results.next()) {
89+
throw SQLException("no rows in result set")
90+
}
91+
val ret = Author(
92+
results.getLong(1),
93+
results.getString(2),
94+
results.getString(3)
95+
)
96+
if (results.next()) {
97+
throw SQLException("expected one row in result set, but got many")
98+
}
99+
ret
100+
}
81101
}
82-
ret
83102
}
84103
}
85104

86105
@Throws(SQLException::class)
87-
override fun listAuthors(): List<Author> {
88-
return conn.prepareStatement(listAuthors).use { stmt ->
89-
90-
val results = stmt.executeQuery()
91-
val ret = mutableListOf<Author>()
92-
while (results.next()) {
93-
ret.add(Author(
94-
results.getLong(1),
95-
results.getString(2),
96-
results.getString(3)
97-
))
106+
override fun listAuthors(): ListQuery<Author> {
107+
return object : ListQuery<Author>() {
108+
override fun execute(): List<Author> {
109+
return conn.prepareStatement(listAuthors).use { stmt ->
110+
this.statement = stmt
111+
112+
val results = stmt.executeQuery()
113+
val ret = mutableListOf<Author>()
114+
while (results.next()) {
115+
ret.add(Author(
116+
results.getLong(1),
117+
results.getString(2),
118+
results.getString(3)
119+
))
120+
}
121+
ret
122+
}
98123
}
99-
ret
100124
}
101125
}
102126

examples/kotlin/src/main/kotlin/com/example/booktest/postgresql/Queries.kt

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,19 @@ import java.sql.SQLException
77
import java.sql.Types
88
import java.time.OffsetDateTime
99

10+
import sqlc.runtime.ExecuteQuery
11+
import sqlc.runtime.ListQuery
12+
import sqlc.runtime.RowQuery
13+
1014
interface Queries {
1115
@Throws(SQLException::class)
12-
fun booksByTags(dollar1: List<String>): List<BooksByTagsRow>
16+
fun booksByTags(dollar1: List<String>): ListQuery<BooksByTagsRow>
1317

1418
@Throws(SQLException::class)
15-
fun booksByTitleYear(title: String, year: Int): List<Book>
19+
fun booksByTitleYear(title: String, year: Int): ListQuery<Book>
1620

1721
@Throws(SQLException::class)
18-
fun createAuthor(name: String): Author
22+
fun createAuthor(name: String): RowQuery<Author>
1923

2024
@Throws(SQLException::class)
2125
fun createBook(
@@ -25,29 +29,29 @@ interface Queries {
2529
title: String,
2630
year: Int,
2731
available: OffsetDateTime,
28-
tags: List<String>): Book
32+
tags: List<String>): RowQuery<Book>
2933

3034
@Throws(SQLException::class)
31-
fun deleteBook(bookId: Int)
35+
fun deleteBook(bookId: Int): ExecuteQuery
3236

3337
@Throws(SQLException::class)
34-
fun getAuthor(authorId: Int): Author
38+
fun getAuthor(authorId: Int): RowQuery<Author>
3539

3640
@Throws(SQLException::class)
37-
fun getBook(bookId: Int): Book
41+
fun getBook(bookId: Int): RowQuery<Book>
3842

3943
@Throws(SQLException::class)
4044
fun updateBook(
4145
title: String,
4246
tags: List<String>,
43-
bookId: Int)
47+
bookId: Int): ExecuteQuery
4448

4549
@Throws(SQLException::class)
4650
fun updateBookISBN(
4751
title: String,
4852
tags: List<String>,
4953
isbn: String,
50-
bookId: Int)
54+
bookId: Int): ExecuteQuery
5155

5256
}
5357

0 commit comments

Comments
 (0)