Skip to content

Commit

Permalink
Add CoroutineScope receiver to transaction & withConnection
Browse files Browse the repository at this point in the history
See: #1
  • Loading branch information
huntj88 authored and michaelbull committed Aug 25, 2020
1 parent 24c4b66 commit d5fd3a9
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 8 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The primary higher-order function exposed by the library is the
[`transaction`][transaction] function.

```kotlin
suspend inline fun <T> transaction(crossinline block: suspend () -> T): T
suspend inline fun <T> transaction(crossinline block: suspend CoroutineScope.() -> T): T
```

Calling this function with a specific suspending block will run the block in
Expand Down
9 changes: 6 additions & 3 deletions src/main/kotlin/com/github/michaelbull/jdbc/Connection.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.github.michaelbull.jdbc.context.CoroutineConnection
import com.github.michaelbull.jdbc.context.CoroutineDataSource
import com.github.michaelbull.jdbc.context.dataSource
import com.github.michaelbull.logging.InlineLogger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.withContext
import java.sql.Connection
import java.sql.SQLException
Expand All @@ -27,7 +28,7 @@ internal val logger = InlineLogger()
* [with the context][withContext] of a new [CoroutineConnection] and an attempt will be made to [Connection.close]
* it afterwards.
*/
suspend inline fun <T> withConnection(crossinline block: suspend () -> T): T {
suspend inline fun <T> withConnection(crossinline block: suspend CoroutineScope.() -> T): T {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
Expand All @@ -37,7 +38,9 @@ suspend inline fun <T> withConnection(crossinline block: suspend () -> T): T {
return if (connection.isNullOrClosed()) {
newConnection(block)
} else {
block()
withContext(coroutineContext) {
block()
}
}
}

Expand All @@ -49,7 +52,7 @@ suspend inline fun <T> withConnection(crossinline block: suspend () -> T): T {
* [IllegalStateException] is thrown.
*/
@PublishedApi
internal suspend inline fun <T> newConnection(crossinline block: suspend () -> T): T {
internal suspend inline fun <T> newConnection(crossinline block: suspend CoroutineScope.() -> T): T {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
Expand Down
13 changes: 9 additions & 4 deletions src/main/kotlin/com/github/michaelbull/jdbc/Transaction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.github.michaelbull.jdbc.context.CoroutineConnection
import com.github.michaelbull.jdbc.context.CoroutineTransaction
import com.github.michaelbull.jdbc.context.connection
import com.github.michaelbull.jdbc.context.transaction
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.withContext
import java.sql.Connection
import kotlin.contracts.InvocationKind
Expand All @@ -26,7 +27,7 @@ import kotlin.coroutines.coroutineContext
* the transaction will [rollback][Connection.rollback] and re-throw the [Throwable], otherwise the transaction will
* [commit][Connection.commit] and return the result of type [T].
*/
suspend inline fun <T> transaction(crossinline block: suspend () -> T): T {
suspend inline fun <T> transaction(crossinline block: suspend CoroutineScope.() -> T): T {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
Expand All @@ -39,7 +40,11 @@ suspend inline fun <T> transaction(crossinline block: suspend () -> T): T {
execute(block)
}
}
existingTransaction.isRunning -> block()

existingTransaction.isRunning -> withContext(coroutineContext) {
block()
}

else -> error("Attempted to start new transaction within: $existingTransaction")
}
}
Expand All @@ -53,7 +58,7 @@ suspend inline fun <T> transaction(crossinline block: suspend () -> T): T {
* [commit][Connection.commit].
*/
@PublishedApi
internal suspend inline fun <T> execute(crossinline block: suspend () -> T): T {
internal suspend inline fun <T> execute(crossinline block: suspend CoroutineScope.() -> T): T {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
Expand All @@ -65,7 +70,7 @@ internal suspend inline fun <T> execute(crossinline block: suspend () -> T): T {
connection.autoCommit = false

try {
val result = block()
val result = withContext(coroutineContext) { block() }
transaction.complete()
connection.commit()
return result
Expand Down

0 comments on commit d5fd3a9

Please sign in to comment.