Skip to content

Commit 1122798

Browse files
author
DominicGBauer
committed
chore: add bucket classes and crud classes
1 parent db11a7d commit 1122798

21 files changed

+1096
-51
lines changed

Demo/PowerSyncExample/PowerSync/Lists.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import Foundation
2-
import PowerSync
32

43
struct ListContent: Identifiable, Hashable, Decodable {
54
let id: String

Demo/PowerSyncExample/PowerSync/SupabaseConnector.swift

Lines changed: 4 additions & 5 deletions
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,7 @@ class SupabaseConnector: PowerSyncBackendConnector {
1615

1716
override init() {
1817
super.init()
19-
18+
2019
observeAuthStateChangesTask = Task { [weak self] in
2120
guard let self = self else { return }
2221

@@ -49,7 +48,7 @@ class SupabaseConnector: PowerSyncBackendConnector {
4948
return PowerSyncCredentials(endpoint: self.powerSyncEndpoint, token: token, userId: currentUserID)
5049
}
5150

52-
override func uploadData(database: PowerSyncDatabase) async throws {
51+
override func uploadData(database: PowerSyncDatabaseProtocol) async throws {
5352

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

@@ -68,14 +67,14 @@ class SupabaseConnector: PowerSyncBackendConnector {
6867
try await table.upsert(data).execute();
6968
case .patch:
7069
guard let opData = entry.opData else { continue }
71-
let encodableData = opData.mapValues { AnyCodable($0) }
70+
let encodableData = opData.mapValues { $0 }
7271
try await table.update(encodableData).eq("id", value: entry.id).execute()
7372
case .delete:
7473
try await table.delete().eq( "id", value: entry.id).execute()
7574
}
7675
}
7776

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

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

Demo/PowerSyncExample/PowerSync/SystemManager.swift

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ class SystemManager {
3535

3636
func watchLists(_ callback: @escaping (_ lists: [ListContent]) -> Void ) async {
3737
for await lists in self.db.watch<[ListContent]>(
38-
sql: "SELECT * FROM \(LISTS_TABLE)",
39-
parameters: [],
38+
"SELECT * FROM \(LISTS_TABLE)",
39+
[],
4040
mapper: { cursor in
4141
ListContent(
4242
id: cursor.getString(index: 0)!,
@@ -52,29 +52,29 @@ class SystemManager {
5252

5353
func insertList(_ list: NewListContent) async throws {
5454
_ = try await self.db.execute(
55-
sql: "INSERT INTO \(LISTS_TABLE) (id, created_at, name, owner_id) VALUES (uuid(), datetime(), ?, ?)",
56-
parameters: [list.name, connector.currentUserID]
55+
"INSERT INTO \(LISTS_TABLE) (id, created_at, name, owner_id) VALUES (uuid(), datetime(), ?, ?)",
56+
[list.name, connector.currentUserID]
5757
)
5858
}
5959

6060
func deleteList(id: String) async throws {
6161
try await db.writeTransaction(callback: { transaction in
6262
_ = try await transaction.execute(
63-
sql: "DELETE FROM \(LISTS_TABLE) WHERE id = ?",
64-
parameters: [id]
63+
"DELETE FROM \(LISTS_TABLE) WHERE id = ?",
64+
[id]
6565
)
6666
_ = try await transaction.execute(
67-
sql: "DELETE FROM \(TODOS_TABLE) WHERE list_id = ?",
68-
parameters: [id]
67+
"DELETE FROM \(TODOS_TABLE) WHERE list_id = ?",
68+
[id]
6969
)
7070
return
7171
})
7272
}
7373

7474
func watchTodos(_ listId: String, _ callback: @escaping (_ todos: [Todo]) -> Void ) async {
7575
for await todos in self.db.watch(
76-
sql: "SELECT * FROM \(TODOS_TABLE) WHERE list_id = ?",
77-
parameters: [listId],
76+
"SELECT * FROM \(TODOS_TABLE) WHERE list_id = ?",
77+
[listId],
7878
mapper: { cursor in
7979
return Todo(
8080
id: cursor.getString(index: 0)!,
@@ -95,31 +95,31 @@ class SystemManager {
9595

9696
func insertTodo(_ todo: NewTodo, _ listId: String) async throws {
9797
_ = try await self.db.execute(
98-
sql: "INSERT INTO \(TODOS_TABLE) (id, created_at, created_by, description, list_id, completed) VALUES (uuid(), datetime(), ?, ?, ?, ?)",
99-
parameters: [connector.currentUserID, todo.description, listId, todo.isComplete]
98+
"INSERT INTO \(TODOS_TABLE) (id, created_at, created_by, description, list_id, completed) VALUES (uuid(), datetime(), ?, ?, ?, ?)",
99+
[connector.currentUserID, todo.description, listId, todo.isComplete]
100100
)
101101
}
102102

103103
func updateTodo(_ todo: Todo) async throws {
104104
// Do this to avoid needing to handle date time from Swift to Kotlin
105105
if(todo.isComplete) {
106106
_ = try await self.db.execute(
107-
sql: "UPDATE \(TODOS_TABLE) SET description = ?, completed = ?, completed_at = datetime(), completed_by = ? WHERE id = ?",
108-
parameters: [todo.description, todo.isComplete, connector.currentUserID, todo.id]
107+
"UPDATE \(TODOS_TABLE) SET description = ?, completed = ?, completed_at = datetime(), completed_by = ? WHERE id = ?",
108+
[todo.description, todo.isComplete, connector.currentUserID, todo.id]
109109
)
110110
} else {
111111
_ = try await self.db.execute(
112-
sql: "UPDATE \(TODOS_TABLE) SET description = ?, completed = ?, completed_at = NULL, completed_by = NULL WHERE id = ?",
113-
parameters: [todo.description, todo.isComplete, todo.id]
112+
"UPDATE \(TODOS_TABLE) SET description = ?, completed = ?, completed_at = NULL, completed_by = NULL WHERE id = ?",
113+
[todo.description, todo.isComplete, todo.id]
114114
)
115115
}
116116
}
117117

118118
func deleteTodo(id: String) async throws {
119119
try await db.writeTransaction(callback: { transaction in
120120
_ = try await transaction.execute(
121-
sql: "DELETE FROM \(TODOS_TABLE) WHERE id = ?",
122-
parameters: [id]
121+
"DELETE FROM \(TODOS_TABLE) WHERE id = ?",
122+
[id]
123123
)
124124
return
125125
})

Demo/PowerSyncExample/PowerSync/Todos.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import Foundation
2-
import PowerSync
32

43
struct Todo: Identifiable, Hashable, Decodable {
54
let id: String

Demo/PowerSyncExample/PowerSyncExampleApp.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import SwiftUI
2-
import PowerSync
32

43
@main
54
struct PowerSyncExampleApp: App {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Foundation
2+
3+
struct BucketChecksum: Codable, Equatable {
4+
let bucket: String
5+
let checksum: Int
6+
let count: Int?
7+
let lastOpId: String?
8+
9+
enum CodingKeys: String, CodingKey {
10+
case bucket
11+
case checksum
12+
case count
13+
case lastOpId = "last_op_id"
14+
}
15+
16+
init(bucket: String, checksum: Int, count: Int? = nil, lastOpId: String? = nil) {
17+
self.bucket = bucket
18+
self.checksum = checksum
19+
self.count = count
20+
self.lastOpId = lastOpId
21+
}
22+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Foundation
2+
3+
struct BucketRequest: Codable {
4+
let name: String
5+
let after: String
6+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Foundation
2+
3+
struct BucketState: Codable {
4+
let bucket: String
5+
let opId: String
6+
7+
enum CodingKeys: String, CodingKey {
8+
case bucket
9+
case opId = "op_id"
10+
}
11+
}
12+
13+
extension BucketState: CustomStringConvertible {
14+
var description: String {
15+
return "BucketState<\(bucket):\(opId)>"
16+
}
17+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import Foundation
2+
import OSLog
3+
4+
class BucketStateManager {
5+
private let db: PowerSyncDatabaseProtocol
6+
private let logger: Logger
7+
private var tableNames: Set<String>
8+
private let pendingBucketDeletes: SharedPendingDeletesActor
9+
10+
init(db: PowerSyncDatabaseProtocol, logger: Logger, pendingBucketDeletes: SharedPendingDeletesActor) {
11+
self.db = db
12+
self.logger = logger
13+
self.tableNames = []
14+
self.pendingBucketDeletes = pendingBucketDeletes
15+
}
16+
17+
func getBucketStates() async throws -> [BucketState] {
18+
try await db.getAll(
19+
"SELECT name AS bucket, CAST(last_op AS TEXT) AS op_id FROM \(InternalTable.buckets.rawValue) WHERE pending_delete = 0"
20+
) { cursor in
21+
BucketState(
22+
bucket: cursor.getString(index: 0)!,
23+
opId: cursor.getString(index: 1)!
24+
)
25+
}
26+
}
27+
28+
func removeBuckets(_ bucketsToDelete: [String]) async throws {
29+
for bucketName in bucketsToDelete {
30+
try await deleteBucket(bucketName)
31+
}
32+
}
33+
34+
func deleteBucket(_ bucketName: String) async throws {
35+
_ = try await db.execute(
36+
"INSERT INTO powersync_operations(op, data) VALUES(?, ?)",
37+
["delete_bucket", bucketName]
38+
)
39+
40+
logger.debug("Done deleting bucket")
41+
await pendingBucketDeletes.setPendingBucketDeletes(true)
42+
}
43+
44+
func updateBucketsWithCheckpoint(_ targetCheckpoint: Checkpoint) async throws {
45+
let bucketNames = targetCheckpoint.checksums.map { $0.bucket }
46+
47+
try await db.writeTransaction { transaction in
48+
_ = try await transaction.execute(
49+
"UPDATE ps_buckets SET last_op = ? WHERE name IN (SELECT json_each.value FROM json_each(?))",
50+
[targetCheckpoint.lastOpId, String(data: try JSONEncoder().encode(bucketNames), encoding: .utf8)!]
51+
)
52+
53+
if let writeCheckpoint = targetCheckpoint.writeCheckpoint {
54+
_ = try await transaction.execute(
55+
"UPDATE ps_buckets SET last_op = ? WHERE name = '$local'",
56+
[writeCheckpoint]
57+
)
58+
}
59+
}
60+
}
61+
62+
func validateChecksums(_ checkpoint: Checkpoint) async throws -> SyncLocalDatabaseResult {
63+
guard let res = try await db.getOptional(
64+
"SELECT powersync_validate_checkpoint(?) AS result",
65+
[String(data: try JSONEncoder().encode(checkpoint), encoding: .utf8)!],
66+
mapper: { $0.getString(index: 0)! }
67+
) else {
68+
return SyncLocalDatabaseResult(
69+
ready: false,
70+
checkpointValid: false
71+
)
72+
}
73+
74+
return try JSONDecoder().decode(SyncLocalDatabaseResult.self, from: res.data(using: .utf8)!)
75+
}
76+
}

0 commit comments

Comments
 (0)