From c4e021cbf1a872ee8952d6f70c7a989929593333 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Mon, 10 Feb 2025 16:49:52 +0200 Subject: [PATCH 1/2] chore: improve error handling for kotlin errors --- CHANGELOG.md | 7 ++++ .../xcshareddata/swiftpm/Package.resolved | 4 +- .../PowerSync/SupabaseConnector.swift | 6 +-- Package.resolved | 4 +- Package.swift | 2 +- .../Kotlin/KotlinPowerSyncDatabaseImpl.swift | 4 +- Sources/PowerSync/Kotlin/SqlCursor.swift | 40 +++++++++---------- .../PowerSyncBackendConnectorAdapter.swift | 24 ++++++++++- 8 files changed, 59 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcba8f6..0b6ea5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog +## 1.0.0-Beta.5 + +* Implement improvements to errors originating in Kotlin so that they can be handled in Swift +* Improve `__fetchCredentials`to log the error but not cause an app crash on error + + ## 1.0.0-Beta.4 + * Allow cursor to use column name to get value by including the following functions that accept a column name parameter: `getBoolean`,`getBooleanOptional`,`getString`,`getStringOptional`, `getLong`,`getLongOptional`, `getDouble`,`getDoubleOptional` * BREAKING CHANGE: This should not affect anyone but made `KotlinPowerSyncCredentials`, `KotlinPowerSyncDatabase` and `KotlinPowerSyncBackendConnector` private as these should never have been public. diff --git a/Demo/PowerSyncExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Demo/PowerSyncExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index cf201e7..74a5351 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-kotlin.git", "state" : { - "revision" : "7cd47ffc9dbec8fae4f9e067945ef2279015a90d", - "version" : "1.0.0-BETA20.0" + "revision" : "61d195816585f30260181dcbd157bf1660c9ac4e", + "version" : "1.0.0-BETA22.0" } }, { diff --git a/Demo/PowerSyncExample/PowerSync/SupabaseConnector.swift b/Demo/PowerSyncExample/PowerSync/SupabaseConnector.swift index 8f228ea..cd048a6 100644 --- a/Demo/PowerSyncExample/PowerSync/SupabaseConnector.swift +++ b/Demo/PowerSyncExample/PowerSync/SupabaseConnector.swift @@ -70,13 +70,13 @@ class SupabaseConnector: PowerSyncBackendConnector { override func fetchCredentials() async throws -> PowerSyncCredentials? { session = try await client.auth.session - + if (self.session == nil) { throw AuthError.sessionMissing } - + let token = session!.accessToken - + // userId is for debugging purposes only return PowerSyncCredentials(endpoint: self.powerSyncEndpoint, token: token, userId: currentUserID) } diff --git a/Package.resolved b/Package.resolved index 599b4f8..a28b3cc 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/powersync-ja/powersync-kotlin.git", "state" : { - "revision" : "7cd47ffc9dbec8fae4f9e067945ef2279015a90d", - "version" : "1.0.0-BETA20.0" + "revision" : "61d195816585f30260181dcbd157bf1660c9ac4e", + "version" : "1.0.0-BETA22.0" } }, { diff --git a/Package.swift b/Package.swift index e56a71a..9643b93 100644 --- a/Package.swift +++ b/Package.swift @@ -16,7 +16,7 @@ let package = Package( targets: ["PowerSync"]), ], dependencies: [ - .package(url: "https://github.com/powersync-ja/powersync-kotlin.git", exact: "1.0.0-BETA20.0"), + .package(url: "https://github.com/powersync-ja/powersync-kotlin.git", exact: "1.0.0-BETA22.0"), .package(url: "https://github.com/powersync-ja/powersync-sqlite-core-swift.git", "0.3.9"..<"0.4.0") ], targets: [ diff --git a/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift b/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift index ad13987..e06c998 100644 --- a/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift +++ b/Sources/PowerSync/Kotlin/KotlinPowerSyncDatabaseImpl.swift @@ -153,7 +153,7 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol { ) -> AsyncStream<[RowType]> { AsyncStream { continuation in Task { - for await values in self.kotlinDatabase.watch( + for await values in try self.kotlinDatabase.watch( sql: sql, parameters: parameters, mapper: mapper @@ -172,7 +172,7 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol { ) -> AsyncStream<[RowType]> { AsyncStream { continuation in Task { - for await values in self.kotlinDatabase.watch( + for await values in try self.kotlinDatabase.watch( sql: sql, parameters: parameters, mapper: { cursor in diff --git a/Sources/PowerSync/Kotlin/SqlCursor.swift b/Sources/PowerSync/Kotlin/SqlCursor.swift index 5ed1f1f..538142b 100644 --- a/Sources/PowerSync/Kotlin/SqlCursor.swift +++ b/Sources/PowerSync/Kotlin/SqlCursor.swift @@ -8,60 +8,60 @@ extension SqlCursor { } return columnIndex } - - private func getValue(name: String, getter: (Int32) -> T?) throws -> T { + + private func getValue(name: String, getter: (Int32) throws -> T?) throws -> T { let columnIndex = try getColumnIndex(name: name) - guard let value = getter(columnIndex) else { + guard let value = try getter(columnIndex) else { throw SqlCursorError.nullValueFound(name) } return value } - - private func getOptionalValue(name: String, getter: (String) -> T?) throws -> T? { + + private func getOptionalValue(name: String, getter: (String) throws -> T?) throws -> T? { _ = try getColumnIndex(name: name) - return getter(name) + return try getter(name) } - + public func getBoolean(name: String) throws -> Bool { try getValue(name: name) { getBoolean(index: $0)?.boolValue } } - + public func getDouble(name: String) throws -> Double { try getValue(name: name) { getDouble(index: $0)?.doubleValue } } - + public func getLong(name: String) throws -> Int { try getValue(name: name) { getLong(index: $0)?.intValue } } - + public func getString(name: String) throws -> String { try getValue(name: name) { getString(index: $0) } } - + public func getBooleanOptional(name: String) throws -> Bool? { - try getOptionalValue(name: name) { getBooleanOptional(name: $0)?.boolValue } + try getOptionalValue(name: name) { try getBooleanOptional(name: $0)?.boolValue } } - + public func getDoubleOptional(name: String) throws -> Double? { - try getOptionalValue(name: name) { getDoubleOptional(name: $0)?.doubleValue } + try getOptionalValue(name: name) { try getDoubleOptional(name: $0)?.doubleValue } } - + public func getLongOptional(name: String) throws -> Int? { - try getOptionalValue(name: name) { getLongOptional(name: $0)?.intValue } + try getOptionalValue(name: name) { try getLongOptional(name: $0)?.intValue } } - + public func getStringOptional(name: String) throws -> String? { - try getOptionalValue(name: name) { PowerSyncKotlin.SqlCursorKt.getStringOptional(self, name: $0) } + try getOptionalValue(name: name) { try PowerSyncKotlin.SqlCursorKt.getStringOptional(self, name: $0) } } } enum SqlCursorError: Error { case nullValue(message: String) - + static func columnNotFound(_ name: String) -> SqlCursorError { .nullValue(message: "Column '\(name)' not found") } - + static func nullValueFound(_ name: String) -> SqlCursorError { .nullValue(message: "Null value found for column \(name)") } diff --git a/Sources/PowerSync/PowerSyncBackendConnectorAdapter.swift b/Sources/PowerSync/PowerSyncBackendConnectorAdapter.swift index df2ce63..8d41820 100644 --- a/Sources/PowerSync/PowerSyncBackendConnectorAdapter.swift +++ b/Sources/PowerSync/PowerSyncBackendConnectorAdapter.swift @@ -1,3 +1,5 @@ +import OSLog + class PowerSyncBackendConnectorAdapter: KotlinPowerSyncBackendConnector { let swiftBackendConnector: PowerSyncBackendConnector @@ -8,11 +10,29 @@ class PowerSyncBackendConnectorAdapter: KotlinPowerSyncBackendConnector { } override func __fetchCredentials() async throws -> KotlinPowerSyncCredentials? { - try await swiftBackendConnector.fetchCredentials()?.kotlinCredentials + do { + let result = try await swiftBackendConnector.fetchCredentials() + return result?.kotlinCredentials + } catch { + if #available(iOS 14.0, *) { + Logger().error("Failed to fetch credentials: \(error.localizedDescription)") + } else { + print("Failed to fetch credentials: \(error.localizedDescription)") + } + return nil + } } override func __uploadData(database: KotlinPowerSyncDatabase) async throws { let swiftDatabase = KotlinPowerSyncDatabaseImpl(kotlinDatabase: database) - try await swiftBackendConnector.uploadData(database: swiftDatabase) + do { + return try await swiftBackendConnector.uploadData(database: swiftDatabase) + } catch { + if #available(iOS 14.0, *) { + Logger().error("Failed to upload data: \(error)") + } else { + print("Failed to upload data: \(error)") + } + } } } From 6e285421aa3924035720460c320565ff1bc06bdd Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Mon, 10 Feb 2025 16:58:48 +0200 Subject: [PATCH 2/2] chore: add red dot --- Sources/PowerSync/PowerSyncBackendConnectorAdapter.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/PowerSync/PowerSyncBackendConnectorAdapter.swift b/Sources/PowerSync/PowerSyncBackendConnectorAdapter.swift index 8d41820..158c665 100644 --- a/Sources/PowerSync/PowerSyncBackendConnectorAdapter.swift +++ b/Sources/PowerSync/PowerSyncBackendConnectorAdapter.swift @@ -15,9 +15,9 @@ class PowerSyncBackendConnectorAdapter: KotlinPowerSyncBackendConnector { return result?.kotlinCredentials } catch { if #available(iOS 14.0, *) { - Logger().error("Failed to fetch credentials: \(error.localizedDescription)") + Logger().error("🔴 Failed to fetch credentials: \(error.localizedDescription)") } else { - print("Failed to fetch credentials: \(error.localizedDescription)") + print("🔴 Failed to fetch credentials: \(error.localizedDescription)") } return nil } @@ -29,9 +29,9 @@ class PowerSyncBackendConnectorAdapter: KotlinPowerSyncBackendConnector { return try await swiftBackendConnector.uploadData(database: swiftDatabase) } catch { if #available(iOS 14.0, *) { - Logger().error("Failed to upload data: \(error)") + Logger().error("🔴 Failed to upload data: \(error)") } else { - print("Failed to upload data: \(error)") + print("🔴 Failed to upload data: \(error)") } } }