Skip to content

Commit dc1a76f

Browse files
chore: improve demo upload data to handle fatal errors (#10)
1 parent 7d46dc9 commit dc1a76f

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

Demo/PowerSyncExample/PowerSync/SupabaseConnector.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,45 @@ import Supabase
44
import PowerSync
55
import AnyCodable
66

7+
private struct PostgresFatalCodes {
8+
/// Postgres Response codes that we cannot recover from by retrying.
9+
static let fatalResponseCodes: [String] = [
10+
// Class 22 — Data Exception
11+
// Examples include data type mismatch.
12+
"22...",
13+
// Class 23 — Integrity Constraint Violation.
14+
// Examples include NOT NULL, FOREIGN KEY and UNIQUE violations.
15+
"23...",
16+
// INSUFFICIENT PRIVILEGE - typically a row-level security violation
17+
"42501"
18+
]
19+
20+
static func isFatalError(_ code: String) -> Bool {
21+
return fatalResponseCodes.contains { pattern in
22+
code.range(of: pattern, options: [.regularExpression]) != nil
23+
}
24+
}
25+
26+
static func extractErrorCode(from error: any Error) -> String? {
27+
// Look for code: Optional("XXXXX") pattern
28+
let errorString = String(describing: error)
29+
if let range = errorString.range(of: "code: Optional\\(\"([^\"]+)\"\\)", options: .regularExpression),
30+
let codeRange = errorString[range].range(of: "\"([^\"]+)\"", options: .regularExpression) {
31+
// Extract just the code from within the quotes
32+
let code = errorString[codeRange].dropFirst().dropLast()
33+
return String(code)
34+
}
35+
return nil
36+
}
37+
}
38+
39+
740
@Observable
841
class SupabaseConnector: PowerSyncBackendConnector {
942
let powerSyncEndpoint: String = Secrets.powerSyncEndpoint
1043
let client: SupabaseClient = SupabaseClient(supabaseURL: Secrets.supabaseURL, supabaseKey: Secrets.supabaseAnonKey)
1144
var session: Session?
45+
private var errorCode: String?
1246

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

78112
} catch {
113+
if let errorCode = PostgresFatalCodes.extractErrorCode(from: error),
114+
PostgresFatalCodes.isFatalError(errorCode) {
115+
print("Data upload error: \(error)")
116+
print("Discarding entry: \(lastEntry!)")
117+
_ = try await transaction.complete.invoke(p1: nil)
118+
return
119+
}
120+
79121
print("Data upload error - retrying last entry: \(lastEntry!), \(error)")
80122
throw error
81123
}

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ This SDK is currently in a beta release it is suitable for production use, given
2222

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

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

2727
## Installation
2828

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

6161
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.
62-

0 commit comments

Comments
 (0)