Skip to content

Commit 225544a

Browse files
committed
transaction processing fixed
As there was probably improper handling of the callback type. Also exec() is now used instead run().
1 parent 849a91c commit 225544a

File tree

3 files changed

+74
-17
lines changed

3 files changed

+74
-17
lines changed

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

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,32 @@ internal suspend fun SQLite3Driver.withSchema(schema: SqlSchema? = null) = this.
2424
class SQLite3Driver internal constructor(private val db: Sqlite3.Database) : SqlDriver {
2525
private val listeners = mutableMapOf<String, MutableSet<Query.Listener>>()
2626
private val statements = mutableMapOf<Int, Sqlite3.Statement>()
27-
private var transaction: Transacter.Transaction? = null
27+
private var transaction: Transaction? = null
2828

29-
private inner class Transaction(
29+
internal inner class Transaction(
3030
override val enclosingTransaction: Transacter.Transaction?,
3131
) : Transacter.Transaction() {
3232
override fun endTransaction(successful: Boolean): QueryResult<Unit> = QueryResult.AsyncValue {
3333
if (enclosingTransaction == null) {
3434
val sql = if (successful) "END TRANSACTION" else "ROLLBACK TRANSACTION"
3535
suspendCoroutine { cont ->
36-
val callback: (Any) -> Unit = { self ->
36+
val callback: (Any?) -> Unit = { self ->
3737
if (self !is Throwable) {
3838
cont.resume(self as Sqlite3.Statement)
3939
} else {
4040
cont.resumeWithException(SQLite3Exception(self))
4141
}
4242
}
43-
db.run(sql, callback)
43+
db.exec(sql, callback)
4444
}
4545
}
46-
transaction = enclosingTransaction
46+
transaction = this
4747
}
48+
49+
/**
50+
* Use for tests only.
51+
*/
52+
internal fun _endTransactionForTests(successful: Boolean) = endTransaction(successful)
4853
}
4954

5055
private fun createOrGetStatement(identifier: Int?, sql: String): Sqlite3.Statement {
@@ -104,14 +109,14 @@ class SQLite3Driver internal constructor(private val db: Sqlite3.Database) : Sql
104109
this.transaction = transaction
105110
if (enclosing == null) {
106111
suspendCoroutine { cont ->
107-
val callback: (Any) -> Unit = { self ->
108-
if (self !is Throwable) {
109-
cont.resume(self as Sqlite3.Statement)
112+
val callback: (Any?) -> Unit = {
113+
if (it == null || it !is Throwable) {
114+
cont.resume(it)
110115
} else {
111-
cont.resumeWithException(SQLite3Exception(self))
116+
cont.resumeWithException(SQLite3Exception(it))
112117
}
113118
}
114-
db.run("BEGIN TRANSACTION", callback)
119+
db.exec("BEGIN TRANSACTION", callback)
115120
}
116121
}
117122

@@ -120,6 +125,9 @@ class SQLite3Driver internal constructor(private val db: Sqlite3.Database) : Sql
120125

121126
override fun currentTransaction(): Transacter.Transaction? = transaction
122127

128+
internal fun _endTransactionForTests(successful: Boolean) = transaction?._endTransactionForTests(successful)
129+
130+
123131
override fun addListener(listener: Query.Listener, queryKeys: Array<String>) {
124132
queryKeys.forEach {
125133
listeners.getOrPut(it) { mutableSetOf() }.add(listener)
@@ -153,10 +161,11 @@ class SQLite3Driver internal constructor(private val db: Sqlite3.Database) : Sql
153161
binders(bound)
154162
suspendCoroutine { cont ->
155163
val callback: (Any?) -> Unit = {
156-
if (it is Throwable)
157-
cont.resumeWithException(it)
158-
else
164+
if (it == null || it !is Throwable) {
159165
cont.resume(it)
166+
} else {
167+
cont.resumeWithException(it)
168+
}
160169
}
161170
bind(bound.parameters.toTypedArray(), callback)
162171
}

src/jsMain/kotlin/node/sqlite3/sqlite3.module_sqlite3.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,10 @@ external object Sqlite3 {
159159
constructor(filename: String, mode: Number = definedExternally)
160160

161161
open fun close(callback: (err: Error?) -> Unit = definedExternally)
162-
open fun run(sql: String, callback: (self: Any?) -> Unit): Database /* this */
162+
open fun run(sql: String, callback: (self: Any?) -> Unit = definedExternally): Database /* this */
163163

164-
// open fun run(sql: String): Database /* this */
165-
open fun run(sql: String, params: Any, callback: (self: Any?) -> Unit = definedExternally): Database /* this */
164+
open fun run(sql: String): Database
165+
open fun run(sql: String, params: Any?, callback: (self: Any?) -> Unit = definedExternally): Database /* this */
166166

167167
// open fun run(sql: String, params: Any): Database /* this */
168168
open fun get(sql: String, callback: (self: Statement, err: Error?, row: Any) -> Unit = definedExternally): Database /* this */
@@ -190,7 +190,7 @@ external object Sqlite3 {
190190

191191
open fun each(sql: String, params: Any): Database /* this */
192192
open fun each(sql: String, params: Any, callback: (self: Statement, err: Error?, row: Any) -> Unit = definedExternally): Database /* this */
193-
open fun exec(sql: String, callback: (self: Statement, err: Error?) -> Unit = definedExternally): Database /* this */
193+
open fun exec(sql: String, callback: (self: Any?) -> Unit = definedExternally): Database /* this */
194194

195195
//open fun prepare(sql: String, callback: (self: Statement, err: Error?) -> Unit = definedExternally): Statement
196196
open fun prepare(sql: String, callback: (self: Any) -> Unit): Statement

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,54 @@ class SQLite3DriverTest {
230230
driver.awaitQuery(8, "SELECT * FROM nullability_test", mapper, 0)
231231
}
232232

233+
@Test
234+
fun test_transaction_commit() = runTest { driver ->
235+
val insert: InsertFunction = { binders: SqlPreparedStatement.() -> Unit ->
236+
driver.await(12, "INSERT INTO test VALUES (?, ?);", 2, binders)
237+
}
238+
239+
driver.newTransaction().await()
240+
val success = try {
241+
insert {
242+
bindLong(0, 3)
243+
bindString(1, "Hello")
244+
}
245+
true
246+
} catch (e: SQLite3Exception) {
247+
false
248+
}
249+
250+
try {
251+
assertTrue(success)
252+
} finally {
253+
(driver as SQLite3Driver)._endTransactionForTests(success)
254+
}
255+
}
256+
257+
@Test
258+
fun test_transaction_rollback() = runTest { driver ->
259+
val insert: InsertFunction = { binders: SqlPreparedStatement.() -> Unit ->
260+
driver.await(13, "INSERT INTO nonexisting_test VALUES (?, ?);", 2, binders)
261+
}
262+
263+
driver.newTransaction().await()
264+
val success = try {
265+
insert {
266+
bindLong(0, 3)
267+
bindString(1, "Hello")
268+
}
269+
true
270+
} catch (e: SQLite3Exception) {
271+
false
272+
}
273+
274+
try {
275+
assertFalse(success)
276+
} finally {
277+
(driver as SQLite3Driver)._endTransactionForTests(success)
278+
}
279+
}
280+
233281
@Test
234282
fun worker_exceptions_are_handled_correctly() = runTest { driver ->
235283
println("IS_LEGACY: $IS_LEGACY")

0 commit comments

Comments
 (0)