From 8a18d5fd05bc61023204d4980f0abc3b0c10af01 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Thu, 11 Sep 2025 15:27:13 -0500 Subject: [PATCH 1/3] A few fixes for Xcode 26. --- Sources/SQLiteData/CloudKit/SyncEngine.swift | 1 + .../MockCloudDatabaseTests.swift | 6 ++--- .../CloudKitTests/SchemaChangeTests.swift | 1 - .../CloudKitTests/SharingTests.swift | 23 ++++++++++++------- .../SyncEngineValidationTests.swift | 1 + 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Sources/SQLiteData/CloudKit/SyncEngine.swift b/Sources/SQLiteData/CloudKit/SyncEngine.swift index 71245e50..e222cb64 100644 --- a/Sources/SQLiteData/CloudKit/SyncEngine.swift +++ b/Sources/SQLiteData/CloudKit/SyncEngine.swift @@ -1745,6 +1745,7 @@ package var isInMemory: Bool { path.isEmpty || path.hasPrefix(":memory:") + || absoluteString.hasPrefix(":memory:") || URLComponents(url: self, resolvingAgainstBaseURL: false)? .queryItems? .contains(where: { $0.name == "mode" && $0.value == "memory" }) diff --git a/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift index bddfd88b..3df8dfc9 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift @@ -392,10 +392,10 @@ try withKnownIssue { _ = try syncEngine.modifyRecords(scope: .private, saving: [share]) } matching: { issue in - issue.description == """ - Issue recorded: An added share is being saved without its rootRecord being saved in the \ + issue.description.hasSuffix(""" + An added share is being saved without its rootRecord being saved in the \ same operation. - """ + """) } } diff --git a/Tests/SQLiteDataTests/CloudKitTests/SchemaChangeTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SchemaChangeTests.swift index 9292a102..d04474ff 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SchemaChangeTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SchemaChangeTests.swift @@ -8,7 +8,6 @@ import Testing extension BaseCloudKitTests { - @MainActor final class SchemaChangeTests: BaseCloudKitTests, @unchecked Sendable { @Dependency(\.dataManager) var dataManager var inMemoryDataManager: InMemoryDataManager { diff --git a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift index 12ce91a5..25ad101d 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift @@ -527,13 +527,18 @@ } try await syncEngine.processPendingRecordZoneChanges(scope: .private) - try await withKnownIssue { - try await syncEngine.unshare(record: remindersList) - } matching: { issue in - issue.description == """ - Issue recorded: No share found associated with record. - """ - } + // NB: Swift 6.2 cannot currently compile this: + // Pattern that the region based isolation checker does not understand how to check. + // Please file a bug. + #if swift(<6.2) + try await withKnownIssue { + try await syncEngine.unshare(record: remindersList) + } matching: { issue in + issue.description == """ + Issue recorded: No share found associated with record. + """ + } + #endif } @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) @@ -629,7 +634,9 @@ ) _ = try syncEngine.modifyRecords(scope: .shared, saving: [share, remindersListRecord]) let freshShare = try syncEngine.shared.database.record(for: share.recordID) as! CKShare - let freshRemindersListRecord = try syncEngine.shared.database.record(for: remindersListRecord.recordID) + let freshRemindersListRecord = try syncEngine.shared.database.record( + for: remindersListRecord.recordID + ) try await syncEngine .acceptShare( diff --git a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineValidationTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineValidationTests.swift index 5b24fe01..e1204463 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineValidationTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineValidationTests.swift @@ -81,6 +81,7 @@ ) } ) + try await Task.sleep(for: .seconds(1)) assertInlineSnapshot(of: error.localizedDescription, as: .customDump) { """ "Could not synchronize data with iCloud." From ff707c4a98112b3da68bcb2a125c1354fdfa403d Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Thu, 11 Sep 2025 15:30:14 -0500 Subject: [PATCH 2/3] wip --- Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift index 25ad101d..b5501529 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift @@ -534,9 +534,9 @@ try await withKnownIssue { try await syncEngine.unshare(record: remindersList) } matching: { issue in - issue.description == """ + issue.description.hasSuffix(""" Issue recorded: No share found associated with record. - """ + """) } #endif } From e23b445e71407e0fa8242dd275aec6fb2364af71 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 15 Sep 2025 11:28:12 -0500 Subject: [PATCH 3/3] wip --- .../CloudKit/Internal/_SendableMetatype.swift | 5 +++ Sources/SQLiteData/CloudKit/SyncEngine.swift | 30 ++++++++-------- .../CloudKitTests/SharingTests.swift | 34 ++++++++++--------- .../SyncEngineValidationTests.swift | 1 - 4 files changed, 38 insertions(+), 32 deletions(-) create mode 100644 Sources/SQLiteData/CloudKit/Internal/_SendableMetatype.swift diff --git a/Sources/SQLiteData/CloudKit/Internal/_SendableMetatype.swift b/Sources/SQLiteData/CloudKit/Internal/_SendableMetatype.swift new file mode 100644 index 00000000..64a0774e --- /dev/null +++ b/Sources/SQLiteData/CloudKit/Internal/_SendableMetatype.swift @@ -0,0 +1,5 @@ +#if swift(>=6.2) + public typealias _SendableMetatype = SendableMetatype +#else + public typealias _SendableMetatype = Any +#endif diff --git a/Sources/SQLiteData/CloudKit/SyncEngine.swift b/Sources/SQLiteData/CloudKit/SyncEngine.swift index e222cb64..a79dc5c3 100644 --- a/Sources/SQLiteData/CloudKit/SyncEngine.swift +++ b/Sources/SQLiteData/CloudKit/SyncEngine.swift @@ -22,9 +22,9 @@ package let userDatabase: UserDatabase package let logger: Logger package let metadatabase: any DatabaseWriter - package let tables: [any PrimaryKeyedTable.Type] - package let privateTables: [any PrimaryKeyedTable.Type] - let tablesByName: [String: any PrimaryKeyedTable.Type] + package let tables: [any (PrimaryKeyedTable & _SendableMetatype).Type] + package let privateTables: [any (PrimaryKeyedTable & _SendableMetatype).Type] + let tablesByName: [String: any (PrimaryKeyedTable & _SendableMetatype).Type] private let tablesByOrder: [String: Int] let foreignKeysByTableName: [String: [ForeignKey]] package let syncEngines = LockIsolated(SyncEngines()) @@ -75,7 +75,7 @@ /// explicit call to ``stop()``. By default this argument is `true`. /// - logger: The logger used to log events in the sync engine. By default a `.disabled` /// logger is used, which means logs are not printed. - public convenience init( + public convenience init( for database: any DatabaseWriter, tables: repeat (each T1).Type, privateTables: repeat (each T2).Type, @@ -93,8 +93,8 @@ containerIdentifier ?? ModelConfiguration(groupContainer: .automatic).cloudKitContainerIdentifier - var allTables: [any PrimaryKeyedTable.Type] = [] - var allPrivateTables: [any PrimaryKeyedTable.Type] = [] + var allTables: [any (PrimaryKeyedTable & _SendableMetatype).Type] = [] + var allPrivateTables: [any (PrimaryKeyedTable & _SendableMetatype).Type] = [] for table in repeat each tables { allTables.append(table) } @@ -203,8 +203,8 @@ ) -> (private: any SyncEngineProtocol, shared: any SyncEngineProtocol), userDatabase: UserDatabase, logger: Logger, - tables: [any PrimaryKeyedTable.Type], - privateTables: [any PrimaryKeyedTable.Type] = [] + tables: [any (PrimaryKeyedTable & _SendableMetatype).Type], + privateTables: [any (PrimaryKeyedTable & _SendableMetatype).Type] = [] ) throws { let allTables = Set((tables + privateTables).map(HashablePrimaryKeyedTableType.init)) .map(\.type) @@ -1404,7 +1404,7 @@ let recordPrimaryKey = failedRecord.recordID.recordPrimaryKey, let table = tablesByName[failedRecord.recordType] else { continue } - func open(_: T.Type) async throws { + func open(_: T.Type) async throws { do { let serverRecord = try await container.sharedCloudDatabase.record( for: failedRecord.recordID @@ -1529,7 +1529,7 @@ serverRecord.userModificationDate = metadata?.userModificationDate ?? serverRecord.userModificationDate - func open(_: T.Type) async throws { + func open(_: T.Type) async throws { let columnNames: [String] if !force, let metadata, let allFields = metadata._lastKnownServerRecordAllFields { columnNames = try await userDatabase.read { db in @@ -1938,8 +1938,8 @@ } private struct HashablePrimaryKeyedTableType: Hashable { - let type: any PrimaryKeyedTable.Type - init(_ type: any PrimaryKeyedTable.Type) { + let type: any (PrimaryKeyedTable & _SendableMetatype).Type + init(_ type: any (PrimaryKeyedTable & _SendableMetatype).Type) { self.type = type } func hash(into hasher: inout Hasher) { @@ -1953,11 +1953,11 @@ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) private func tablesByOrder( userDatabase: UserDatabase, - tables: [any PrimaryKeyedTable.Type], - tablesByName: [String: any PrimaryKeyedTable.Type] + tables: [any (PrimaryKeyedTable & _SendableMetatype).Type], + tablesByName: [String: any (PrimaryKeyedTable & _SendableMetatype).Type] ) throws -> [String: Int] { let tableDependencies = try userDatabase.read { db in - var dependencies: [HashablePrimaryKeyedTableType: [any PrimaryKeyedTable.Type]] = [:] + var dependencies: [HashablePrimaryKeyedTableType: [any (PrimaryKeyedTable & _SendableMetatype).Type]] = [:] for table in tables { func open(_: T.Type) throws -> [String] { try PragmaForeignKeyList.select(\.table) diff --git a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift index b5501529..22d1bd47 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift @@ -517,29 +517,31 @@ } } - @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) - @Test func unshareNonSharedRecord() async throws { - let remindersList = RemindersList(id: 1, title: "Personal") - try await userDatabase.userWrite { db in - try db.seed { - remindersList + // NB: Swift 6.2 cannot currently compile this: + // Pattern that the region based isolation checker does not understand how to check. + // Please file a bug. + #if swift(<6.2) + @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) + @Test func unshareNonSharedRecord() async throws { + let remindersList = RemindersList(id: 1, title: "Personal") + try await userDatabase.userWrite { db in + try db.seed { + remindersList + } } - } - try await syncEngine.processPendingRecordZoneChanges(scope: .private) + try await syncEngine.processPendingRecordZoneChanges(scope: .private) - // NB: Swift 6.2 cannot currently compile this: - // Pattern that the region based isolation checker does not understand how to check. - // Please file a bug. - #if swift(<6.2) try await withKnownIssue { try await syncEngine.unshare(record: remindersList) } matching: { issue in - issue.description.hasSuffix(""" + issue.description.hasSuffix( + """ Issue recorded: No share found associated with record. - """) + """ + ) } - #endif - } + } + #endif @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) @Test func shareUnshareShareAgain() async throws { diff --git a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineValidationTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineValidationTests.swift index e1204463..5b24fe01 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineValidationTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineValidationTests.swift @@ -81,7 +81,6 @@ ) } ) - try await Task.sleep(for: .seconds(1)) assertInlineSnapshot(of: error.localizedDescription, as: .customDump) { """ "Could not synchronize data with iCloud."