Skip to content

Commit b656d28

Browse files
committed
fixing error handling
1 parent 225544a commit b656d28

File tree

4 files changed

+61
-40
lines changed

4 files changed

+61
-40
lines changed

src/jsMain/kotlin/cz/sazel/sqldelight/node/sqlite3/SQLite3Driver.kt

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ class SQLite3Driver internal constructor(private val db: Sqlite3.Database) : Sql
3333
if (enclosingTransaction == null) {
3434
val sql = if (successful) "END TRANSACTION" else "ROLLBACK TRANSACTION"
3535
suspendCoroutine { cont ->
36-
val callback: (Any?) -> Unit = { self ->
37-
if (self !is Throwable) {
38-
cont.resume(self as Sqlite3.Statement)
36+
val callback: (Any?) -> Unit = {
37+
if (it == null || it !is Throwable) {
38+
cont.resume(it)
3939
} else {
40-
cont.resumeWithException(SQLite3Exception(self))
40+
cont.resumeWithException(SQLite3JsException(it))
4141
}
4242
}
4343
db.exec(sql, callback)
@@ -60,9 +60,6 @@ class SQLite3Driver internal constructor(private val db: Sqlite3.Database) : Sql
6060
val res2 = db.prepare(sql)
6161
return@getOrPut res2
6262
}
63-
// .apply {
64-
// reset()
65-
// }
6663
}
6764
return res
6865
}
@@ -75,7 +72,7 @@ class SQLite3Driver internal constructor(private val db: Sqlite3.Database) : Sql
7572
val rows = suspendCoroutine { cont ->
7673
statement.all { error, rows ->
7774
if (error is Throwable) {
78-
cont.resumeWithException(error)
75+
cont.resumeWithException(SQLite3JsException(error))
7976
} else {
8077
cont.resume(rows)
8178
}
@@ -88,19 +85,24 @@ class SQLite3Driver internal constructor(private val db: Sqlite3.Database) : Sql
8885
}
8986

9087
override fun execute(identifier: Int?, sql: String, parameters: Int, binders: (SqlPreparedStatement.() -> Unit)?): QueryResult<Long> = QueryResult.AsyncValue {
91-
val statement = createOrGetStatement(identifier, sql)
92-
statement.bind(parameters, binders)
93-
suspendCoroutine { cont ->
94-
val callback: (Any) -> Unit = { self ->
95-
if (self is Throwable) {
96-
cont.resumeWithException(SQLite3Exception(self))
97-
} else {
98-
cont.resume(Unit)
88+
try {
89+
val statement = createOrGetStatement(identifier, sql)
90+
statement.bind(parameters, binders)
91+
suspendCoroutine { cont ->
92+
val callback: (Any) -> Unit = {
93+
if (it is Throwable) {
94+
cont.resumeWithException(SQLite3JsException(it))
95+
} else {
96+
cont.resume(Unit)
97+
}
9998
}
99+
statement.run(callback)
100100
}
101-
statement.run(callback)
101+
return@AsyncValue 0
102+
} catch (e: Throwable) {
103+
println("exception $e")
104+
return@AsyncValue 0
102105
}
103-
return@AsyncValue 0
104106
}
105107

106108
override fun newTransaction(): QueryResult<Transacter.Transaction> = QueryResult.AsyncValue {
@@ -113,7 +115,7 @@ class SQLite3Driver internal constructor(private val db: Sqlite3.Database) : Sql
113115
if (it == null || it !is Throwable) {
114116
cont.resume(it)
115117
} else {
116-
cont.resumeWithException(SQLite3Exception(it))
118+
cont.resumeWithException(SQLite3JsException(it))
117119
}
118120
}
119121
db.exec("BEGIN TRANSACTION", callback)
@@ -159,16 +161,22 @@ class SQLite3Driver internal constructor(private val db: Sqlite3.Database) : Sql
159161
if (parameters > 0) {
160162
val bound = SQLite3PreparedStatement(parameters)
161163
binders(bound)
164+
println("binders")
162165
suspendCoroutine { cont ->
163166
val callback: (Any?) -> Unit = {
164167
if (it == null || it !is Throwable) {
168+
println("bind resume")
165169
cont.resume(it)
166170
} else {
167-
cont.resumeWithException(it)
171+
println("bind resume exception")
172+
cont.resumeWithException(SQLite3JsException(it))
168173
}
169174
}
170-
bind(bound.parameters.toTypedArray(), callback)
175+
println("bind")
176+
bind(bound.parameters.toTypedArray(), callback = callback)
177+
println("bind end")
171178
}
179+
println("bind after susp")
172180
}
173181
}
174182
}
Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
11
package cz.sazel.sqldelight.node.sqlite3
22

3-
class SQLite3Exception(val error: Any?) : Exception()
3+
4+
/**
5+
* Exception of [SQLite3Driver].
6+
* Usually this class is directly returned in case of error within driver itself.
7+
*/
8+
open class SQLite3Exception(message: String) : Exception(message)
9+
10+
/**
11+
* Exception that occurs from within SQLite 3 Node.js module.
12+
*/
13+
class SQLite3JsException(private val err: Throwable?) : SQLite3Exception(err.nullable?.message ?: "unknown error") {
14+
/**
15+
* SQLite error number
16+
*/
17+
val errorNumber: Int
18+
get() = err?.asDynamic().errno as? Int ?: -1
19+
}
20+

src/jsMain/kotlin/cz/sazel/sqldelight/node/sqlite3/utils.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@ suspend fun <T : Any> Query<T>.executeSuspendingAsList(): List<T> {
2424
return (query as QueryResult.AsyncValue<List<T>>).await()
2525
} else throw IllegalArgumentException("Can be used only with async SQLite3 driver")
2626
}
27+
28+
29+
internal val <T> T?.nullable: T?
30+
get() = when (this) {
31+
null -> null
32+
undefined -> null
33+
else -> this
34+
}

src/jsTest/kotlin/cz/sazel/sqldelight/node/sqlite3/SQLite3DriverTest.kt

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,10 @@ class SQLite3DriverTest {
257257
@Test
258258
fun test_transaction_rollback() = runTest { driver ->
259259
val insert: InsertFunction = { binders: SqlPreparedStatement.() -> Unit ->
260-
driver.await(13, "INSERT INTO nonexisting_test VALUES (?, ?);", 2, binders)
260+
driver.await(13, "INSERT INTO nonexisting_table VALUES (?, ?);", 2, binders)
261261
}
262262

263-
driver.newTransaction().await()
263+
// driver.newTransaction().await()
264264
val success = try {
265265
insert {
266266
bindLong(0, 3)
@@ -274,28 +274,16 @@ class SQLite3DriverTest {
274274
try {
275275
assertFalse(success)
276276
} finally {
277-
(driver as SQLite3Driver)._endTransactionForTests(success)
277+
// (driver as SQLite3Driver)._endTransactionForTests(success)
278278
}
279279
}
280280

281281
@Test
282-
fun worker_exceptions_are_handled_correctly() = runTest { driver ->
283-
println("IS_LEGACY: $IS_LEGACY")
284-
// Despite the exception being thrown correctly in LEGACY builds, this test fails for some reason
285-
if (IS_LEGACY) return@runTest
286-
287-
val error = assertFailsWith<Exception> { //TODO change exception
282+
fun exceptions_are_handled_correctly() = runTest { driver ->
283+
val error = assertFailsWith<SQLite3JsException> {
288284
schema.awaitCreate(driver)
289285
}
290286
assertContains(error.toString(), "table test already exists")
291-
}
292-
293-
// TODO: Remove this once LEGACY builds are dropped
294-
companion object {
295-
private data class Obj(val entry: String)
296-
297-
private val prototype = js("Object").getPrototypeOf(Obj("test"))
298-
private val prototypeProps: Array<String> = js("Object").getOwnPropertyNames(prototype).unsafeCast<Array<String>>()
299-
private val IS_LEGACY = prototypeProps.firstOrNull { it.contains("_get_") } == null
287+
assertEquals(error.errorNumber, 1)
300288
}
301289
}

0 commit comments

Comments
 (0)