Skip to content

Commit 5434a5f

Browse files
Merge remote-tracking branch 'origin/main' into grdb-drivers
2 parents 587934c + ee9984a commit 5434a5f

File tree

65 files changed

+1377
-318
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1377
-318
lines changed

.github/workflows/deploy.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
outputs:
1212
tag: ${{ steps.tag.outputs.tag }}
1313
steps:
14-
- uses: actions/checkout@v4
14+
- uses: actions/checkout@v5
1515
with:
1616
fetch-depth: 0
1717

@@ -32,7 +32,7 @@ jobs:
3232
maven_publish:
3333
runs-on: macos-latest
3434
steps:
35-
- uses: actions/checkout@v4
35+
- uses: actions/checkout@v5
3636
- name: Validate Gradle Wrapper
3737
uses: gradle/wrapper-validation-action@v1
3838
- uses: actions/cache@v3
@@ -81,14 +81,14 @@ jobs:
8181
with:
8282
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
8383
- name: Build frameworks
84-
run: "./gradlew PowerSyncKotlin:buildRelease"
84+
run: "./gradlew internal:PowerSyncKotlin:buildRelease"
8585

8686
- uses: actions/upload-artifact@v4
8787
with:
8888
name: XCFramework
8989
retention-days: 1 # Only used temporarily
9090
compression-level: 0 # We're already uploading a compressed file
91-
path: PowerSyncKotlin/build/FrameworkArchives/PowersyncKotlinRelease.zip
91+
path: internal/PowerSyncKotlin/build/FrameworkArchives/PowersyncKotlinRelease.zip
9292
if-no-files-found: error
9393

9494
add_assets:

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 1.7.0 (unreleased)
4+
5+
- Add `PowerSyncDatabase.inMemory` to create an in-memory SQLite database with PowerSync.
6+
This may be useful for testing.
7+
- The Supabase connector can now be subclassed to customize how rows are uploaded and how errors are handled.
8+
- Experimental support for sync streams.
9+
310
## 1.6.1
411

512
* Fix `dlopen failed: library "libpowersync.so.so" not found` errors on Android.

