Skip to content

Commit 7591c29

Browse files
DominicGBauerDominicGBauer
and
DominicGBauer
authored
feat: implement native connector (#2)
* feat: implement native connector * fix: failing test --------- Co-authored-by: DominicGBauer <[email protected]>
1 parent db11a7d commit 7591c29

File tree

11 files changed

+115
-48
lines changed

11 files changed

+115
-48
lines changed

Demo/PowerSyncExample.xcodeproj/project.pbxproj

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
6A7315882B9854220004CB17 /* PowerSyncExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7315872B9854220004CB17 /* PowerSyncExampleApp.swift */; };
1515
6A73158C2B9854240004CB17 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A73158B2B9854240004CB17 /* Assets.xcassets */; };
1616
6A73158F2B9854240004CB17 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A73158E2B9854240004CB17 /* Preview Assets.xcassets */; };
17-
6A7315BB2B98BDD30004CB17 /* PowerSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7315BA2B98BDD30004CB17 /* PowerSyncManager.swift */; };
17+
6A7315BB2B98BDD30004CB17 /* SystemManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7315BA2B98BDD30004CB17 /* SystemManager.swift */; };
1818
6A9668FE2B9EE4FE00B05DCF /* Auth in Frameworks */ = {isa = PBXBuildFile; productRef = 6A9668FD2B9EE4FE00B05DCF /* Auth */; };
1919
6A9669002B9EE4FE00B05DCF /* PostgREST in Frameworks */ = {isa = PBXBuildFile; productRef = 6A9668FF2B9EE4FE00B05DCF /* PostgREST */; };
2020
6A9669022B9EE69500B05DCF /* Supabase in Frameworks */ = {isa = PBXBuildFile; productRef = 6A9669012B9EE69500B05DCF /* Supabase */; };
@@ -64,7 +64,7 @@
6464
6A7315872B9854220004CB17 /* PowerSyncExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowerSyncExampleApp.swift; sourceTree = "<group>"; };
6565
6A73158B2B9854240004CB17 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6666
6A73158E2B9854240004CB17 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
67-
6A7315BA2B98BDD30004CB17 /* PowerSyncManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowerSyncManager.swift; sourceTree = "<group>"; };
67+
6A7315BA2B98BDD30004CB17 /* SystemManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemManager.swift; sourceTree = "<group>"; };
6868
6A9669032B9EE6FA00B05DCF /* SignInScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInScreen.swift; sourceTree = "<group>"; };
6969
6ABD78662B9F2B4800558A41 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = "<group>"; };
7070
6ABD786A2B9F2C1500558A41 /* TodoListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodoListView.swift; sourceTree = "<group>"; };
@@ -218,7 +218,7 @@
218218
B65C4D6F2C60D58500176007 /* PowerSync */ = {
219219
isa = PBXGroup;
220220
children = (
221-
6A7315BA2B98BDD30004CB17 /* PowerSyncManager.swift */,
221+
6A7315BA2B98BDD30004CB17 /* SystemManager.swift */,
222222
6A4AD3842B9EE763005CBFD4 /* SupabaseConnector.swift */,
223223
6ABD78772B9F2D2800558A41 /* Schema.swift */,
224224
B66658642C62314B00159A81 /* Lists.swift */,
@@ -567,7 +567,7 @@
567567
B66658632C621CA700159A81 /* AddTodoListView.swift in Sources */,
568568
B666585D2C620E9E00159A81 /* WifiIcon.swift in Sources */,
569569
6A9669042B9EE6FA00B05DCF /* SignInScreen.swift in Sources */,
570-
6A7315BB2B98BDD30004CB17 /* PowerSyncManager.swift in Sources */,
570+
6A7315BB2B98BDD30004CB17 /* SystemManager.swift in Sources */,
571571
);
572572
runOnlyForDeploymentPostprocessing = 0;
573573
};

Demo/PowerSyncExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

