Skip to content

Conversation

stevensJourney
Copy link
Contributor

Overview

This adds an integration with the Structured Queries library in order to provide typed query execution.

A new PowerSyncStructuredQueries library Product has been added to the monorepo with a small example Swift executable StructuredQueriesExample which uses the library.

Background

PowerSync currently only allows using raw SQL statements and SqlCursors to execute SQL operations. Queries are specified as SQL strings and the result for SELECT operations are mapped to the result type using a mapper closure which uses a SqlCursor to access result set column values.

let user: User = try await database.get(
    sql: "SELECT id, name, email FROM users WHERE id = ?",
    parameters: ["1"]
) { cursor in
    try User (
        id: cursor.getString(name: "id"),
        name: cursor.getString(name: "name"),
        email: cursor.getString(name: "email")
    )
}

Where User above can be a Swift struct which is manually instantiated inside the mapper closure.

A structured query approach would involve:

  1. Combining the data class definitions (e.g. User above) with the SQL table definitions.
  2. Using the data class definitions to construct the relevant query operations.
  3. Executing query operations and returning the typed result set values automatically

Structured Queries

StructuredQueries provides a suite of tools that empower you to write safe, expressive, composable SQL with Swift. By simply attaching macros to types that represent your database schema

The Structured Queries library takes care of 1 and 2, but it lacks any concrete SQL driver implementations for 3.

The sharing-grdb project provides an integration with the GRDB SQLite driver to perform 3.

PowerSync is currently not directly compatible with GRDB (although this might change in the future). The work here follows the patterns of Sharing GRDB to include PowerSync as the SQLite driver for executing structured queries.

@StructuredQueries.Table("users")
struct User {
    var id: String
    var name: String
    var birthday: Date?
}

let powersync = PowerSyncDatabase(...)

try await User.insert {
    ($0.id, $0.name, $0.birthday)
} values: {
    (testUserID, "Steven", Date())
}.execute(powersync)

let users = try await User.all.fetchAll(powersync)

Outstanding work

The Structured Query table definitions are currently not shared with the PowerSync client side schema definition. It should be possible to potentially declare this once.

This work here extends the Statement protocol in order to add the execute and fetchAll methods (similar to the sharing-grdb implementation). Additional extensions are required for for more complex queries like joins.

The sharing-grdb library exposes reactive macros for fetching observable data in UI applications. This is not implemented here yet.

Base automatically changed from swift-concurrency to main August 27, 2025 08:51
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