README.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,14 @@ and API documentation [here](https://powersync-ja.github.io/powersync-kotlin/).
2626

2727
- This is the Kotlin Multiplatform SDK implementation.
2828

29-
- [connectors](./connectors/)
30-
31-
- [SupabaseConnector.kt](./connectors/supabase/src/commonMain/kotlin/com/powersync/connector/supabase/SupabaseConnector.kt) An example connector implementation for Supabase (Postgres). The backend
32-
connector provides the connection between your application backend and the PowerSync managed database. It is used to:
33-
1. Retrieve a token to connect to the PowerSync service.
34-
2. Apply local changes on your backend application server (and from there, to your backend database).
35-
3629
- [integrations](./integrations/)
3730
- [room](./integrations/room/README.md): Allows using the [Room database library](https://developer.android.com/jetpack/androidx/releases/room) with PowerSync, making it easier to run typed queries on the database.
3831
- [sqldelight](./integrations/sqldelight/README.md): Allows using [SQLDelight](https://sqldelight.github.io/sqldelight)
3932
with PowerSync, also enabling typed statements on the database.
40-
33+
- [SupabaseConnector.kt](./integrations/supabase/src/commonMain/kotlin/com/powersync/connector/supabase/SupabaseConnector.kt) An example connector implementation for Supabase (Postgres). The backend
34+
connector provides the connection between your application backend and the PowerSync managed database. It is used to:
35+
1. Retrieve a token to connect to the PowerSync service.
36+
2. Apply local changes on your backend application server (and from there, to your backend database).
4137

4238
## Demo Apps / Example Projects
4339

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ tasks.getByName<Delete>("clean") {
6868
// Merges individual module docs into a single HTML output
6969
dependencies {
7070
dokka(project(":core:"))
71-
dokka(project(":connectors:supabase"))
7271
dokka(project(":compose:"))
7372
dokka(project(":integrations:room"))
7473
dokka(project(":integrations:sqldelight"))
74+
dokka(project(":integrations:supabase"))
7575
}
7676

7777
dokka {

core/src/androidMain/kotlin/com/powersync/DatabaseDriverFactory.android.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,5 @@ public fun BundledSQLiteDriver.addPowerSyncExtension() {
2626
@ExperimentalPowerSyncAPI
2727
@Throws(PowerSyncException::class)
2828
public actual fun resolvePowerSyncLoadableExtensionPath(): String? = "libpowersync.so"
29+
30+
internal actual fun openInMemoryConnection(): SQLiteConnection = BundledSQLiteDriver().also { it.addPowerSyncExtension() }.open(":memory:")

core/src/appleNonWatchOsMain/kotlin/com/powersync/DatabaseDriverFactory.appleNonWatchOs.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ public actual class DatabaseDriverFactory {
2525
@ExperimentalPowerSyncAPI
2626
@Throws(PowerSyncException::class)
2727
public actual fun resolvePowerSyncLoadableExtensionPath(): String? = powerSyncExtensionPath
28+
29+
internal actual fun openInMemoryConnection(): SQLiteConnection = DatabaseDriverFactory().openConnection(":memory:", 0x02)

core/src/commonIntegrationTest/kotlin/com/powersync/DatabaseTest.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.powersync
22

3-
import androidx.sqlite.SQLiteConnection
4-
import androidx.sqlite.execSQL
53
import app.cash.turbine.test
64
import app.cash.turbine.turbineScope
75
import co.touchlab.kermit.ExperimentalKermitApi
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.powersync.db
2+
3+
import app.cash.turbine.turbineScope
4+
import co.touchlab.kermit.ExperimentalKermitApi
5+
import co.touchlab.kermit.Logger
6+
import co.touchlab.kermit.Severity
7+
import co.touchlab.kermit.TestConfig
8+
import co.touchlab.kermit.TestLogWriter
9+
import com.powersync.PowerSyncDatabase
10+
import com.powersync.db.schema.Column
11+
import com.powersync.db.schema.Schema
12+
import com.powersync.db.schema.Table
13+
import io.kotest.matchers.collections.shouldHaveSize
14+
import io.kotest.matchers.shouldBe
15+
import kotlinx.coroutines.test.runTest
16+
import kotlin.test.Test
17+
18+
@OptIn(ExperimentalKermitApi::class)
19+
class InMemoryTest {
20+
private val logWriter =
21+
TestLogWriter(
22+
loggable = Severity.Debug,
23+
)
24+
25+
private val logger =
26+
Logger(
27+
TestConfig(
28+
minSeverity = Severity.Debug,
29+
logWriterList = listOf(logWriter),
30+
),
31+
)
32+
33+
@Test
34+
fun createsSchema() =
35+
runTest {
36+
val db = PowerSyncDatabase.Companion.inMemory(schema, this, logger)
37+
try {
38+
db.getAll("SELECT * FROM users") { } shouldHaveSize 0
39+
} finally {
40+
db.close()
41+
}
42+
}
43+
44+
@Test
45+
fun watch() =
46+
runTest {
47+
val db = PowerSyncDatabase.Companion.inMemory(schema, this, logger)
48+
try {
49+
turbineScope {
50+
val turbine =
51+
db.watch("SELECT name FROM users", mapper = { it.getString(0)!! }).testIn(this)
52+
53+
turbine.awaitItem() shouldBe listOf()
54+
55+
db.execute("INSERT INTO users (id, name) VALUES (uuid(), ?)", listOf("test user"))
56+
turbine.awaitItem() shouldBe listOf("test user")
57+
turbine.cancelAndIgnoreRemainingEvents()
58+
}
59+
} finally {
60+
db.close()
61+
}
62+
}
63+
64+
companion object {
65+
private val schema =
66+
Schema(
67+
Table(
68+
name = "users",
69+
columns =
70+
listOf(
71+
Column.Companion.text("name"),
72+
),
73+
),
74+
)
75+
}
76+
}

core/src/commonIntegrationTest/kotlin/com/powersync/sync/SyncIntegrationTest.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import com.powersync.PowerSyncDatabase
77
import com.powersync.PowerSyncException
88
import com.powersync.TestConnector
99
import com.powersync.bucket.BucketChecksum
10-
import com.powersync.bucket.BucketPriority
1110
import com.powersync.bucket.Checkpoint
1211
import com.powersync.bucket.OpType
1312
import com.powersync.bucket.OplogEntry
13+
import com.powersync.bucket.StreamPriority
1414
import com.powersync.bucket.WriteCheckpointData
1515
import com.powersync.bucket.WriteCheckpointResponse
1616
import com.powersync.connectors.PowerSyncBackendConnector
@@ -165,7 +165,7 @@ abstract class BaseSyncIntegrationTest(
165165
add(
166166
BucketChecksum(
167167
bucket = "bucket$prio",
168-
priority = BucketPriority(prio),
168+
priority = StreamPriority(prio),
169169
checksum = 10 + prio,
170170
),
171171
)
@@ -218,7 +218,7 @@ abstract class BaseSyncIntegrationTest(
218218

219219
// Emit a partial sync complete for each priority but the last.
220220
for (priorityNo in 0..<3) {
221-
val priority = BucketPriority(priorityNo)
221+
val priority = StreamPriority(priorityNo)
222222
pushData(priorityNo)
223223
syncLines.send(
224224
SyncLine.CheckpointPartiallyComplete(
@@ -258,7 +258,7 @@ abstract class BaseSyncIntegrationTest(
258258
listOf(
259259
BucketChecksum(
260260
bucket = "bkt",
261-
priority = BucketPriority(1),
261+
priority = StreamPriority(1),
262262
checksum = 0,
263263
),
264264
),
@@ -268,17 +268,17 @@ abstract class BaseSyncIntegrationTest(
268268
syncLines.send(
269269
SyncLine.CheckpointPartiallyComplete(
270270
lastOpId = "0",
271-
priority = BucketPriority(1),
271+
priority = StreamPriority(1),
272272
),
273273
)
274274

275-
database.waitForFirstSync(BucketPriority(1))
275+
database.waitForFirstSync(StreamPriority(1))
276276
database.close()
277277

278278
// Connect to the same database again
279279
database = openDatabaseAndInitialize()
280280
database.currentStatus.hasSynced shouldBe false
281-
database.currentStatus.statusForPriority(BucketPriority(1)).hasSynced shouldBe true
281+
database.currentStatus.statusForPriority(StreamPriority(1)).hasSynced shouldBe true
282282
}
283283

284284
@Test

core/src/commonIntegrationTest/kotlin/com/powersync/sync/SyncProgressTest.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ package com.powersync.sync
33
import app.cash.turbine.ReceiveTurbine
44
import app.cash.turbine.turbineScope
55
import com.powersync.bucket.BucketChecksum
6-
import com.powersync.bucket.BucketPriority
76
import com.powersync.bucket.Checkpoint
87
import com.powersync.bucket.OpType
98
import com.powersync.bucket.OplogEntry
9+
import com.powersync.bucket.StreamPriority
1010
import com.powersync.testutils.ActiveDatabaseTest
1111
import com.powersync.testutils.databaseTest
1212
import com.powersync.testutils.waitFor
@@ -35,7 +35,7 @@ abstract class BaseSyncProgressTest(
3535
private fun bucket(
3636
name: String,
3737
count: Int,
38-
priority: BucketPriority = BucketPriority(3),
38+
priority: StreamPriority = StreamPriority(3),
3939
): BucketChecksum =
4040
BucketChecksum(
4141
bucket = name,
@@ -68,7 +68,7 @@ abstract class BaseSyncProgressTest(
6868
)
6969
}
7070

71-
private suspend fun ActiveDatabaseTest.addCheckpointComplete(priority: BucketPriority? = null) {
71+
private suspend fun ActiveDatabaseTest.addCheckpointComplete(priority: StreamPriority? = null) {
7272
if (priority != null) {
7373
syncLines.send(
7474
SyncLine.CheckpointPartiallyComplete(
@@ -93,7 +93,7 @@ abstract class BaseSyncProgressTest(
9393

9494
private suspend fun ReceiveTurbine<SyncStatusData>.expectProgress(
9595
total: Pair<Int, Int>,
96-
priorities: Map<BucketPriority, Pair<Int, Int>> = emptyMap(),
96+
priorities: Map<StreamPriority, Pair<Int, Int>> = emptyMap(),
9797
) {
9898
val item = awaitItem()
9999
val progress = item.downloadProgress ?: error("Expected download progress on $item")
@@ -357,7 +357,7 @@ abstract class BaseSyncProgressTest(
357357
) {
358358
turbine.expectProgress(
359359
prio2,
360-
mapOf(BucketPriority(0) to prio0, BucketPriority(2) to prio2),
360+
mapOf(StreamPriority(0) to prio0, StreamPriority(2) to prio2),
361361
)
362362
}
363363

@@ -367,8 +367,8 @@ abstract class BaseSyncProgressTest(
367367
lastOpId = "10",
368368
checksums =
369369
listOf(
370-
bucket("a", 5, BucketPriority(0)),
371-
bucket("b", 5, BucketPriority(2)),
370+
bucket("a", 5, StreamPriority(0)),
371+
bucket("b", 5, StreamPriority(2)),
372372
),
373373
),
374374
),
@@ -378,7 +378,7 @@ abstract class BaseSyncProgressTest(
378378
addDataLine("a", 5)
379379
expectProgress(5 to 5, 5 to 10)
380380

381-
addCheckpointComplete(BucketPriority(0))
381+
addCheckpointComplete(StreamPriority(0))
382382
expectProgress(5 to 5, 5 to 10)
383383

384384
addDataLine("b", 2)
@@ -390,8 +390,8 @@ abstract class BaseSyncProgressTest(
390390
lastOpId = "14",
391391
updatedBuckets =
392392
listOf(
393-
bucket("a", 8, BucketPriority(0)),
394-
bucket("b", 6, BucketPriority(2)),
393+
bucket("a", 8, StreamPriority(0)),
394+
bucket("b", 6, StreamPriority(2)),
395395
),
396396
removedBuckets = emptyList(),
397397
),

0 commit comments

Comments
 (0)