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
8 changes: 4 additions & 4 deletions Demo/PowerSyncExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
6A7315882B9854220004CB17 /* PowerSyncExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7315872B9854220004CB17 /* PowerSyncExampleApp.swift */; };
6A73158C2B9854240004CB17 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A73158B2B9854240004CB17 /* Assets.xcassets */; };
6A73158F2B9854240004CB17 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A73158E2B9854240004CB17 /* Preview Assets.xcassets */; };
6A7315BB2B98BDD30004CB17 /* PowerSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7315BA2B98BDD30004CB17 /* PowerSyncManager.swift */; };
6A7315BB2B98BDD30004CB17 /* SystemManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7315BA2B98BDD30004CB17 /* SystemManager.swift */; };
6A9668FE2B9EE4FE00B05DCF /* Auth in Frameworks */ = {isa = PBXBuildFile; productRef = 6A9668FD2B9EE4FE00B05DCF /* Auth */; };
6A9669002B9EE4FE00B05DCF /* PostgREST in Frameworks */ = {isa = PBXBuildFile; productRef = 6A9668FF2B9EE4FE00B05DCF /* PostgREST */; };
6A9669022B9EE69500B05DCF /* Supabase in Frameworks */ = {isa = PBXBuildFile; productRef = 6A9669012B9EE69500B05DCF /* Supabase */; };
Expand Down Expand Up @@ -64,7 +64,7 @@
6A7315872B9854220004CB17 /* PowerSyncExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowerSyncExampleApp.swift; sourceTree = "<group>"; };
6A73158B2B9854240004CB17 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6A73158E2B9854240004CB17 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
6A7315BA2B98BDD30004CB17 /* PowerSyncManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowerSyncManager.swift; sourceTree = "<group>"; };
6A7315BA2B98BDD30004CB17 /* SystemManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemManager.swift; sourceTree = "<group>"; };
6A9669032B9EE6FA00B05DCF /* SignInScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInScreen.swift; sourceTree = "<group>"; };
6ABD78662B9F2B4800558A41 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = "<group>"; };
6ABD786A2B9F2C1500558A41 /* TodoListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodoListView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -218,7 +218,7 @@
B65C4D6F2C60D58500176007 /* PowerSync */ = {
isa = PBXGroup;
children = (
6A7315BA2B98BDD30004CB17 /* PowerSyncManager.swift */,
6A7315BA2B98BDD30004CB17 /* SystemManager.swift */,
6A4AD3842B9EE763005CBFD4 /* SupabaseConnector.swift */,
6ABD78772B9F2D2800558A41 /* Schema.swift */,
B66658642C62314B00159A81 /* Lists.swift */,
Expand Down Expand Up @@ -567,7 +567,7 @@
B66658632C621CA700159A81 /* AddTodoListView.swift in Sources */,
B666585D2C620E9E00159A81 /* WifiIcon.swift in Sources */,
6A9669042B9EE6FA00B05DCF /* SignInScreen.swift in Sources */,
6A7315BB2B98BDD30004CB17 /* PowerSyncManager.swift in Sources */,
6A7315BB2B98BDD30004CB17 /* SystemManager.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions Demo/PowerSyncExample/PowerSync/SupabaseConnector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import Auth
import SwiftUI
import Supabase
import PowerSyncSwift
import PowerSync
import AnyCodable

@Observable
Expand All @@ -16,7 +15,6 @@ class SupabaseConnector: PowerSyncBackendConnector {

override init() {
super.init()

observeAuthStateChangesTask = Task { [weak self] in
guard let self = self else { return }

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

override func uploadData(database: PowerSyncDatabase) async throws {
override func uploadData(database: PowerSyncDatabaseProtocol) async throws {

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

Expand All @@ -75,7 +73,7 @@ class SupabaseConnector: PowerSyncBackendConnector {
}
}

try await transaction.complete.invoke(p1: nil)
_ = try await transaction.complete.invoke(p1: nil)

} catch {
print("Data upload error - retrying last entry: \(lastEntry!), \(error)")
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ let package = Package(
targets: ["PowerSyncSwift"]),
],
dependencies: [
.package(url: "https://github.com/powersync-ja/powersync-kotlin.git", exact: "1.0.0-BETA5.0"),
.package(url: "https://github.com/powersync-ja/powersync-kotlin.git", exact: "1.0.0-BETA6.0"),
.package(url: "https://github.com/powersync-ja/powersync-sqlite-core-swift.git", "0.3.1"..<"0.4.0"),
],
targets: [
Expand Down
54 changes: 30 additions & 24 deletions Sources/PowerSyncSwift/Kotlin/KotlinPowerSyncDatabaseImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,30 @@ import Foundation
import PowerSync

final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
private let kmpDatabase: PowerSync.PowerSyncDatabase
private let kotlinDatabase: PowerSync.PowerSyncDatabase

var currentStatus: SyncStatus {
get { kmpDatabase.currentStatus }
get { kotlinDatabase.currentStatus }
}

init(
schema: Schema,
dbFilename: String
) {
let factory = PowerSync.DatabaseDriverFactory()
self.kmpDatabase = PowerSyncDatabase(
self.kotlinDatabase = PowerSyncDatabase(
factory: factory,
schema: KotlinAdapter.Schema.toKotlin(schema),
dbFilename: dbFilename
)
}


init(kotlinDatabase: KotlinPowerSyncDatabase) {
self.kotlinDatabase = kotlinDatabase
}

func waitForFirstSync() async throws {
try await kmpDatabase.waitForFirstSync()
try await kotlinDatabase.waitForFirstSync()
}

func connect(
Expand All @@ -30,44 +34,46 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
retryDelayMs: Int64 = 5000,
params: [String: JsonParam?] = [:]
) async throws {
try await kmpDatabase.connect(
connector: connector,
let connectorProxy = PowerSyncBackendConnectorAdapter(swiftBackendConnector: connector)

try await kotlinDatabase.connect(
connector: connectorProxy,
crudThrottleMs: crudThrottleMs,
retryDelayMs: retryDelayMs,
params: params
)
}

func getCrudBatch(limit: Int32 = 100) async throws -> CrudBatch? {
try await kmpDatabase.getCrudBatch(limit: limit)
try await kotlinDatabase.getCrudBatch(limit: limit)
}

func getNextCrudTransaction() async throws -> CrudTransaction? {
try await kmpDatabase.getNextCrudTransaction()
try await kotlinDatabase.getNextCrudTransaction()
}

func getPowerSyncVersion() async throws -> String {
try await kmpDatabase.getPowerSyncVersion()
try await kotlinDatabase.getPowerSyncVersion()
}

func disconnect() async throws {
try await kmpDatabase.disconnect()
try await kotlinDatabase.disconnect()
}

func disconnectAndClear(clearLocal: Bool = true) async throws {
try await kmpDatabase.disconnectAndClear(clearLocal: clearLocal)
try await kotlinDatabase.disconnectAndClear(clearLocal: clearLocal)
}

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

func get<RowType>(
sql: String,
parameters: [Any]?,
mapper: @escaping (SqlCursor) -> RowType
) async throws -> RowType {
try await kmpDatabase.get(
try await kotlinDatabase.get(
sql: sql,
parameters: parameters,
mapper: mapper
Expand All @@ -79,7 +85,7 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
parameters: [Any]?,
mapper: @escaping (SqlCursor) -> RowType
) async throws -> [RowType] {
try await kmpDatabase.getAll(
try await kotlinDatabase.getAll(
sql: sql,
parameters: parameters,
mapper: mapper
Expand All @@ -91,7 +97,7 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
parameters: [Any]?,
mapper: @escaping (SqlCursor) -> RowType
) async throws -> RowType? {
try await kmpDatabase.getOptional(
try await kotlinDatabase.getOptional(
sql: sql,
parameters: parameters,
mapper: mapper
Expand All @@ -105,7 +111,7 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
) -> AsyncStream<[RowType]> {
AsyncStream { continuation in
Task {
for await values in self.kmpDatabase.watch(
for await values in self.kotlinDatabase.watch(
sql: sql,
parameters: parameters,
mapper: mapper
Expand All @@ -118,29 +124,29 @@ final class KotlinPowerSyncDatabaseImpl: PowerSyncDatabaseProtocol {
}

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

return try await kmpDatabase.writeTransaction(callback: wrappedCallback) as! R
return try await kotlinDatabase.writeTransaction(callback: wrappedCallback) as! R
}

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

return try await kmpDatabase.readTransaction(callback: wrappedCallback) as! R
return try await kotlinDatabase.readTransaction(callback: wrappedCallback) as! R
}
}

Expand All @@ -156,7 +162,7 @@ class SuspendTaskWrapper: KotlinSuspendFunction1 {
}

@MainActor
func invoke(p1: Any?, completionHandler: @escaping (Any?, Error?) -> Void) {
func __invoke(p1: Any?, completionHandler: @escaping (Any?, Error?) -> Void) {
Task {
do {
let result = try await self.handle()
Expand Down
5 changes: 3 additions & 2 deletions Sources/PowerSyncSwift/Kotlin/KotlinTypes.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import PowerSync

public typealias PowerSyncBackendConnector = PowerSync.PowerSyncBackendConnector
public typealias KotlinPowerSyncBackendConnector = PowerSync.PowerSyncBackendConnector
public typealias CrudEntry = PowerSync.CrudEntry
public typealias CrudBatch = PowerSync.CrudBatch
public typealias SyncStatus = PowerSync.SyncStatus
public typealias SqlCursor = PowerSync.RuntimeSqlCursor
public typealias JsonParam = PowerSync.JsonParam
public typealias CrudTransaction = PowerSync.CrudTransaction
public typealias PowerSyncCredentials = PowerSync.PowerSyncCredentials
public typealias KotlinPowerSyncCredentials = PowerSync.PowerSyncCredentials
public typealias KotlinPowerSyncDatabase = PowerSync.PowerSyncDatabase

16 changes: 16 additions & 0 deletions Sources/PowerSyncSwift/PowerSyncBackendConnector.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
public protocol PowerSyncBackendConnectorProtocol {
func uploadData(database: PowerSyncDatabaseProtocol) async throws

func fetchCredentials() async throws -> PowerSyncCredentials?
}

open class PowerSyncBackendConnector: PowerSyncBackendConnectorProtocol {
public init() {}

open func uploadData(database: PowerSyncDatabaseProtocol) async throws {}

open func fetchCredentials() async throws -> PowerSyncCredentials? {
return nil
}
}

18 changes: 18 additions & 0 deletions Sources/PowerSyncSwift/PowerSyncBackendConnectorAdapter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class PowerSyncBackendConnectorAdapter: KotlinPowerSyncBackendConnector {
let swiftBackendConnector: PowerSyncBackendConnector

init(
swiftBackendConnector: PowerSyncBackendConnector
) {
self.swiftBackendConnector = swiftBackendConnector
}

override func __fetchCredentials() async throws -> KotlinPowerSyncCredentials? {
try await swiftBackendConnector.fetchCredentials()?.kotlinCredentials
}

override func __uploadData(database: KotlinPowerSyncDatabase) async throws {
let swiftDatabase = KotlinPowerSyncDatabaseImpl(kotlinDatabase: database)
try await swiftBackendConnector.uploadData(database: swiftDatabase)
}
}
38 changes: 38 additions & 0 deletions Sources/PowerSyncSwift/PowerSyncCredentials.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Foundation

public struct PowerSyncCredentials: Codable {
/// PowerSync endpoint, e.g. "https://myinstance.powersync.co".
public let endpoint: String

/// Temporary token to authenticate against the service.
public let token: String

/// User ID.
public let userId: String?

public init(endpoint: String, token: String, userId: String?) {
self.endpoint = endpoint
self.token = token
self.userId = userId
}

internal init(kotlin: KotlinPowerSyncCredentials) {
self.endpoint = kotlin.endpoint
self.token = kotlin.token
self.userId = kotlin.userId
}

internal var kotlinCredentials: KotlinPowerSyncCredentials {
return KotlinPowerSyncCredentials(endpoint: endpoint, token: token, userId: userId)
}

public func endpointUri(path: String) -> String {
return "\(endpoint)/\(path)"
}
}

extension PowerSyncCredentials: CustomStringConvertible {
public var description: String {
return "PowerSyncCredentials<endpoint: \(endpoint) userId: \(userId ?? "nil")>"
}
}
1 change: 0 additions & 1 deletion Sources/PowerSyncSwift/PowerSyncDatabase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ public let DEFAULT_DB_FILENAME = "powersync.db"
/// - schema: The database schema
/// - dbFilename: The database filename. Defaults to "powersync.db"
/// - Returns: A configured PowerSyncDatabase instance
@MainActor
public func PowerSyncDatabase(
schema: Schema,
dbFilename: String = DEFAULT_DB_FILENAME
Expand Down