Skip to content

Commit c0bdde9

Browse files
improve error handling
1 parent 068d8ed commit c0bdde9

File tree

1 file changed

+61
-25
lines changed

1 file changed

+61
-25
lines changed

PowerSyncKotlin/src/appleMain/kotlin/com/powersync/SwiftSQLiteConnectionPool.kt

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import cnames.structs.sqlite3
55
import co.touchlab.kermit.Logger
66
import com.powersync.db.driver.SQLiteConnectionLease
77
import com.powersync.db.driver.SQLiteConnectionPool
8+
import com.powersync.db.runWrapped
89
import com.powersync.db.schema.Schema
910
import com.powersync.sqlite.Database
1011
import io.ktor.utils.io.CancellationException
@@ -20,12 +21,12 @@ import kotlinx.coroutines.runBlocking
2021
internal class RawConnectionLease
2122
@OptIn(ExperimentalForeignApi::class)
2223
constructor(
23-
connectionPointer: CPointer<sqlite3>,
24+
private val lease: SwiftLeaseAdapter,
2425
) : SQLiteConnectionLease {
2526
private var isCompleted = false
2627

2728
@OptIn(ExperimentalForeignApi::class)
28-
private var db = Database(connectionPointer)
29+
private var db = Database(lease.pointer)
2930

3031
private fun checkNotCompleted() {
3132
check(!isCompleted) { "Connection lease already closed" }
@@ -52,6 +53,24 @@ internal class RawConnectionLease
5253
}
5354
}
5455

56+
public fun interface LeaseCallback {
57+
@Throws(PowerSyncException::class, CancellationException::class)
58+
public fun execute(lease: SwiftLeaseAdapter)
59+
}
60+
61+
public fun interface AllLeaseCallback {
62+
@Throws(PowerSyncException::class, CancellationException::class)
63+
public fun execute(
64+
writeLease: SwiftLeaseAdapter,
65+
readLeases: List<SwiftLeaseAdapter>,
66+
)
67+
}
68+
69+
public interface SwiftLeaseAdapter {
70+
@OptIn(ExperimentalForeignApi::class)
71+
public val pointer: CPointer<sqlite3>
72+
}
73+
5574
/**
5675
* We only allow synchronous callbacks on the Swift side for leased READ/WRITE connections.
5776
* We also get a SQLite connection pointer (sqlite3*) from Swift side. which is used in a [Database]
@@ -60,15 +79,17 @@ internal class RawConnectionLease
6079
public interface SwiftPoolAdapter {
6180
@OptIn(ExperimentalForeignApi::class)
6281
@Throws(PowerSyncException::class, CancellationException::class)
63-
public suspend fun leaseRead(callback: (CPointer<sqlite3>) -> Unit)
82+
public suspend fun leaseRead(callback: LeaseCallback)
6483

6584
@OptIn(ExperimentalForeignApi::class)
6685
@Throws(PowerSyncException::class, CancellationException::class)
67-
public suspend fun leaseWrite(callback: (CPointer<sqlite3>) -> Unit)
86+
public suspend fun leaseWrite(callback: LeaseCallback)
6887

6988
@OptIn(ExperimentalForeignApi::class)
7089
@Throws(PowerSyncException::class, CancellationException::class)
71-
public suspend fun leaseAll(callback: (CPointer<sqlite3>, List<CPointer<sqlite3>>) -> Unit)
90+
public suspend fun leaseAll(callback: AllLeaseCallback)
91+
92+
public fun linkUpdates(callback: suspend (Set<String>) -> Unit)
7293

7394
public suspend fun closePool()
7495
}
@@ -82,25 +103,30 @@ public open class SwiftSQLiteConnectionPool
82103
private val _updates = MutableSharedFlow<Set<String>>(replay = 0)
83104
override val updates: SharedFlow<Set<String>> get() = _updates
84105

85-
public fun pushUpdate(update: Set<String>) {
86-
_updates.tryEmit(update)
106+
init {
107+
adapter.linkUpdates { tables ->
108+
_updates.emit(tables)
109+
}
87110
}
88111

89112
@OptIn(ExperimentalForeignApi::class)
90113
override suspend fun <T> read(callback: suspend (SQLiteConnectionLease) -> T): T {
91114
var result: T? = null
92115
adapter.leaseRead {
93-
/**
94-
* For GRDB, this should be running inside the callback
95-
* ```swift
96-
* db.write {
97-
* // should be here
98-
* }
99-
* ```
100-
*/
101-
val lease = RawConnectionLease(it)
102-
runBlocking {
103-
result = callback(lease)
116+
runWrapped {
117+
/**
118+
* For GRDB, this should be running inside the callback
119+
* ```swift
120+
* db.write {
121+
* // should be here
122+
* }
123+
* ```
124+
*/
125+
val lease =
126+
RawConnectionLease(it)
127+
runBlocking {
128+
result = callback(lease)
129+
}
104130
}
105131
}
106132
return result as T
@@ -109,20 +135,30 @@ public open class SwiftSQLiteConnectionPool
109135
@OptIn(ExperimentalForeignApi::class)
110136
override suspend fun <T> write(callback: suspend (SQLiteConnectionLease) -> T): T {
111137
var result: T? = null
112-
adapter.leaseWrite {
113-
val lease = RawConnectionLease(it)
114-
runBlocking {
115-
result = callback(lease)
138+
adapter.leaseWrite { lease ->
139+
runWrapped {
140+
val lease = RawConnectionLease(lease)
141+
142+
runBlocking {
143+
result = callback(lease)
144+
}
116145
}
117146
}
118147
return result as T
119148
}
120149

121150
@OptIn(ExperimentalForeignApi::class)
122151
override suspend fun <R> withAllConnections(action: suspend (SQLiteConnectionLease, List<SQLiteConnectionLease>) -> R) {
123-
adapter.leaseAll { writerPtr, readerPtrs ->
124-
runBlocking {
125-
action(RawConnectionLease(writerPtr), readerPtrs.map { RawConnectionLease(it) })
152+
adapter.leaseAll { writerLease, readerLeases ->
153+
runWrapped {
154+
runBlocking {
155+
action(
156+
RawConnectionLease(writerLease),
157+
readerLeases.map {
158+
RawConnectionLease(it)
159+
},
160+
)
161+
}
126162
}
127163
}
128164
}

0 commit comments

Comments
 (0)