Skip to content

Commit e763b85

Browse files
committed
Add Room web support
1 parent 4c4d7ee commit e763b85

5 files changed

Lines changed: 76 additions & 34 deletions

File tree

integrations/room/build.gradle.kts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ kotlin {
1818
android = {
1919
namespace = "com.powersync.integrations.room"
2020
},
21-
legacyJavaSupport = false
21+
legacyJavaSupport = false,
22+
web = true
2223
)
2324

2425
explicitApi()
@@ -34,23 +35,43 @@ kotlin {
3435
commonMain.dependencies {
3536
api(projects.common)
3637
api(libs.androidx.room.runtime)
37-
api(libs.androidx.sqlite.bundled)
3838

39+
implementation(libs.androidx.sqlite.async)
3940
implementation(libs.kotlinx.serialization.json)
4041
}
4142

43+
val commonNonWeb by creating {
44+
dependsOn(commonMain.get())
45+
46+
dependencies {
47+
api(libs.androidx.sqlite.bundled)
48+
}
49+
}
50+
51+
jvmMain {
52+
dependsOn(commonNonWeb)
53+
}
54+
nativeMain {
55+
dependsOn(commonNonWeb)
56+
}
57+
androidMain {
58+
dependsOn(commonNonWeb)
59+
}
60+
4261
commonTest.dependencies {
4362
implementation(libs.kotlin.test)
4463
implementation(libs.kotlinx.io)
4564
implementation(libs.test.kotest.assertions)
4665
implementation(libs.test.coroutines)
4766
implementation(libs.test.turbine)
48-
49-
implementation(libs.androidx.sqlite.bundled)
5067
}
5168

5269
val commonIntegrationTest by creating {
5370
dependsOn(commonTest.get())
71+
72+
dependencies {
73+
implementation(libs.androidx.sqlite.bundled)
74+
}
5475
}
5576

5677
// We're putting the native libraries into our JAR, so integration tests for the JVM can run as part of the unit

integrations/room/src/commonMain/kotlin/com/powersync/integrations/room/RoomConnectionPool.kt

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@ import androidx.room3.useReaderConnection
77
import androidx.room3.useWriterConnection
88
import androidx.sqlite.SQLiteException
99
import androidx.sqlite.SQLiteStatement
10+
import androidx.sqlite.async.step
1011
import com.powersync.db.driver.SQLiteConnectionLease
1112
import com.powersync.db.driver.SQLiteConnectionPool
1213
import com.powersync.db.schema.Schema
13-
import kotlinx.coroutines.currentCoroutineContext
1414
import kotlinx.coroutines.flow.MutableSharedFlow
1515
import kotlinx.coroutines.flow.SharedFlow
1616
import kotlinx.coroutines.launch
17-
import kotlinx.coroutines.runBlocking
18-
import kotlin.coroutines.CoroutineContext
1917

2018
/**
2119
* A [SQLiteConnectionPool] implementation for the PowerSync SDK that is backed by a [RoomDatabase].
@@ -52,7 +50,7 @@ public class RoomConnectionPool(
5250

5351
override suspend fun <T> read(callback: suspend (SQLiteConnectionLease) -> T): T =
5452
db.useReaderConnection {
55-
callback(RoomTransactionLease(it, currentCoroutineContext()))
53+
callback(it.asConnectionLease())
5654
}
5755

5856
/**
@@ -97,7 +95,7 @@ public class RoomConnectionPool(
9795
}
9896

9997
try {
100-
callback(RoomTransactionLease(it, currentCoroutineContext()))
98+
callback(it.asConnectionLease())
10199
} finally {
102100
// List changed tables, excluding virtual and shadow tables for e.g. fts5
103101
val statement =
@@ -138,36 +136,15 @@ public class RoomConnectionPool(
138136
}
139137
}
140138

141-
private class RoomTransactionLease(
142-
private val transactor: Transactor,
143-
/**
144-
* The context to use for [runBlocking] calls to avoid the "Attempted to use connection on a
145-
* different coroutine" error.
146-
*/
147-
private val context: CoroutineContext,
139+
internal expect suspend fun Transactor.asConnectionLease(): SQLiteConnectionLease
140+
141+
internal abstract class RoomTransactionLease(
142+
protected val transactor: Transactor,
148143
) : SQLiteConnectionLease {
149144
override suspend fun isInTransaction(): Boolean = transactor.inTransaction()
150145

151-
override suspend fun <R> usePrepared(
152-
sql: String,
153-
block: (SQLiteStatement) -> R,
154-
): R = transactor.usePrepared(sql, block)
155-
156146
override suspend fun <R> usePreparedAsync(
157147
sql: String,
158148
block: suspend (SQLiteStatement) -> R,
159149
): R = transactor.usePrepared(sql, block)
160-
161-
override fun isInTransactionSync(): Boolean =
162-
runBlocking(context) {
163-
isInTransaction()
164-
}
165-
166-
override fun <R> usePreparedSync(
167-
sql: String,
168-
block: (SQLiteStatement) -> R,
169-
): R =
170-
runBlocking(context) {
171-
usePrepared(sql, block)
172-
}
173150
}

integrations/room/src/commonMain/kotlin/com/powersync/integrations/room/PowerSyncExtension.kt renamed to integrations/room/src/commonNonWeb/kotlin/com/powersync/integrations/room/PowerSyncExtension.kt

File renamed without changes.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.powersync.integrations.room
2+
3+
import androidx.room3.Transactor
4+
import androidx.sqlite.SQLiteStatement
5+
import com.powersync.db.driver.SQLiteConnectionLease
6+
import kotlinx.coroutines.currentCoroutineContext
7+
import kotlinx.coroutines.runBlocking
8+
import kotlin.coroutines.CoroutineContext
9+
10+
internal actual suspend fun Transactor.asConnectionLease(): SQLiteConnectionLease =
11+
SyncRoomTransactionLease(this, currentCoroutineContext())
12+
13+
private class SyncRoomTransactionLease(
14+
transactor: Transactor,
15+
private val context: CoroutineContext,
16+
) : RoomTransactionLease(transactor) {
17+
override suspend fun <R> usePrepared(
18+
sql: String,
19+
block: (SQLiteStatement) -> R,
20+
): R = transactor.usePrepared(sql, block)
21+
22+
override fun isInTransactionSync(): Boolean =
23+
runBlocking(context) {
24+
isInTransaction()
25+
}
26+
27+
override fun <R> usePreparedSync(
28+
sql: String,
29+
block: (SQLiteStatement) -> R,
30+
): R =
31+
runBlocking(context) {
32+
usePrepared(sql, block)
33+
}
34+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.powersync.integrations.room
2+
3+
import androidx.room3.Transactor
4+
import com.powersync.db.driver.SQLiteConnectionLease
5+
6+
internal actual suspend fun Transactor.asConnectionLease(): SQLiteConnectionLease = WebRoomTransactionLease(this)
7+
8+
private class WebRoomTransactionLease(
9+
transactor: Transactor,
10+
) : RoomTransactionLease(transactor)

0 commit comments

Comments
 (0)