+1-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"originHash" : "5d7fb7f47b01e814cbc6b4a65dfe62c7af5a96a435a0288b747750c370fcd28a",
2+
"originHash" : "25b8cd5d97789d7e497d6a5e0b04419a426018d83f0e80ab6817b213aa976748",
33
"pins" : [
44
{
55
"identity" : "anycodable",
@@ -10,15 +10,6 @@
1010
"version" : "0.6.7"
1111
}
1212
},
13-
{
14-
"identity" : "powersync-kotlin",
15-
"kind" : "remoteSourceControl",
16-
"location" : "https://github.com/powersync-ja/powersync-kotlin.git",
17-
"state" : {
18-
"revision" : "4186fa9a2004a4bc85a22c3f37bce4f3ebd4ff81",
19-
"version" : "1.0.0-BETA5.0"
20-
}
21-
},
2213
{
2314
"identity" : "powersync-sqlite-core-swift",
2415
"kind" : "remoteSourceControl",

Demo/PowerSyncExample/PowerSync/SupabaseConnector.swift

+2-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import Auth
22
import SwiftUI
33
import Supabase
44
import PowerSyncSwift
5-
import PowerSync
65
import AnyCodable
76

87
@Observable
@@ -16,7 +15,6 @@ class SupabaseConnector: PowerSyncBackendConnector {
1615

1716
override init() {
1817
super.init()
19-
2018
observeAuthStateChangesTask = Task { [weak self] in
2119
guard let self = self else { return }
2220

@@ -49,7 +47,7 @@ class SupabaseConnector: PowerSyncBackendConnector {
4947
return PowerSyncCredentials(endpoint: self.powerSyncEndpoint, token: token, userId: currentUserID)
5048
}
5149

52-
override func uploadData(database: PowerSyncDatabase) async throws {
50+
override func uploadData(database: PowerSyncDatabaseProtocol) async throws {
5351

5452
guard let transaction = try await database.getNextCrudTransaction() else { return }
5553

@@ -75,7 +73,7 @@ class SupabaseConnector: PowerSyncBackendConnector {
7573
}
7674
}
7775

78-
try await transaction.complete.invoke(p1: nil)
76+
_ = try await transaction.complete.invoke(p1: nil)
7977

8078
} catch {
8179
print("Data upload error - retrying last entry: \(lastEntry!), \(error)")

Package.resolved

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"kind" : "remoteSourceControl",
66
"location" : "https://github.com/powersync-ja/powersync-kotlin.git",
77
"state" : {
8-
"revision" : "4186fa9a2004a4bc85a22c3f37bce4f3ebd4ff81",
9-
"version" : "1.0.0-BETA5.0"
8+
"revision" : "7fb870f4530e5629b11f1a9b079644b200385985",
9+
"version" : "1.0.0-BETA6.0"
1010
}
1111
},
1212
{

Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ let package = Package(
1717
targets: ["PowerSyncSwift"]),
1818
],
1919
dependencies: [
20-
.package(url: "https://github.com/powersync-ja/powersync-kotlin.git", exact: "1.0.0-BETA5.0"),
20+
.package(url: "https://github.com/powersync-ja/powersync-kotlin.git", exact: "1.0.0-BETA6.0"),
2121
.package(url: "https://github.com/powersync-ja/powersync-sqlite-core-swift.git", "0.3.1"..<"0.4.0"),
2222
],
2323
targets: [

Sources/PowerSyncSwift/Kotlin/KotlinPowerSyncDatabaseImpl.swift

+30-24
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,30 @@ import Foundation
22
import PowerSync
33

44
final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
5-
private let kmpDatabase: PowerSync.PowerSyncDatabase
5+
private let kotlinDatabase: PowerSync.PowerSyncDatabase
66

77
var currentStatus: SyncStatus {
8-
get { kmpDatabase.currentStatus }
8+
get { kotlinDatabase.currentStatus }
99
}
1010

1111
init(
1212
schema: Schema,
1313
dbFilename: String
1414
) {
1515
let factory = PowerSync.DatabaseDriverFactory()
16-
self.kmpDatabase = PowerSyncDatabase(
16+
self.kotlinDatabase = PowerSyncDatabase(
1717
factory: factory,
1818
schema: KotlinAdapter.Schema.toKotlin(schema),
1919
dbFilename: dbFilename
2020
)
2121
}
22-
22+
23+
init(kotlinDatabase: KotlinPowerSyncDatabase) {
24+
self.kotlinDatabase = kotlinDatabase
25+
}
26+
2327
func waitForFirstSync() async throws {
24-
try await kmpDatabase.waitForFirstSync()
28+
try await kotlinDatabase.waitForFirstSync()
2529
}
2630

2731
func connect(
@@ -30,44 +34,46 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
3034
retryDelayMs: Int64 = 5000,
3135
params: [String: JsonParam?] = [:]
3236
) async throws {
33-
try await kmpDatabase.connect(
34-
connector: connector,
37+
let connectorProxy = PowerSyncBackendConnectorAdapter(swiftBackendConnector: connector)
38+
39+
try await kotlinDatabase.connect(
40+
connector: connectorProxy,
3541
crudThrottleMs: crudThrottleMs,
3642
retryDelayMs: retryDelayMs,
3743
params: params
3844
)
3945
}
4046

4147
func getCrudBatch(limit: Int32 = 100) async throws -> CrudBatch? {
42-
try await kmpDatabase.getCrudBatch(limit: limit)
48+
try await kotlinDatabase.getCrudBatch(limit: limit)
4349
}
4450

4551
func getNextCrudTransaction() async throws -> CrudTransaction? {
46-
try await kmpDatabase.getNextCrudTransaction()
52+
try await kotlinDatabase.getNextCrudTransaction()
4753
}
4854

4955
func getPowerSyncVersion() async throws -> String {
50-
try await kmpDatabase.getPowerSyncVersion()
56+
try await kotlinDatabase.getPowerSyncVersion()
5157
}
5258

5359
func disconnect() async throws {
54-
try await kmpDatabase.disconnect()
60+
try await kotlinDatabase.disconnect()
5561
}
5662

5763
func disconnectAndClear(clearLocal: Bool = true) async throws {
58-
try await kmpDatabase.disconnectAndClear(clearLocal: clearLocal)
64+
try await kotlinDatabase.disconnectAndClear(clearLocal: clearLocal)
5965
}
6066

6167
func execute(sql: String, parameters: [Any]?) async throws -> Int64 {
62-
Int64(truncating: try await kmpDatabase.execute(sql: sql, parameters: parameters))
68+
Int64(truncating: try await kotlinDatabase.execute(sql: sql, parameters: parameters))
6369
}
6470

6571
func get<RowType>(
6672
sql: String,
6773
parameters: [Any]?,
6874
mapper: @escaping (SqlCursor) -> RowType
6975
) async throws -> RowType {
70-
try await kmpDatabase.get(
76+
try await kotlinDatabase.get(
7177
sql: sql,
7278
parameters: parameters,
7379
mapper: mapper
@@ -79,7 +85,7 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
7985
parameters: [Any]?,
8086
mapper: @escaping (SqlCursor) -> RowType
8187
) async throws -> [RowType] {
82-
try await kmpDatabase.getAll(
88+
try await kotlinDatabase.getAll(
8389
sql: sql,
8490
parameters: parameters,
8591
mapper: mapper
@@ -91,7 +97,7 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
9197
parameters: [Any]?,
9298
mapper: @escaping (SqlCursor) -> RowType
9399
) async throws -> RowType? {
94-
try await kmpDatabase.getOptional(
100+
try await kotlinDatabase.getOptional(
95101
sql: sql,
96102
parameters: parameters,
97103
mapper: mapper
@@ -105,7 +111,7 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
105111
) -> AsyncStream<[RowType]> {
106112
AsyncStream { continuation in
107113
Task {
108-
for await values in self.kmpDatabase.watch(
114+
for await values in self.kotlinDatabase.watch(
109115
sql: sql,
110116
parameters: parameters,
111117
mapper: mapper
@@ -118,29 +124,29 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
118124
}
119125

120126
func writeTransaction<R>(callback: @escaping (any PowerSyncTransactionProtocol) async throws -> R) async throws -> R {
121-
let wrappedCallback = SuspendTaskWrapper { [kmpDatabase] in
127+
let wrappedCallback = SuspendTaskWrapper { [kotlinDatabase] in
122128
// Create a wrapper that converts the KMP transaction to our Swift protocol
123-
if let kmpTransaction = kmpDatabase as? PowerSyncTransactionProtocol {
129+
if let kmpTransaction = kotlinDatabase as? PowerSyncTransactionProtocol {
124130
return try await callback(kmpTransaction)
125131
} else {
126132
throw PowerSyncError.invalidTransaction
127133
}
128134
}
129135

130-
return try await kmpDatabase.writeTransaction(callback: wrappedCallback) as! R
136+
return try await kotlinDatabase.writeTransaction(callback: wrappedCallback) as! R
131137
}
132138

133139
func readTransaction<R>(callback: @escaping (any PowerSyncTransactionProtocol) async throws -> R) async throws -> R {
134-
let wrappedCallback = SuspendTaskWrapper { [kmpDatabase] in
140+
let wrappedCallback = SuspendTaskWrapper { [kotlinDatabase] in
135141
// Create a wrapper that converts the KMP transaction to our Swift protocol
136-
if let kmpTransaction = kmpDatabase as? PowerSyncTransactionProtocol {
142+
if let kmpTransaction = kotlinDatabase as? PowerSyncTransactionProtocol {
137143
return try await callback(kmpTransaction)
138144
} else {
139145
throw PowerSyncError.invalidTransaction
140146
}
141147
}
142148

143-
return try await kmpDatabase.readTransaction(callback: wrappedCallback) as! R
149+
return try await kotlinDatabase.readTransaction(callback: wrappedCallback) as! R
144150
}
145151
}
146152

@@ -156,7 +162,7 @@ class SuspendTaskWrapper: KotlinSuspendFunction1 {
156162
}
157163

158164
@MainActor
159-
func invoke(p1: Any?, completionHandler: @escaping (Any?, Error?) -> Void) {
165+
func __invoke(p1: Any?, completionHandler: @escaping (Any?, Error?) -> Void) {
160166
Task {
161167
do {
162168
let result = try await self.handle()
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import PowerSync
22

3-
public typealias PowerSyncBackendConnector = PowerSync.PowerSyncBackendConnector
3+
public typealias KotlinPowerSyncBackendConnector = PowerSync.PowerSyncBackendConnector
44
public typealias CrudEntry = PowerSync.CrudEntry
55
public typealias CrudBatch = PowerSync.CrudBatch
66
public typealias SyncStatus = PowerSync.SyncStatus
77
public typealias SqlCursor = PowerSync.RuntimeSqlCursor
88
public typealias JsonParam = PowerSync.JsonParam
99
public typealias CrudTransaction = PowerSync.CrudTransaction
10-
public typealias PowerSyncCredentials = PowerSync.PowerSyncCredentials
10+
public typealias KotlinPowerSyncCredentials = PowerSync.PowerSyncCredentials
11+
public typealias KotlinPowerSyncDatabase = PowerSync.PowerSyncDatabase
1112

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
public protocol PowerSyncBackendConnectorProtocol {
2+
func uploadData(database: PowerSyncDatabaseProtocol) async throws
3+
4+
func fetchCredentials() async throws -> PowerSyncCredentials?
5+
}
6+
7+
open class PowerSyncBackendConnector: PowerSyncBackendConnectorProtocol {
8+
public init() {}
9+
10+
open func uploadData(database: PowerSyncDatabaseProtocol) async throws {}
11+
12+
open func fetchCredentials() async throws -> PowerSyncCredentials? {
13+
return nil
14+
}
15+
}
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class PowerSyncBackendConnectorAdapter: KotlinPowerSyncBackendConnector {
2+
let swiftBackendConnector: PowerSyncBackendConnector
3+
4+
init(
5+
swiftBackendConnector: PowerSyncBackendConnector
6+
) {
7+
self.swiftBackendConnector = swiftBackendConnector
8+
}
9+
10+
override func __fetchCredentials() async throws -> KotlinPowerSyncCredentials? {
11+
try await swiftBackendConnector.fetchCredentials()?.kotlinCredentials
12+
}
13+
14+
override func __uploadData(database: KotlinPowerSyncDatabase) async throws {
15+
let swiftDatabase = KotlinPowerSyncDatabaseImpl(kotlinDatabase: database)
16+
try await swiftBackendConnector.uploadData(database: swiftDatabase)
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import Foundation
2+
3+
public struct PowerSyncCredentials: Codable {
4+
/// PowerSync endpoint, e.g. "https://myinstance.powersync.co".
5+
public let endpoint: String
6+
7+
/// Temporary token to authenticate against the service.
8+
public let token: String
9+
10+
/// User ID.
11+
public let userId: String?
12+
13+
public init(endpoint: String, token: String, userId: String?) {
14+
self.endpoint = endpoint
15+
self.token = token
16+
self.userId = userId
17+
}
18+
19+
internal init(kotlin: KotlinPowerSyncCredentials) {
20+
self.endpoint = kotlin.endpoint
21+
self.token = kotlin.token
22+
self.userId = kotlin.userId
23+
}
24+
25+
internal var kotlinCredentials: KotlinPowerSyncCredentials {
26+
return KotlinPowerSyncCredentials(endpoint: endpoint, token: token, userId: userId)
27+
}
28+
29+
public func endpointUri(path: String) -> String {
30+
return "\(endpoint)/\(path)"
31+
}
32+
}
33+
34+
extension PowerSyncCredentials: CustomStringConvertible {
35+
public var description: String {
36+
return "PowerSyncCredentials<endpoint: \(endpoint) userId: \(userId ?? "nil")>"
37+
}
38+
}

Sources/PowerSyncSwift/PowerSyncDatabase.swift

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ public let DEFAULT_DB_FILENAME = "powersync.db"
88
/// - schema: The database schema
99
/// - dbFilename: The database filename. Defaults to "powersync.db"
1010
/// - Returns: A configured PowerSyncDatabase instance
11-
@MainActor
1211
public func PowerSyncDatabase(
1312
schema: Schema,
1413
dbFilename: String = DEFAULT_DB_FILENAME

0 commit comments

Comments
 (0)