1+ import AnyCodable
12import Auth
2- import SwiftUI
3- import Supabase
43import PowerSync
5- import AnyCodable
4+ import Supabase
5+ import SwiftUI
66
7- private struct PostgresFatalCodes {
7+ private enum PostgresFatalCodes {
88 /// Postgres Response codes that we cannot recover from by retrying.
99 static let fatalResponseCodes : [ String ] = [
1010 // Class 22 — Data Exception
@@ -14,7 +14,7 @@ private struct PostgresFatalCodes {
1414 // Examples include NOT NULL, FOREIGN KEY and UNIQUE violations.
1515 " 23... " ,
1616 // INSUFFICIENT PRIVILEGE - typically a row-level security violation
17- " 42501 "
17+ " 42501 " ,
1818 ]
1919
2020 static func isFatalError( _ code: String ) -> Bool {
@@ -27,20 +27,20 @@ private struct PostgresFatalCodes {
2727 // Look for code: Optional("XXXXX") pattern
2828 let errorString = String ( describing: error)
2929 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- }
30+ let codeRange = errorString [ range] . range ( of: " \" ([^ \" ]+) \" " , options: . regularExpression)
31+ {
32+ // Extract just the code from within the quotes
33+ let code = errorString [ codeRange] . dropFirst ( ) . dropLast ( )
34+ return String ( code)
35+ }
3536 return nil
3637 }
3738}
3839
39-
4040@Observable
4141class SupabaseConnector : PowerSyncBackendConnector {
4242 let powerSyncEndpoint : String = Secrets . powerSyncEndpoint
43- let client : SupabaseClient = SupabaseClient ( supabaseURL: Secrets . supabaseURL, supabaseKey: Secrets . supabaseAnonKey)
43+ let client : SupabaseClient = . init ( supabaseURL: Secrets . supabaseURL, supabaseKey: Secrets . supabaseAnonKey)
4444 var session : Session ?
4545 private var errorCode : String ?
4646
@@ -68,20 +68,23 @@ class SupabaseConnector: PowerSyncBackendConnector {
6868 return id. uuidString. lowercased ( )
6969 }
7070
71+ func getStorageBucket( ) -> StorageFileApi {
72+ return client. storage. from ( Secrets . supabaseStorageBucket)
73+ }
74+
7175 override func fetchCredentials( ) async throws -> PowerSyncCredentials ? {
7276 session = try await client. auth. session
7377
74- if ( self . session == nil ) {
78+ if session == nil {
7579 throw AuthError . sessionMissing
7680 }
7781
7882 let token = session!. accessToken
7983
80- return PowerSyncCredentials ( endpoint: self . powerSyncEndpoint, token: token)
84+ return PowerSyncCredentials ( endpoint: powerSyncEndpoint, token: token)
8185 }
8286
8387 override func uploadData( database: PowerSyncDatabaseProtocol ) async throws {
84-
8588 guard let transaction = try await database. getNextCrudTransaction ( ) else { return }
8689
8790 var lastEntry : CrudEntry ?
@@ -96,39 +99,36 @@ class SupabaseConnector: PowerSyncBackendConnector {
9699 case . put:
97100 var data : [ String : AnyCodable ] = entry. opData? . mapValues { AnyCodable ( $0) } ?? [ : ]
98101 data [ " id " ] = AnyCodable ( entry. id)
99- try await table. upsert ( data) . execute ( ) ;
102+ try await table. upsert ( data) . execute ( )
100103 case . patch:
101104 guard let opData = entry. opData else { continue }
102105 let encodableData = opData. mapValues { AnyCodable ( $0) }
103106 try await table. update ( encodableData) . eq ( " id " , value: entry. id) . execute ( )
104107 case . delete:
105- try await table. delete ( ) . eq ( " id " , value: entry. id) . execute ( )
108+ try await table. delete ( ) . eq ( " id " , value: entry. id) . execute ( )
106109 }
107110 }
108111
109112 _ = try await transaction. complete. invoke ( p1: nil )
110113
111114 } catch {
112115 if let errorCode = PostgresFatalCodes . extractErrorCode ( from: error) ,
113- PostgresFatalCodes . isFatalError ( errorCode) {
114- /// Instead of blocking the queue with these errors,
115- /// discard the (rest of the) transaction.
116- ///
117- /// Note that these errors typically indicate a bug in the application.
118- /// If protecting against data loss is important, save the failing records
119- /// elsewhere instead of discarding, and/or notify the user.
120- print ( " Data upload error: \( error) " )
121- print ( " Discarding entry: \( lastEntry!) " )
122- _ = try await transaction. complete. invoke ( p1: nil )
123- return
124- }
116+ PostgresFatalCodes . isFatalError ( errorCode)
117+ {
118+ /// Instead of blocking the queue with these errors,
119+ /// discard the (rest of the) transaction.
120+ ///
121+ /// Note that these errors typically indicate a bug in the application.
122+ /// If protecting against data loss is important, save the failing records
123+ /// elsewhere instead of discarding, and/or notify the user.
124+ print ( " Data upload error: \( error) " )
125+ print ( " Discarding entry: \( lastEntry!) " )
126+ _ = try await transaction. complete. invoke ( p1: nil )
127+ return
128+ }
125129
126130 print ( " Data upload error - retrying last entry: \( lastEntry!) , \( error) " )
127131 throw error
128132 }
129133 }
130-
131- deinit {
132- observeAuthStateChangesTask? . cancel ( )
133- }
134134}
0 commit comments