crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

commit 19772412fa3d29376a77791825f1805d4c59c688
parent c79ed4b81c9003a9eb97455360a6d8ead651e685
Author: Michael Camilleri <[email protected]>
Date:   Thu, 23 Jul 2026 20:53:29 +0900

Use enumeration to find invalid Player records

Diffstat:
MCrossmate/Sync/SyncEngine.swift | 36+++++++++++++++++++++++++++++-------
1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/Crossmate/Sync/SyncEngine.swift b/Crossmate/Sync/SyncEngine.swift @@ -1068,13 +1068,7 @@ actor SyncEngine { } do { - let records = try await queryRecords( - type: "Player", - database: container.privateCloudDatabase, - zoneID: Archive.zoneID, - predicate: NSPredicate(value: true), - desiredKeys: [] - ) + let records = try await chroniclePlayerRecords() try await deleteRecords( withIDs: records.map(\.recordID), in: container.privateCloudDatabase @@ -1089,6 +1083,34 @@ actor SyncEngine { } } + /// Enumerates the zone's change history rather than issuing a CKQuery. + /// Production does not have a queryable `recordName` index for Player, but + /// a zone-change fetch needs no schema index and is already the mechanism + /// used by the storage audit. + private func chroniclePlayerRecords() async throws -> [CKRecord] { + let database = container.privateCloudDatabase + var records: [CKRecord] = [] + var token: CKServerChangeToken? + var moreComing = true + + while moreComing { + let page = try await database.recordZoneChanges( + inZoneWith: Archive.zoneID, + since: token, + desiredKeys: [] + ) + token = page.changeToken + moreComing = page.moreComing + for result in page.modificationResultsByID.values { + let record = try result.get().record + if record.recordType == "Player" { + records.append(record) + } + } + } + return records + } + /// Pure classifier shared with tests so the migration cannot remove a /// Player record from a live game zone. nonisolated static func isChroniclePlayerRecordID(_ recordID: CKRecord.ID) -> Bool {