Skip to content

Conversation

simolus3
Copy link
Contributor

@simolus3 simolus3 commented Jul 25, 2025

Overview

To make the PowerSync Kotlin and Swift SDKs easier to integrate with other database libraries providing asynchronous database access, users need the ability to use the SDK without the builtin connection pool.

To facilitate this, this adds the new SQLiteConnectionPool interface, which

  • has read() and write() methods taking a suspend (SQLiteConnectionLease) -> T to schedule read and write operations on the pool.
  • SQLiteConnectionLease in turn provides two methods:
    • isInTransaction(), reporting the autocommit state
    • usePrepared(), giving users temporary access to a raw prepared statement
  • Can be used to create a PowerSyncDatabase instance, with the new PowerSyncDatabase.opened method. The internal opening logic has also been refactored to call that method after constructing a pool.

This interface mirrors the semantics of a WAL connection pool, and has also been designed so that a SQLiteConnectionPool can easily be implemented ontop of Room: The read() and write() methods correspond to useConnection in Room, see the Transactor API from Room for a comparison.

In :core, existing public interfaces like the cursor are then consistently implemented across the common underlying connection pool API.
I've also added a new API to PowerSyncDatabase to give out a temporary view to an underlying SQLiteConnection. This would give users full control over the statements to run, while still letting the PowerSync SDK taking care of connection management.

New SQLite interface

Previously, we've used SQLDelight and SQLiter libraries internally. The main issue with those is that they do too much, and don't give us enough control to implement the SQLiteConnectionPool API we need for Room or GRDB support:

  • SQLiter doesn't support custom database directories on iOS.
  • SQLDelight is great for applications, but its interfaces are also fairly high-level and not as suitable for a library like PowerSync.
  • As an example of this, we're currently running a pointless empty migration to version 1 just because the internal libraries need a migration to open database...
  • sqlite-jdbc is cool, but also very jdbc-centric and doesn't support some APIs we really want (like isInTransaction()).

This restructures our internal driver implementations to be aligned with cross-platform APIs from the androidx.sqlite:sqlite library, and removes all internal usages of SQLiter, SQLDelight and sqlite-jdbc.

Because the higher layers of the SDK are implemented ontop of a SQLiteConnectionPool, this also adds a pool implementation based on multiple SQLiteConnection instances (although we mostly had that before as well).

New SQLite implementation

Because the interface to access SQLite databases has changed, we'll also need new implementations. The androidx project maintains a cross-platform SQLiteConnection implementation (in the androidx.sqlite:sqlite-bundled artifact). Ideally, we would just be using that. In practice however, we get linker errors then integrating our XCFramework into the Swift SDK :(
I have send a PR upstream to fix this. In the meantime, using our existing static-sqlite-driver package to implement SQLiteConnection with cinterop is not that bad of an alternative.

So, to summarize which implementations are used:

Platform Implementation before Implementation after
Android sqlite-jdbc + SQLDelight androidx.sqlite:sqlite-bundled
JVM sqlite-jdbc + SQLDelight androidx.sqlite:sqlite-bundled
Apple (watchOS, iOS, tvOS, macOS) SQLiter + SQLDelight + static-slqite-driver Custom SQLite bindings + static-slqite-driver

TODOs:

  • Check Swift SDK still works with this.
  • Check we're using the same paths as SQLiter by default

@simolus3 simolus3 marked this pull request as ready for review September 5, 2025 13:43
stevensJourney
stevensJourney previously approved these changes Sep 8, 2025
Copy link
Contributor

@stevensJourney stevensJourney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm very very happy with the changes here. This is amazing.

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR removes internal dependencies on SQLDelight and SQLiter libraries and replaces them with Android's androidx.sqlite bindings internally. The main purpose is to make the PowerSync Kotlin and Swift SDKs easier to integrate with other database libraries by introducing a new SQLiteConnectionPool interface.

Key changes:

  • Introduced new SQLiteConnectionPool interface for external database integration
  • Replaced SQLiter/SQLDelight with androidx.sqlite bindings across all platforms
  • Added new internal SQLite connection implementations for Apple platforms using cinterop

Reviewed Changes

Copilot reviewed 66 out of 67 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
settings.gradle.kts Updated module paths and removed deprecated modules
gradle/libs.versions.toml Updated dependencies, removed SQLDelight and SQLiter, updated androidx.sqlite version
core/src/commonMain/kotlin/com/powersync/db/driver/SQLiteConnectionPool.kt New interface for connection pool abstraction
core/src/nativeMain/kotlin/com/powersync/sqlite/ New SQLite implementation for Apple platforms using cinterop
core/src/jvmMain/kotlin/com/powersync/DatabaseDriverFactory.jvm.kt Updated to use BundledSQLiteDriver instead of JDBC
core/src/androidMain/kotlin/com/powersync/DatabaseDriverFactory.android.kt Updated to use BundledSQLiteDriver
core/build.gradle.kts Updated build configuration, removed JDBC dependencies, added sqlite3 cinterop
Comments suppressed due to low confidence (2)

core/src/nativeMain/kotlin/com/powersync/sqlite/Statement.kt:1

  • There's a grammatical error in the documentation comment: 'Block most only run' should be 'Block must only run'.
package com.powersync.sqlite

plugins/build-plugin/src/main/kotlin/com/powersync/compile/CreateSqliteCInterop.kt:1

  • [nitpick] This import appears to be unused after the removal. Consider removing this import statement to clean up the code.
package com.powersync.compile

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@simolus3 simolus3 merged commit 7650661 into main Sep 9, 2025
7 of 8 checks passed
@simolus3 simolus3 deleted the refactor-drivers branch September 9, 2025 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants