forked from angryziber/kotlin-jooby-svelte-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTransaction.kt
54 lines (45 loc) · 1.64 KB
/
Transaction.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package db
import io.jooby.RequestScope
import kotlinx.coroutines.ThreadContextElement
import java.sql.Connection
import java.sql.SQLException
import javax.sql.DataSource
import kotlin.coroutines.AbstractCoroutineContextElement
import kotlin.coroutines.CoroutineContext
class Transaction(private val db: DataSource) {
companion object {
fun current(): Transaction? = RequestScope.get("tx")
}
private var conn: Connection? = null
val connection: Connection
get() = conn ?: db.connection.also { it.autoCommit = false; conn = it }
fun close(commit: Boolean) {
try {
conn?.apply {
if (commit) commit() else rollback()
autoCommit = true
close()
}
} finally {
conn = null
detachFromRequest()
}
}
fun attachToRequest() = this.also { RequestScope.bind("tx", it) }
fun detachFromRequest() = RequestScope.unbind<Transaction?>("tx")
}
fun <R> DataSource.withConnection(block: Connection.() -> R): R {
val tx = Transaction.current()
return try {
if (tx != null) tx.connection.block()
else connection.use(block)
}
catch (e: SQLException) {
throw if (e.message?.contains("unique constraint") == true) AlreadyExistsException(e) else e
}
}
class TransactionCoroutineContext(private val tx: Transaction? = Transaction.current()): ThreadContextElement<Transaction?>, AbstractCoroutineContextElement(Key) {
companion object Key: CoroutineContext.Key<TransactionCoroutineContext>
override fun updateThreadContext(context: CoroutineContext) = tx?.attachToRequest()
override fun restoreThreadContext(context: CoroutineContext, oldState: Transaction?) { oldState?.attachToRequest() }
}