Skip to content

Implement connection pool in Swift, remove Kotlin framework#130

Draft
simolus3 wants to merge 43 commits intomainfrom
swift-pool
Draft

Implement connection pool in Swift, remove Kotlin framework#130
simolus3 wants to merge 43 commits intomainfrom
swift-pool

Conversation

@simolus3
Copy link
Copy Markdown
Contributor

@simolus3 simolus3 commented Apr 23, 2026

This implements SqlCursor and connection pools directly in Swift instead of depending on a Kotlin XCFramework. On a high level, this PR:

  • Moves some protocol methods into extensions. For instance, the get$Type(name:) functions on SqlCursor are now implemented by delegating to get$Type(index:).
  • Changes the SQLiteConnectionPoolProtocol protocol to be able to actually run statements instead of just exposing a sqlite3* pointer. This allows using high-level GRDB APIs to implement that, which lets GRDB track updates and allows us to skip the session hack.
  • Adds a Swift implementation of SQLiteConnectionPoolProtocol responsible for opening connections, configuring them and to dispatch queries on a background thread. The actual implementation is close to what we have on JavaScript, with an AsyncSemaphore helper guarding connections.
  • Uses a direct function call to load the core extension! We can let the OS loader take care of loading the core extension framework, avoiding sqlite3_load_extension and having to resolve the path manually.

For the native SQLite wrapper, the implementation consists of these structs:

  • NativeSqliteStatement is an owning (~Copyable) struct managing a SQLite statement and exposing raw SQLite methods to step through it.
  • StatementCursor implements the existing SqlCursor protocol with a dynamic reference to a NativeSqliteStatement. Ideally, I would have preferred this to be ~Copyable as well and change APIs to give users a borrowing SqlCursor in callbacks for safety. That would be breaking though, so we instead have manual checks to verify a cursor isn't used outside of its callback.
  • NativeConnectionPool manages a write connection (and an optional collection of readers). These are implemented through the owning RawSqliteConnection struct and an AsyncSemaphore with a design taken from our JS SDK implementation. We use the core extension with powersync_update_hooks to dispatch update notifications. For simplicity, this class is not responsible for opening connections or dispatching writes to a background thread.
  • AsyncConnectionPool is responsible for opening connections and supports both in-memory databases and files in the default database directory (the design is so that we can potentially support custom paths in the future as well). It wraps a NativeConnectionPool for concurrency control and invokes callbacks on DispatchQueue.global(qos:)` to avoid blocking the main thread.
  • PowerSyncDatabaseImpl implements high-level PowerSync APIs by opening a pool and running the usual initial statements to resolve the initial sync state.

Most of this is covered by existing tests, I've added a simple additional test covering how we bind parameter values.

@simolus3 simolus3 mentioned this pull request Apr 27, 2026
8 tasks
Base automatically changed from swift-sync-client to main April 29, 2026 07:06
@simolus3 simolus3 marked this pull request as ready for review April 29, 2026 08:27
@simolus3 simolus3 requested a review from stevensJourney April 29, 2026 08:27
@simolus3 simolus3 marked this pull request as draft April 30, 2026 15:58
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.

1 participant