Skip to content

Commit f1ee1bd

Browse files
authored
Merge pull request #43 from pointfreeco/improve-delete-efficiency
Improves efficiency of deleting many unsync'd records
2 parents 52d05c0 + 72797df commit f1ee1bd

File tree

2 files changed

+66
-46
lines changed

2 files changed

+66
-46
lines changed

Sources/SharingGRDBCore/CloudKit/SyncEngine.swift

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,51 @@
819819
deletions: [(recordID: CKRecord.ID, recordType: CKRecord.RecordType)] = [],
820820
syncEngine: any SyncEngineProtocol
821821
) async {
822+
let recordIDsByRecordType = OrderedDictionary(
823+
grouping: deletions.sorted { lhs, rhs in
824+
guard
825+
let lhsIndex = tablesByOrder[lhs.recordType],
826+
let rhsIndex = tablesByOrder[rhs.recordType]
827+
else { return true }
828+
return lhsIndex > rhsIndex
829+
},
830+
by: \.recordType
831+
)
832+
.mapValues { $0.map(\.recordID) }
833+
for (recordType, recordIDs) in recordIDsByRecordType {
834+
let recordPrimaryKeys = recordIDs.compactMap(\.recordPrimaryKey)
835+
if let table = tablesByName[recordType] {
836+
func open<T: PrimaryKeyedTable>(_: T.Type) {
837+
withErrorReporting(.sqliteDataCloudKitFailure) {
838+
try userDatabase.write { db in
839+
try T
840+
.where {
841+
$0.primaryKey.in(
842+
recordPrimaryKeys.map { SQLQueryExpression("\(bind: $0)") }
843+
)
844+
}
845+
.delete()
846+
.execute(db)
847+
848+
try UnsyncedRecordID
849+
.findAll(recordIDs)
850+
.delete()
851+
.execute(db)
852+
}
853+
}
854+
}
855+
open(table)
856+
} else if recordType == CKRecord.SystemType.share {
857+
withErrorReporting {
858+
for recordID in recordIDs {
859+
try deleteShare(recordID: recordID)
860+
}
861+
}
862+
} else {
863+
// NB: Deleting a record from a table we do not currently recognize.
864+
}
865+
}
866+
822867
let unsyncedRecords =
823868
await withErrorReporting(.sqliteDataCloudKitFailure) {
824869
var unsyncedRecordIDs = try await userDatabase.write { db in
@@ -833,9 +878,10 @@
833878
unsyncedRecordIDs.subtract(modificationRecordIDs)
834879
if !unsyncedRecordIDsToDelete.isEmpty {
835880
try await userDatabase.write { db in
836-
for recordID in unsyncedRecordIDsToDelete {
837-
try UnsyncedRecordID.find(recordID).delete().execute(db)
838-
}
881+
try UnsyncedRecordID
882+
.findAll(unsyncedRecordIDsToDelete)
883+
.delete()
884+
.execute(db)
839885
}
840886
}
841887
let results = try await syncEngine.database.records(for: Array(unsyncedRecordIDs))
@@ -902,46 +948,6 @@
902948
}
903949
}
904950
}
905-
906-
let recordIDsByRecordType = OrderedDictionary(
907-
grouping: deletions.sorted { lhs, rhs in
908-
guard
909-
let lhsIndex = tablesByOrder[lhs.recordType],
910-
let rhsIndex = tablesByOrder[rhs.recordType]
911-
else { return true }
912-
return lhsIndex > rhsIndex
913-
},
914-
by: \.recordType
915-
)
916-
.mapValues { $0.map(\.recordID) }
917-
for (recordType, recordIDs) in recordIDsByRecordType {
918-
let recordPrimaryKeys = recordIDs.compactMap(\.recordPrimaryKey)
919-
if let table = tablesByName[recordType] {
920-
func open<T: PrimaryKeyedTable>(_: T.Type) {
921-
withErrorReporting(.sqliteDataCloudKitFailure) {
922-
try userDatabase.write { db in
923-
try T
924-
.where {
925-
$0.primaryKey.in(
926-
recordPrimaryKeys.map { SQLQueryExpression("\(bind: $0)") }
927-
)
928-
}
929-
.delete()
930-
.execute(db)
931-
}
932-
}
933-
}
934-
open(table)
935-
} else if recordType == CKRecord.SystemType.share {
936-
withErrorReporting {
937-
for recordID in recordIDs {
938-
try deleteShare(recordID: recordID)
939-
}
940-
}
941-
} else {
942-
// NB: Deleting a record from a table we do not currently recognize.
943-
}
944-
}
945951
}
946952

947953
package func handleSentRecordZoneChanges(

Sources/SharingGRDBCore/CloudKit/UnsyncedRecordID.swift

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import StructuredQueriesCore
44

55
// @Table("\(String.sqliteDataCloudKitSchemaName)_unsyncedRecordIDs")
6-
package struct UnsyncedRecordID: Equatable {
6+
package struct UnsyncedRecordID: Equatable {
77
package let recordName: String
88
package let zoneName: String
99
package let ownerName: String
@@ -18,8 +18,22 @@ package struct UnsyncedRecordID: Equatable {
1818
package static func find(_ recordID: CKRecord.ID) -> Where<UnsyncedRecordID> {
1919
Self.where {
2020
$0.recordName.eq(recordID.recordName)
21-
&& $0.zoneName.eq(recordID.zoneID.zoneName)
22-
&& $0.ownerName.eq(recordID.zoneID.ownerName)
21+
&& $0.zoneName.eq(recordID.zoneID.zoneName)
22+
&& $0.ownerName.eq(recordID.zoneID.ownerName)
23+
}
24+
}
25+
package static func findAll(_ recordIDs: some Collection<CKRecord.ID>) -> Where<UnsyncedRecordID> {
26+
let condition: QueryFragment = recordIDs.map {
27+
"(\(bind: $0.recordName), \(bind: $0.zoneID.zoneName), \(bind: $0.zoneID.ownerName))"
28+
}
29+
.joined(separator: ", ")
30+
return Self.where {
31+
SQLQueryExpression(
32+
"""
33+
(\($0.recordName), \($0.zoneName), \($0.ownerName)) \
34+
IN (\(condition))
35+
"""
36+
)
2337
}
2438
}
2539
}

0 commit comments

Comments
 (0)