@@ -5,6 +5,7 @@ import cnames.structs.sqlite3
55import co.touchlab.kermit.Logger
66import com.powersync.db.driver.SQLiteConnectionLease
77import com.powersync.db.driver.SQLiteConnectionPool
8+ import com.powersync.db.runWrapped
89import com.powersync.db.schema.Schema
910import com.powersync.sqlite.Database
1011import io.ktor.utils.io.CancellationException
@@ -20,12 +21,12 @@ import kotlinx.coroutines.runBlocking
2021internal 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
6079public 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