Skip to content

Update Kotlin SDK, support raw tables #61

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Changelog

## 1.2.2 (unreleased)
## 1.3.0

* Use version `0.4.2` of the PowerSync core extension, which improves the reliability
of the new Rust client implementation.
* Add support for [raw tables](https://docs.powersync.com/usage/use-case-examples/raw-tables), which
are custom tables managed by the user instead of JSON-based views managed by the SDK.
* Fix attachments never downloading again when the sandbox path of the app (e.g. on the simulator)
changes.

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ if let kotlinSdkPath = localKotlinSdkOverride {
// Not using a local build, so download from releases
conditionalTargets.append(.binaryTarget(
name: "PowerSyncKotlin",
url: "https://github.com/powersync-ja/powersync-kotlin/releases/download/v1.2.2/PowersyncKotlinRelease.zip",
checksum: "51ddc7d48fa85e881c33a26ca63e4aae694ae16789368f9fbba20a467279fb97"
url: "https://github.com/powersync-ja/powersync-kotlin/releases/download/v1.3.0/PowersyncKotlinRelease.zip",
checksum: "5351c0a89e74ceaad570cd5c016c8ea4b8e10dc404daff3c20485ae0b6b989fa"
))
}

Expand Down
32 changes: 30 additions & 2 deletions Sources/PowerSync/Kotlin/KotlinAdapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,30 @@ enum KotlinAdapter {
ignoreEmptyUpdates: table.ignoreEmptyUpdates
)
}

static func toKotlin(_ table: RawTable) -> PowerSyncKotlin.RawTable {
return PowerSyncKotlin.RawTable(
name: table.name,
put: translateStatement(table.put),
delete: translateStatement(table.delete)
);
}

private static func translateStatement(_ stmt: PendingStatement) -> PowerSyncKotlin.PendingStatement {
return PowerSyncKotlin.PendingStatement(
sql: stmt.sql,
parameters: stmt.parameters.map(translateParameter)
)
}

private static func translateParameter(_ param: PendingStatementParameter) -> PowerSyncKotlin.PendingStatementParameter {
switch param {
case .id:
return PowerSyncKotlin.PendingStatementParameterId.shared
case .column(let name):
return PowerSyncKotlin.PendingStatementParameterColumn(name: name)
}
}
}

struct Column {
Expand All @@ -68,8 +92,12 @@ enum KotlinAdapter {

struct Schema {
static func toKotlin(_ schema: SchemaProtocol) -> PowerSyncKotlin.Schema {
PowerSyncKotlin.Schema(
tables: schema.tables.map { Table.toKotlin($0) }
var mappedTables: [PowerSyncKotlin.BaseTable] = []
mappedTables.append(contentsOf: schema.tables.map(Table.toKotlin))
mappedTables.append(contentsOf: schema.rawTables.map(Table.toKotlin))

return PowerSyncKotlin.Schema(
tables: mappedTables
)
}
}
Expand Down
60 changes: 60 additions & 0 deletions Sources/PowerSync/Protocol/Schema/RawTable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/// A table that is managed by the user instead of being auto-created and migrated by the PowerSync SDK.
///
/// These tables give application developers full control over the table (including table and column constraints).
/// The ``RawTable/put`` and ``RawTable/delete`` statements used by the sync client to apply
/// operations to the local database also need to be set explicitly.
///
/// A main benefit of raw tables is that, since they're not backed by JSON views, complex queries on them
/// can be much more efficient.
/// However, it's the responsibility of the developer to create these raw tables, migrate them when necessary
/// and to write triggers detecting local writes. For more information, see [the documentation](https://docs.powersync.com/usage/use-case-examples/raw-tables).
///
/// Note that raw tables are only supported when ``ConnectOptions/newClientImplementation``
/// is enabled.
public struct RawTable: BaseTableProtocol {
/// The name of the table as it appears in sync rules.
///
/// This doesn't necessarily have to match the statement that ``RawTable/put`` and ``RawTable/delete``
/// write into.
/// Instead, it is used by the sync client to identify which operations need to use which raw table definition.
public let name: String

/// The statement to run when the sync client has to insert or update a row.
public let put: PendingStatement

/// The statement to run when the sync client has to delete a row.
public let delete: PendingStatement

public init(name: String, put: PendingStatement, delete: PendingStatement) {
self.name = name;
self.put = put;
self.delete = delete;
}
}

/// A statement to run to sync server-side changes into a local raw table.
public struct PendingStatement {
/// The SQL statement to execute.
public let sql: String
/// For parameters in the prepared statement, the values to fill in.
///
/// Note that the ``RawTable/delete`` statement can only use ``PendingStatementParameter/id`` - upsert
/// statements can also use ``PendingStatementParameter/column`` to refer to columns.
public let parameters: [PendingStatementParameter]

public init(sql: String, parameters: [PendingStatementParameter]) {
self.sql = sql
self.parameters = parameters
}
}

/// A parameter that can be used in a ``PendingStatement``.
public enum PendingStatementParameter {
/// A value that resolves to the textual id of the row to insert, update or delete.
case id
/// A value that resolves to the value of a column in a `PUT` operation for inserts or updates.
///
/// Note that using this parameter is not allowed for ``RawTable/delete`` statements, which only have access
/// to the row's ``PendingStatementParameter/id``.
case column(String)
}
24 changes: 21 additions & 3 deletions Sources/PowerSync/Protocol/Schema/Schema.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ public protocol SchemaProtocol {
/// Tables used in Schema
///
var tables: [Table] { get }

/// Raw tables referenced in the schema.
var rawTables: [RawTable] { get }
///
/// Validate tables
///
Expand All @@ -11,15 +14,30 @@ public protocol SchemaProtocol {

public struct Schema: SchemaProtocol {
public let tables: [Table]
public let rawTables: [RawTable]

public init(tables: [Table]) {
public init(tables: [Table], rawTables: [RawTable] = []) {
self.tables = tables
self.rawTables = rawTables
}
///
/// Convenience initializer with variadic parameters
///
public init(_ tables: Table...) {
self.init(tables: tables)
public init(_ tables: BaseTableProtocol...) {
var managedTables: [Table] = []
var rawTables: [RawTable] = []

for table in tables {
if let table = table as? Table {
managedTables.append(table)
} else if let rawTable = table as? RawTable {
rawTables.append(rawTable)
} else {
fatalError("BaseTableProtocol must only be implemented in Swift SDK")
}
}

self.init(tables: managedTables, rawTables: rawTables)
}

public func validate() throws {
Expand Down
7 changes: 6 additions & 1 deletion Sources/PowerSync/Protocol/Schema/Table.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import Foundation

public protocol TableProtocol {
/// Shared protocol for both PowerSync-managed ``Table``s as well as ``RawTable``s managed by the user.
public protocol BaseTableProtocol {
///
/// The synced table name, matching sync rules.
///
var name: String { get }
}

/// Protocol for describing ``Table``s managed by PowerSync.
public protocol TableProtocol: BaseTableProtocol {
///
/// List of columns.
///
Expand Down
Loading