From 10d0d795428b33a6dcd463ec1bf6159e62034d5d Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Thu, 23 Oct 2025 17:27:08 +0200 Subject: [PATCH 01/14] Prepare for Kotlin common module --- Package.resolved | 9 +++++++++ Package.swift | 15 +++++++++++---- .../Kotlin/KotlinPowerSyncDatabaseImpl.swift | 2 +- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Package.resolved b/Package.resolved index a62a2d5..8bba077 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,14 @@ { "pins" : [ + { + "identity" : "csqlite", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sbooth/CSQLite.git", + "state" : { + "revision" : "b1161e6c73fa68c25292f6bb697293d6c679f919", + "version" : "3.50.4" + } + }, { "identity" : "powersync-sqlite-core-swift", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index cece14d..438c8d9 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.7 +// swift-tools-version: 6.1 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -18,14 +18,20 @@ let localCoreExtension: String? = nil // a binary target. // With a local SDK, we point to a `Package.swift` within the Kotlin SDK containing a target pointing // towards a local framework build -var conditionalDependencies: [Package.Dependency] = [] +var conditionalDependencies: [Package.Dependency] = [ + .package( + url: "https://github.com/sbooth/CSQLite.git", + from: "3.50.4", + traits: ["ENABLE_SESSION"] + ) +] var conditionalTargets: [Target] = [] var kotlinTargetDependency = Target.Dependency.target(name: "PowerSyncKotlin") if let kotlinSdkPath = localKotlinSdkOverride { // We can't depend on local XCFrameworks outside of this project's root, so there's a Package.swift // in the PowerSyncKotlin project pointing towards a local build. - conditionalDependencies.append(.package(path: "\(kotlinSdkPath)/PowerSyncKotlin")) + conditionalDependencies.append(.package(path: "\(kotlinSdkPath)/internal/PowerSyncKotlin")) kotlinTargetDependency = .product(name: "PowerSyncKotlin", package: "PowerSyncKotlin") } else { @@ -81,7 +87,8 @@ let package = Package( name: packageName, dependencies: [ kotlinTargetDependency, - .product(name: "PowerSyncSQLiteCore", package: corePackageName) + .product(name: "PowerSyncSQLiteCore", package: corePackageName), + .product(name: "CSQLite", package: "CSQLite") ] ), .testTarget( diff --git a/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift b/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift index aa81d1d..c795366 100644 --- a/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift +++ b/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift @@ -16,7 +16,7 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol, dbFilename: String, logger: DatabaseLogger ) { - let factory = PowerSyncKotlin.DatabaseDriverFactory() + let factory = sqlite3DatabaseFactory(initialStatements: []) kotlinDatabase = PowerSyncDatabase( factory: factory, schema: KotlinAdapter.Schema.toKotlin(schema), From 9ddc7065c6df8e964e6b996506ba6fedc3fdabc7 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 27 Oct 2025 11:58:02 +0100 Subject: [PATCH 02/14] Update PowerSync Kotlin and core extension --- Package.resolved | 7 +++--- Package.swift | 6 ++--- Sources/PowerSync/Kotlin/KotlinAdapter.swift | 3 ++- .../Kotlin/KotlinPowerSyncDatabaseImpl.swift | 3 ++- .../Protocol/PowerSyncDatabaseProtocol.swift | 22 +++++++++++++------ .../PowerSync/Protocol/Schema/RawTable.swift | 6 ++++- Tests/PowerSyncTests/CrudTests.swift | 15 +++++++++++++ 7 files changed, 46 insertions(+), 16 deletions(-) diff --git a/Package.resolved b/Package.resolved index 8bba077..d0dc9d8 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,4 +1,5 @@ { + "originHash" : "82539474c4bcedf04818c668b504533c49309a0dd3669f4ec2fb8e77b64439b3", "pins" : [ { "identity" : "csqlite", @@ -14,10 +15,10 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/powersync-ja/powersync-sqlite-core-swift.git", "state" : { - "revision" : "b2a81af14e9ad83393eb187bb02e62e6db8b5ad6", - "version" : "0.4.6" + "revision" : "9801f4aa0923c7f33fa479a01e643d00e7764f0b", + "version" : "0.4.8" } } ], - "version" : 2 + "version" : 3 } diff --git a/Package.swift b/Package.swift index 438c8d9..ce28be9 100644 --- a/Package.swift +++ b/Package.swift @@ -38,8 +38,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.7.0/PowersyncKotlinRelease.zip", - checksum: "836ac106c26a184c10373c862745d9af195737ad01505bb965f197797aa88535" + url: "https://github.com/powersync-ja/powersync-kotlin/releases/download/v1.8.0/PowersyncKotlinRelease.zip", + checksum: "31ac7c5e11d747e11bceb0b34f30438d37033e700c621b0a468aa308d887587f" )) } @@ -51,7 +51,7 @@ if let corePath = localCoreExtension { // Not using a local build, so download from releases conditionalDependencies.append(.package( url: "https://github.com/powersync-ja/powersync-sqlite-core-swift.git", - exact: "0.4.6" + exact: "0.4.8" )) } diff --git a/Sources/PowerSync/Kotlin/KotlinAdapter.swift b/Sources/PowerSync/Kotlin/KotlinAdapter.swift index 8e85220..2d73ab3 100644 --- a/Sources/PowerSync/Kotlin/KotlinAdapter.swift +++ b/Sources/PowerSync/Kotlin/KotlinAdapter.swift @@ -49,7 +49,8 @@ enum KotlinAdapter { return PowerSyncKotlin.RawTable( name: table.name, put: translateStatement(table.put), - delete: translateStatement(table.delete) + delete: translateStatement(table.delete), + clear: table.clear, ); } diff --git a/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift b/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift index c795366..66afb36 100644 --- a/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift +++ b/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift @@ -91,7 +91,8 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol, func disconnectAndClear(clearLocal: Bool = true) async throws { try await kotlinDatabase.disconnectAndClear( - clearLocal: clearLocal + clearLocal: clearLocal, + soft: false ) } diff --git a/Sources/PowerSync/Protocol/PowerSyncDatabaseProtocol.swift b/Sources/PowerSync/Protocol/PowerSyncDatabaseProtocol.swift index c71f95f..b02fe96 100644 --- a/Sources/PowerSync/Protocol/PowerSyncDatabaseProtocol.swift +++ b/Sources/PowerSync/Protocol/PowerSyncDatabaseProtocol.swift @@ -216,12 +216,20 @@ public protocol PowerSyncDatabaseProtocol: Queries, Sendable { func disconnect() async throws /// Disconnect and clear the database. - /// Use this when logging out. - /// The database can still be queried after this is called, but the tables - /// would be empty. /// - /// - Parameter clearLocal: Set to false to preserve data in local-only tables. Defaults to `true`. - func disconnectAndClear(clearLocal: Bool) async throws + /// Clearing the database is useful when a user logs out, to ensure another user logging in later would not see + /// previous data. + /// + /// The database can still be queried after this is called, but the tables would be empty. + /// + /// To perserve data in local-only tables, set `clearLocal` to `false`. + /// + /// A `soft` clear deletes publicly visible data, but keeps internal copies of data synced in the database. This + /// usually means that if the same user logs out and back in again, the first sync is very fast because all internal + /// data is still available. When a different user logs in, no old data would be visible at any point. + /// Using soft clears is recommended where it's not a security issue that old data could be reconstructed from + /// the database. + func disconnectAndClear(clearLocal: Bool, soft: Bool) async throws /// Close the database, releasing resources. /// Also disconnects any active connection. @@ -300,8 +308,8 @@ public extension PowerSyncDatabaseProtocol { ) } - func disconnectAndClear() async throws { - try await disconnectAndClear(clearLocal: true) + func disconnectAndClear(clearLocal: Bool = true, soft: Bool = false) async throws { + try await disconnectAndClear(clearLocal: clearLocal, soft: soft) } func getCrudBatch(limit: Int32 = 100) async throws -> CrudBatch? { diff --git a/Sources/PowerSync/Protocol/Schema/RawTable.swift b/Sources/PowerSync/Protocol/Schema/RawTable.swift index b209583..f8fbcd0 100644 --- a/Sources/PowerSync/Protocol/Schema/RawTable.swift +++ b/Sources/PowerSync/Protocol/Schema/RawTable.swift @@ -24,11 +24,15 @@ public struct RawTable: BaseTableProtocol { /// The statement to run when the sync client has to delete a row. public let delete: PendingStatement + + /// An optional statement to run when the database is cleared. + public let clear: String? - public init(name: String, put: PendingStatement, delete: PendingStatement) { + public init(name: String, put: PendingStatement, delete: PendingStatement, clear: String? = nil) { self.name = name self.put = put self.delete = delete + self.clear = clear } } diff --git a/Tests/PowerSyncTests/CrudTests.swift b/Tests/PowerSyncTests/CrudTests.swift index c315b38..d3a508f 100644 --- a/Tests/PowerSyncTests/CrudTests.swift +++ b/Tests/PowerSyncTests/CrudTests.swift @@ -238,4 +238,19 @@ final class CrudTests: XCTestCase { let finalTx = try await database.getNextCrudTransaction() XCTAssertEqual(finalTx!.crud.count, 15) } + + func testSoftClear() async throws { + try await database.execute(sql: "INSERT INTO users (id, name) VALUES (uuid(), ?)", parameters: ["test"]); + try await database.execute(sql: "INSERT INTO ps_buckets (name, last_applied_op) VALUES (?, ?)", parameters: ["bkt", 10]) + + // Doing a soft-clear should delete data but keep the bucket around. + try await database.disconnectAndClear(soft: true) + let entries = try await database.getAll("SELECT name FROM ps_buckets", mapper: { cursor in try cursor.getString(index: 0) }) + XCTAssertEqual(entries.count, 1) + + // Doing a default clear also deletes buckets. + try await database.disconnectAndClear(); + let newEntries = try await database.getAll("SELECT name FROM ps_buckets", mapper: { cursor in try cursor.getString(index: 0) }) + XCTAssertEqual(newEntries.count, 0) + } } From cf29fe2fa1241145aaaf2784b1a7bcb9c2e59bfa Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 27 Oct 2025 12:19:59 +0100 Subject: [PATCH 03/14] Fix tests --- .../Kotlin/KotlinPowerSyncDatabaseImpl.swift | 4 ++-- .../Protocol/PowerSyncDatabaseProtocol.swift | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift b/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift index 66afb36..ddb1206 100644 --- a/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift +++ b/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift @@ -89,10 +89,10 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol, try await kotlinDatabase.disconnect() } - func disconnectAndClear(clearLocal: Bool = true) async throws { + func disconnectAndClear(clearLocal: Bool, soft: Bool) async throws { try await kotlinDatabase.disconnectAndClear( clearLocal: clearLocal, - soft: false + soft: soft ) } diff --git a/Sources/PowerSync/Protocol/PowerSyncDatabaseProtocol.swift b/Sources/PowerSync/Protocol/PowerSyncDatabaseProtocol.swift index b02fe96..0a8bd75 100644 --- a/Sources/PowerSync/Protocol/PowerSyncDatabaseProtocol.swift +++ b/Sources/PowerSync/Protocol/PowerSyncDatabaseProtocol.swift @@ -308,8 +308,16 @@ public extension PowerSyncDatabaseProtocol { ) } - func disconnectAndClear(clearLocal: Bool = true, soft: Bool = false) async throws { - try await disconnectAndClear(clearLocal: clearLocal, soft: soft) + func disconnectAndClear() async throws { + try await disconnectAndClear(clearLocal: true, soft: false) + } + + func disconnectAndClear(clearLocal: Bool) async throws { + try await disconnectAndClear(clearLocal: clearLocal, soft: false) + } + + func disconnectAndClear(soft: Bool) async throws { + try await disconnectAndClear(clearLocal: true, soft: soft) } func getCrudBatch(limit: Int32 = 100) async throws -> CrudBatch? { From 4fa1e32fa72813353796bd61786a98648347dd03 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 27 Oct 2025 12:24:25 +0100 Subject: [PATCH 04/14] Remove explicit Swift 6 test --- .github/workflows/build_and_test.yaml | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml index f13117d..9a8ff59 100644 --- a/.github/workflows/build_and_test.yaml +++ b/.github/workflows/build_and_test.yaml @@ -14,25 +14,13 @@ jobs: uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: latest-stable - - name: Build and Test + + - name: Test on iOS simulator run: | xcodebuild test -scheme PowerSync-Package -destination "platform=iOS Simulator,name=iPhone 16" - xcodebuild test -scheme PowerSync-Package -destination "platform=macOS,arch=arm64,name=My Mac" - xcodebuild test -scheme PowerSync-Package -destination "platform=watchOS Simulator,arch=arm64,name=Apple Watch Ultra 2 (49mm)" - - buildSwift6: - name: Build and test with Swift 6 - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Set up XCode - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: latest-stable - - name: Use Swift 6 + - name: Test on macOS run: | - sed -i '' 's|^// swift-tools-version:.*$|// swift-tools-version:6.1|' Package.swift - - name: Build and Test + xcodebuild test -scheme PowerSync-Package -destination "platform=macOS,arch=arm64,name=My Mac" + - name: Test on watchOS simulator run: | - swift build -Xswiftc -strict-concurrency=complete - swift test -Xswiftc -strict-concurrency=complete + xcodebuild test -scheme PowerSync-Package -destination "platform=watchOS Simulator,arch=arm64,name=Apple Watch Ultra 2 (49mm)" From aa5087f7ec2e7d63172f22f3210accb1ff263bb5 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 27 Oct 2025 13:52:48 +0100 Subject: [PATCH 05/14] Try initializing SQLite --- Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift b/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift index ddb1206..ad990f1 100644 --- a/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift +++ b/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift @@ -1,5 +1,6 @@ import Foundation import PowerSyncKotlin +import CSQLite final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol, // `PowerSyncKotlin.PowerSyncDatabase` cannot be marked as Sendable @@ -16,6 +17,11 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol, dbFilename: String, logger: DatabaseLogger ) { + let rc = sqlite3_initialize(); + if (rc != 0) { + fatalError("Call to sqlite3_initialize() failed with \(rc)") + } + let factory = sqlite3DatabaseFactory(initialStatements: []) kotlinDatabase = PowerSyncDatabase( factory: factory, From 19472cb529168bc17639d21d127493991e0bf648 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 28 Oct 2025 15:03:20 +0100 Subject: [PATCH 06/14] Explicitly pass threadsafe 2 --- Package.swift | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index ce28be9..f502a95 100644 --- a/Package.swift +++ b/Package.swift @@ -22,7 +22,22 @@ var conditionalDependencies: [Package.Dependency] = [ .package( url: "https://github.com/sbooth/CSQLite.git", from: "3.50.4", - traits: ["ENABLE_SESSION"] + traits: [ + .defaults, + // CSQLite uses THREADSAFE=0 by default, which breaks PowerSync because we're using SQLite on + // multiple threads (it can lead to race conditions when closing connecting sharing resources + // like shared memory, causing crashes). + // THREADSAFE=2 overrides the default, and is safe to use as long as a single SQLite connection + // is not shared between threads. + // TODO: Technically, we should not use .defaults because there's a logical conflict between + // the threadsafe options. Instead, we should spell out all defaults again and remove that + // thread-safety option. + // However, despite the docs explicitly saying something else, it looks like there's no way to + // disable default traits anyway (XCode compiles sqlite3.c with the default option even without + // .defaults being included here). + "THREADSAFE_2", + "ENABLE_SESSION" + ] ) ] var conditionalTargets: [Target] = [] From 4cfe611b76cde1317be2102d07d4786a2fe7dc92 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 28 Oct 2025 15:18:19 +0100 Subject: [PATCH 07/14] typo --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index f502a95..86b91d6 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ var conditionalDependencies: [Package.Dependency] = [ traits: [ .defaults, // CSQLite uses THREADSAFE=0 by default, which breaks PowerSync because we're using SQLite on - // multiple threads (it can lead to race conditions when closing connecting sharing resources + // multiple threads (it can lead to race conditions when closing connections sharing resources // like shared memory, causing crashes). // THREADSAFE=2 overrides the default, and is safe to use as long as a single SQLite connection // is not shared between threads. From 756dcd5ef013b1fccd42621d0d2557c72f69a26a Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Thu, 4 Dec 2025 17:20:28 +0100 Subject: [PATCH 08/14] Prepare to use our CSQLite fork --- Package.resolved | 15 +++------------ Package.swift | 33 +++++++-------------------------- 2 files changed, 10 insertions(+), 38 deletions(-) diff --git a/Package.resolved b/Package.resolved index d0dc9d8..06bbfdb 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,22 +1,13 @@ { - "originHash" : "82539474c4bcedf04818c668b504533c49309a0dd3669f4ec2fb8e77b64439b3", + "originHash" : "07cca32b599d2d8e93fb0f48a44643e0cac92225db615070dba76b849ec0ded7", "pins" : [ - { - "identity" : "csqlite", - "kind" : "remoteSourceControl", - "location" : "https://github.com/sbooth/CSQLite.git", - "state" : { - "revision" : "b1161e6c73fa68c25292f6bb697293d6c679f919", - "version" : "3.50.4" - } - }, { "identity" : "powersync-sqlite-core-swift", "kind" : "remoteSourceControl", "location" : "https://github.com/powersync-ja/powersync-sqlite-core-swift.git", "state" : { - "revision" : "9801f4aa0923c7f33fa479a01e643d00e7764f0b", - "version" : "0.4.8" + "revision" : "9743740980cd488a11f50cffe62ed34a9739a135", + "version" : "0.4.10" } } ], diff --git a/Package.swift b/Package.swift index 86b91d6..97986b4 100644 --- a/Package.swift +++ b/Package.swift @@ -18,28 +18,7 @@ let localCoreExtension: String? = nil // a binary target. // With a local SDK, we point to a `Package.swift` within the Kotlin SDK containing a target pointing // towards a local framework build -var conditionalDependencies: [Package.Dependency] = [ - .package( - url: "https://github.com/sbooth/CSQLite.git", - from: "3.50.4", - traits: [ - .defaults, - // CSQLite uses THREADSAFE=0 by default, which breaks PowerSync because we're using SQLite on - // multiple threads (it can lead to race conditions when closing connections sharing resources - // like shared memory, causing crashes). - // THREADSAFE=2 overrides the default, and is safe to use as long as a single SQLite connection - // is not shared between threads. - // TODO: Technically, we should not use .defaults because there's a logical conflict between - // the threadsafe options. Instead, we should spell out all defaults again and remove that - // thread-safety option. - // However, despite the docs explicitly saying something else, it looks like there's no way to - // disable default traits anyway (XCode compiles sqlite3.c with the default option even without - // .defaults being included here). - "THREADSAFE_2", - "ENABLE_SESSION" - ] - ) -] +var conditionalDependencies: [Package.Dependency] = [] var conditionalTargets: [Target] = [] var kotlinTargetDependency = Target.Dependency.target(name: "PowerSyncKotlin") @@ -53,8 +32,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.8.0/PowersyncKotlinRelease.zip", - checksum: "31ac7c5e11d747e11bceb0b34f30438d37033e700c621b0a468aa308d887587f" + url: "https://github.com/powersync-ja/powersync-kotlin/releases/download/v1.9.0/PowersyncKotlinRelease.zip", + checksum: "6d9847391ab2bbbca1f6a7abe163f0682ddca4a559ef5a1d2567b3e62e7d9979" )) } @@ -66,7 +45,7 @@ if let corePath = localCoreExtension { // Not using a local build, so download from releases conditionalDependencies.append(.package( url: "https://github.com/powersync-ja/powersync-sqlite-core-swift.git", - exact: "0.4.8" + exact: "0.4.10" )) } @@ -94,7 +73,9 @@ let package = Package( targets: ["PowerSync"] ) ], - dependencies: conditionalDependencies, + dependencies: conditionalDependencies + [ + .package(path: "/Users/simon/src/CSQLite") + ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products from dependencies. From 5b8dbaf59c8dc7f3c37c8b1558c7d246bc0561c9 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Thu, 4 Dec 2025 17:23:12 +0100 Subject: [PATCH 09/14] Test with Swift 5 --- .github/workflows/build_and_test.yaml | 24 +++++++++++++++----- Sources/PowerSync/Kotlin/KotlinAdapter.swift | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml index 9a8ff59..f13117d 100644 --- a/.github/workflows/build_and_test.yaml +++ b/.github/workflows/build_and_test.yaml @@ -14,13 +14,25 @@ jobs: uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: latest-stable - - - name: Test on iOS simulator + - name: Build and Test run: | xcodebuild test -scheme PowerSync-Package -destination "platform=iOS Simulator,name=iPhone 16" - - name: Test on macOS - run: | xcodebuild test -scheme PowerSync-Package -destination "platform=macOS,arch=arm64,name=My Mac" - - name: Test on watchOS simulator - run: | xcodebuild test -scheme PowerSync-Package -destination "platform=watchOS Simulator,arch=arm64,name=Apple Watch Ultra 2 (49mm)" + + buildSwift6: + name: Build and test with Swift 6 + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Set up XCode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + - name: Use Swift 6 + run: | + sed -i '' 's|^// swift-tools-version:.*$|// swift-tools-version:6.1|' Package.swift + - name: Build and Test + run: | + swift build -Xswiftc -strict-concurrency=complete + swift test -Xswiftc -strict-concurrency=complete diff --git a/Sources/PowerSync/Kotlin/KotlinAdapter.swift b/Sources/PowerSync/Kotlin/KotlinAdapter.swift index 2d73ab3..a294b81 100644 --- a/Sources/PowerSync/Kotlin/KotlinAdapter.swift +++ b/Sources/PowerSync/Kotlin/KotlinAdapter.swift @@ -50,7 +50,7 @@ enum KotlinAdapter { name: table.name, put: translateStatement(table.put), delete: translateStatement(table.delete), - clear: table.clear, + clear: table.clear ); } From c0eff8f7b54b33f9165e2a1db38d0de3dd2f1752 Mon Sep 17 00:00:00 2001 From: stevensJourney Date: Mon, 8 Dec 2025 11:28:14 +0200 Subject: [PATCH 10/14] use git dependency for csqlite --- Package.resolved | 11 ++++++++++- Package.swift | 33 ++++++++++++++++++--------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Package.resolved b/Package.resolved index 06bbfdb..9a37a96 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,6 +1,15 @@ { - "originHash" : "07cca32b599d2d8e93fb0f48a44643e0cac92225db615070dba76b849ec0ded7", + "originHash" : "72f93cb20dd4d81570efadb81f0559085b16ddcb46bd6f2de009a4ed98597f93", "pins" : [ + { + "identity" : "csqlite", + "kind" : "remoteSourceControl", + "location" : "git@github.com:powersync-ja/CSQLite.git", + "state" : { + "branch" : "init", + "revision" : "b77a2814107d919d75035a2b057305326bf13a1e" + } + }, { "identity" : "powersync-sqlite-core-swift", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index 97986b4..6cf25b7 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 6.1 +// swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -30,11 +30,13 @@ if let kotlinSdkPath = localKotlinSdkOverride { kotlinTargetDependency = .product(name: "PowerSyncKotlin", package: "PowerSyncKotlin") } else { // 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.9.0/PowersyncKotlinRelease.zip", - checksum: "6d9847391ab2bbbca1f6a7abe163f0682ddca4a559ef5a1d2567b3e62e7d9979" - )) + conditionalTargets.append( + .binaryTarget( + name: "PowerSyncKotlin", + url: + "https://github.com/powersync-ja/powersync-kotlin/releases/download/v1.9.0/PowersyncKotlinRelease.zip", + checksum: "6d9847391ab2bbbca1f6a7abe163f0682ddca4a559ef5a1d2567b3e62e7d9979" + )) } var corePackageName = "powersync-sqlite-core-swift" @@ -43,10 +45,11 @@ if let corePath = localCoreExtension { corePackageName = "powersync-sqlite-core" } else { // Not using a local build, so download from releases - conditionalDependencies.append(.package( - url: "https://github.com/powersync-ja/powersync-sqlite-core-swift.git", - exact: "0.4.10" - )) + conditionalDependencies.append( + .package( + url: "https://github.com/powersync-ja/powersync-sqlite-core-swift.git", + exact: "0.4.10" + )) } let package = Package( @@ -54,7 +57,7 @@ let package = Package( platforms: [ .iOS(.v15), .macOS(.v12), - .watchOS(.v9) + .watchOS(.v9), ], products: [ // Products define the executables and libraries a package produces, making them visible to other packages. @@ -71,10 +74,10 @@ let package = Package( // Dynamic linking is particularly important for XCode previews. type: .dynamic, targets: ["PowerSync"] - ) + ), ], dependencies: conditionalDependencies + [ - .package(path: "/Users/simon/src/CSQLite") + .package(url: "git@github.com:powersync-ja/CSQLite.git", revision: "init") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. @@ -84,12 +87,12 @@ let package = Package( dependencies: [ kotlinTargetDependency, .product(name: "PowerSyncSQLiteCore", package: corePackageName), - .product(name: "CSQLite", package: "CSQLite") + .product(name: "CSQLite", package: "CSQLite"), ] ), .testTarget( name: "PowerSyncTests", dependencies: ["PowerSync"] - ) + ), ] + conditionalTargets ) From c4997da9c7322034a0b8d904ab8d335d56148b9f Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 12 Dec 2025 11:15:08 +0100 Subject: [PATCH 11/14] Use stable CSQLite release --- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- Package.resolved | 7 +++---- Package.swift | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Demo/PowerSyncExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Demo/PowerSyncExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2aa1e82..e6ba700 100644 --- a/Demo/PowerSyncExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Demo/PowerSyncExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/powersync-ja/powersync-sqlite-core-swift.git", "state" : { - "revision" : "b2a81af14e9ad83393eb187bb02e62e6db8b5ad6", - "version" : "0.4.6" + "revision" : "9743740980cd488a11f50cffe62ed34a9739a135", + "version" : "0.4.10" } }, { diff --git a/Package.resolved b/Package.resolved index 9a37a96..1b561eb 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,13 +1,12 @@ { - "originHash" : "72f93cb20dd4d81570efadb81f0559085b16ddcb46bd6f2de009a4ed98597f93", "pins" : [ { "identity" : "csqlite", "kind" : "remoteSourceControl", "location" : "git@github.com:powersync-ja/CSQLite.git", "state" : { - "branch" : "init", - "revision" : "b77a2814107d919d75035a2b057305326bf13a1e" + "branch" : "3.51.1", + "revision" : "25f4a02fce2dcd588bad37ea6fc047c2bbe8ef5e" } }, { @@ -20,5 +19,5 @@ } } ], - "version" : 3 + "version" : 2 } diff --git a/Package.swift b/Package.swift index 6cf25b7..10dfd0f 100644 --- a/Package.swift +++ b/Package.swift @@ -77,7 +77,7 @@ let package = Package( ), ], dependencies: conditionalDependencies + [ - .package(url: "git@github.com:powersync-ja/CSQLite.git", revision: "init") + .package(url: "git@github.com:powersync-ja/CSQLite.git", revision: "3.51.1") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From 68c597f196e1d5d96dfb851a6d9072c9dedb7dde Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 12 Dec 2025 11:36:47 +0100 Subject: [PATCH 12/14] Use public git URI --- Package.resolved | 2 +- Package.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.resolved b/Package.resolved index 1b561eb..47fca67 100644 --- a/Package.resolved +++ b/Package.resolved @@ -3,7 +3,7 @@ { "identity" : "csqlite", "kind" : "remoteSourceControl", - "location" : "git@github.com:powersync-ja/CSQLite.git", + "location" : "https://github.com/powersync-ja/CSQLite.git", "state" : { "branch" : "3.51.1", "revision" : "25f4a02fce2dcd588bad37ea6fc047c2bbe8ef5e" diff --git a/Package.swift b/Package.swift index 10dfd0f..ee58fa4 100644 --- a/Package.swift +++ b/Package.swift @@ -77,7 +77,7 @@ let package = Package( ), ], dependencies: conditionalDependencies + [ - .package(url: "git@github.com:powersync-ja/CSQLite.git", revision: "3.51.1") + .package(url: "https://github.com/powersync-ja/CSQLite.git", revision: "3.51.1") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. From 78c680e5832ee4764b0eaaa2c42fc45d5ac3104c Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 12 Dec 2025 11:47:46 +0100 Subject: [PATCH 13/14] Update to Swift 6.1 --- .github/workflows/build_and_test.yaml | 17 ----------------- Package.swift | 2 +- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml index f13117d..0e97fad 100644 --- a/.github/workflows/build_and_test.yaml +++ b/.github/workflows/build_and_test.yaml @@ -19,20 +19,3 @@ jobs: xcodebuild test -scheme PowerSync-Package -destination "platform=iOS Simulator,name=iPhone 16" xcodebuild test -scheme PowerSync-Package -destination "platform=macOS,arch=arm64,name=My Mac" xcodebuild test -scheme PowerSync-Package -destination "platform=watchOS Simulator,arch=arm64,name=Apple Watch Ultra 2 (49mm)" - - buildSwift6: - name: Build and test with Swift 6 - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Set up XCode - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: latest-stable - - name: Use Swift 6 - run: | - sed -i '' 's|^// swift-tools-version:.*$|// swift-tools-version:6.1|' Package.swift - - name: Build and Test - run: | - swift build -Xswiftc -strict-concurrency=complete - swift test -Xswiftc -strict-concurrency=complete diff --git a/Package.swift b/Package.swift index ee58fa4..c77f30f 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.9 +// swift-tools-version: 6.1 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription From 7935ac070e6b840827f87c5544c105f4199ad1d6 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 12 Dec 2025 11:50:46 +0100 Subject: [PATCH 14/14] Add strict concurrency tests --- .github/workflows/build_and_test.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml index 0e97fad..31e2200 100644 --- a/.github/workflows/build_and_test.yaml +++ b/.github/workflows/build_and_test.yaml @@ -14,6 +14,12 @@ jobs: uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: latest-stable + + - name: Test with strict concurrency + run: | + swift build -Xswiftc -strict-concurrency=complete + swift test -Xswiftc -strict-concurrency=complete + - name: Build and Test run: | xcodebuild test -scheme PowerSync-Package -destination "platform=iOS Simulator,name=iPhone 16"