Skip to content
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
42 changes: 42 additions & 0 deletions Demo/PowerSyncExample/PowerSync/SupabaseConnector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,45 @@ import Supabase
import PowerSync
import AnyCodable

private struct PostgresFatalCodes {
/// Postgres Response codes that we cannot recover from by retrying.
static let fatalResponseCodes: [String] = [
// Class 22 — Data Exception
// Examples include data type mismatch.
"22...",
// Class 23 — Integrity Constraint Violation.
// Examples include NOT NULL, FOREIGN KEY and UNIQUE violations.
"23...",
// INSUFFICIENT PRIVILEGE - typically a row-level security violation
"42501"
]

static func isFatalError(_ code: String) -> Bool {
return fatalResponseCodes.contains { pattern in
code.range(of: pattern, options: [.regularExpression]) != nil
}
}

static func extractErrorCode(from error: any Error) -> String? {
// Look for code: Optional("XXXXX") pattern
let errorString = String(describing: error)
if let range = errorString.range(of: "code: Optional\\(\"([^\"]+)\"\\)", options: .regularExpression),
let codeRange = errorString[range].range(of: "\"([^\"]+)\"", options: .regularExpression) {
// Extract just the code from within the quotes
let code = errorString[codeRange].dropFirst().dropLast()
return String(code)
}
return nil
}
}


@Observable
class SupabaseConnector: PowerSyncBackendConnector {
let powerSyncEndpoint: String = Secrets.powerSyncEndpoint
let client: SupabaseClient = SupabaseClient(supabaseURL: Secrets.supabaseURL, supabaseKey: Secrets.supabaseAnonKey)
var session: Session?
private var errorCode: String?

@ObservationIgnored
private var observeAuthStateChangesTask: Task<Void, Error>?
Expand Down Expand Up @@ -76,6 +110,14 @@ class SupabaseConnector: PowerSyncBackendConnector {
_ = try await transaction.complete.invoke(p1: nil)

} catch {
if let errorCode = PostgresFatalCodes.extractErrorCode(from: error),
PostgresFatalCodes.isFatalError(errorCode) {
print("Data upload error: \(error)")
print("Discarding entry: \(lastEntry!)")
_ = try await transaction.complete.invoke(p1: nil)
return
}

print("Data upload error - retrying last entry: \(lastEntry!), \(error)")
throw error
}
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ This SDK is currently in a beta release it is suitable for production use, given

The easiest way to test the PowerSync Swift SDK is to run our demo application.

- [Demo/PowerSyncExample](./Demo/PowerSyncExample/README.md): A simple to-do list application demonstrating the use of the PowerSync Swift SDK using a Supabase connector.
- [Demo/PowerSyncExample](./Demo/README.md): A simple to-do list application demonstrating the use of the PowerSync Swift SDK using a Supabase connector.

## Installation

Expand Down Expand Up @@ -59,4 +59,3 @@ The PowerSync Swift SDK currently makes use of the [PowerSync Kotlin Multiplatfo
## Migration from Alpha to Beta

See these [developer notes](https://docs.powersync.com/client-sdk-references/swift#migrating-from-the-alpha-to-the-beta-sdk) if you are migrating from the alpha to the beta version of the Swift SDK.