From a01f0d3cf45450e57e06a583a6c140d024bc8e6a Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Sun, 11 Jan 2026 18:21:01 -0600 Subject: [PATCH 01/11] Fix metadata observation. --- Examples/RemindersTests/Internal.swift | 2 +- .../SQLiteData/CloudKit/CloudKitSharing.swift | 2 +- Sources/SQLiteData/CloudKit/SyncEngine.swift | 2 +- Tests/SQLiteDataTests/AssertQueryTests.swift | 2 +- .../CloudKitTests/MetadataTests.swift | 66 +++++++++++++++++++ 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/Examples/RemindersTests/Internal.swift b/Examples/RemindersTests/Internal.swift index 61c1dd30..03f45434 100644 --- a/Examples/RemindersTests/Internal.swift +++ b/Examples/RemindersTests/Internal.swift @@ -14,7 +14,7 @@ import Testing try $0.bootstrapDatabase() try await $0.defaultSyncEngine.sendChanges() }, - .snapshots(record: .failed) + .snapshots(record: .missing) ) struct BaseTestSuite {} diff --git a/Sources/SQLiteData/CloudKit/CloudKitSharing.swift b/Sources/SQLiteData/CloudKit/CloudKitSharing.swift index 09f4181b..284b0d6b 100644 --- a/Sources/SQLiteData/CloudKit/CloudKitSharing.swift +++ b/Sources/SQLiteData/CloudKit/CloudKitSharing.swift @@ -195,7 +195,7 @@ """ ) } - try await metadatabase.write { db in + try await userDatabase.write { db in try SyncMetadata .where { $0.recordName.eq(recordName) } .update { diff --git a/Sources/SQLiteData/CloudKit/SyncEngine.swift b/Sources/SQLiteData/CloudKit/SyncEngine.swift index 24891aa4..68bc6cf0 100644 --- a/Sources/SQLiteData/CloudKit/SyncEngine.swift +++ b/Sources/SQLiteData/CloudKit/SyncEngine.swift @@ -1937,7 +1937,7 @@ private func refreshLastKnownServerRecord(_ record: CKRecord) async { await withErrorReporting(.sqliteDataCloudKitFailure) { - try await metadatabase.write { db in + try await userDatabase.write { db in let metadata = try SyncMetadata.find(record.recordID).fetchOne(db) func updateLastKnownServerRecord() throws { try SyncMetadata diff --git a/Tests/SQLiteDataTests/AssertQueryTests.swift b/Tests/SQLiteDataTests/AssertQueryTests.swift index 08ca809e..ac82ec53 100644 --- a/Tests/SQLiteDataTests/AssertQueryTests.swift +++ b/Tests/SQLiteDataTests/AssertQueryTests.swift @@ -8,7 +8,7 @@ import Testing @MainActor @Suite( .dependency(\.defaultDatabase, try .database()), - .snapshots(record: .failed), + .snapshots(record: .missing), ) struct AssertQueryTests { @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) diff --git a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift index c3db0e3c..d8012cf8 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift @@ -621,6 +621,72 @@ """ } } + + @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) + @Test(.attachMetadatabase(true)) + func observation() 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) + + @FetchAll( + SyncMetadata + .select { + RecordNameAndIsShared.Columns( + recordName: $0.recordName, + isShared: $0.share.isNot(nil) + ) + }, + database: userDatabase.database + ) + var rows + try await $rows.load() + #expect(rows == [RecordNameAndIsShared(recordName: "1:remindersLists", isShared: false)]) + + _ = try await syncEngine.share(record: remindersList) { _ in } + + try await Task.sleep(for: .seconds(0.5)) + #expect(rows == [RecordNameAndIsShared(recordName: "1:remindersLists", isShared: true)]) + } + + @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) + @Test(.attachMetadatabase(true)) + func observation_GeneratedColumn() 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) + + @FetchAll( + SyncMetadata + .select { + RecordNameAndIsShared.Columns( + recordName: $0.recordName, + isShared: $0.isShared + ) + }, + database: userDatabase.database + ) + var rows + try await $rows.load() + #expect(rows == [RecordNameAndIsShared(recordName: "1:remindersLists", isShared: false)]) + + _ = try await syncEngine.share(record: remindersList) { _ in } + + try await Task.sleep(for: .seconds(0.5)) + withKnownIssue("Query observation does not work with generated columns right now") { + #expect(rows == [RecordNameAndIsShared(recordName: "1:remindersLists", isShared: true)]) + } + } } } + + +@Selection struct RecordNameAndIsShared: Equatable { + let recordName: String + let isShared: Bool +} #endif From 67ce6bf4afed077b7f5a6346fa9c0db79d602cdd Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 12 Jan 2026 10:39:58 -0600 Subject: [PATCH 02/11] Workaround for generated column observation behavior. --- .../SQLiteData/CloudKit/SyncMetadata.swift | 19 +++++++++----- .../CloudKitTests/AccountLifecycleTests.swift | 8 ------ .../AttachedMetadatabaseTests.swift | 1 - .../FetchRecordZoneChangesTests.swift | 3 --- .../CloudKitTests/MetadataTests.swift | 16 +----------- .../CloudKitTests/SharingTests.swift | 25 ------------------- .../SyncEngineDelegateTests.swift | 2 -- .../SyncEngineLifecycleTests.swift | 8 ------ 8 files changed, 14 insertions(+), 68 deletions(-) diff --git a/Sources/SQLiteData/CloudKit/SyncMetadata.swift b/Sources/SQLiteData/CloudKit/SyncMetadata.swift index 2d64e7a4..82b011d8 100644 --- a/Sources/SQLiteData/CloudKit/SyncMetadata.swift +++ b/Sources/SQLiteData/CloudKit/SyncMetadata.swift @@ -100,16 +100,17 @@ @Column(generated: .virtual) public let hasLastKnownServerRecord: Bool + /// The time the user last modified the record. + public let userModificationTime: Int64 + /// Determines if the record associated with this metadata is currently shared in CloudKit. /// /// This can only return `true` for root records. For example, the metadata associated with a /// `RemindersList` can have `isShared == true`, but a `Reminder` associated with the list /// will have `isShared == false`. - @Column(generated: .virtual) - public let isShared: Bool - - /// The time the user last modified the record. - public let userModificationTime: Int64 + public var isShared: Bool { + share != nil + } } @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) @@ -129,6 +130,13 @@ public var parentRecordType: TableColumn { parentRecordID.parentRecordType } + + // NB: Workaround for https://github.com/groue/GRDB.swift/discussions/1844 + public var isShared: some QueryExpression { + #sql(""" + (\(QueryValue.self)."isShared" AND (\(self.share) OR 1)) + """) + } } @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) @@ -163,7 +171,6 @@ self._lastKnownServerRecordAllFields = _lastKnownServerRecordAllFields self.share = share self.hasLastKnownServerRecord = lastKnownServerRecord != nil - self.isShared = share != nil self.userModificationTime = userModificationTime self._isDeleted = false } diff --git a/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift b/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift index c9e7c117..d77998c6 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift @@ -172,7 +172,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├────────────────────────────────────────────────────────────────────┤ @@ -194,7 +193,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────────────┘ @@ -258,7 +256,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -294,7 +291,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────┘ @@ -422,7 +418,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -444,7 +439,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -519,7 +513,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -555,7 +548,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift b/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift index 6a199936..4c1b88f7 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift @@ -57,7 +57,6 @@ │ │ share: nil, │ │ │ _isDeleted: false, │ │ │ hasLastKnownServerRecord: true, │ - │ │ isShared: false, │ │ │ userModificationTime: 0 │ │ │ ) │ └─────────────────────┴────────────────────────────────────────────────────────────────────┘ diff --git a/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift b/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift index 13e85616..07d65e02 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift @@ -547,7 +547,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────┘ @@ -630,7 +629,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────┘ @@ -700,7 +698,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────────┘ diff --git a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift index d8012cf8..c4ac4b72 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift @@ -236,7 +236,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -272,7 +271,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -303,7 +301,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -335,7 +332,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -371,7 +367,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -402,7 +397,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -434,7 +428,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -470,7 +463,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -500,7 +492,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -530,7 +521,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────┘ @@ -583,7 +573,6 @@ │ │ share: nil, │ │ │ _isDeleted: false, │ │ │ hasLastKnownServerRecord: true, │ - │ │ isShared: false, │ │ │ userModificationTime: 0 │ │ │ ) │ ├─────────────────────┼────────────────────────────────────────────────────────────────────┤ @@ -614,7 +603,6 @@ │ │ share: nil, │ │ │ _isDeleted: false, │ │ │ hasLastKnownServerRecord: true, │ - │ │ isShared: false, │ │ │ userModificationTime: 0 │ │ │ ) │ └─────────────────────┴────────────────────────────────────────────────────────────────────┘ @@ -677,9 +665,7 @@ _ = try await syncEngine.share(record: remindersList) { _ in } try await Task.sleep(for: .seconds(0.5)) - withKnownIssue("Query observation does not work with generated columns right now") { - #expect(rows == [RecordNameAndIsShared(recordName: "1:remindersLists", isShared: true)]) - } + #expect(rows == [RecordNameAndIsShared(recordName: "1:remindersLists", isShared: true)]) } } } diff --git a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift index f74d730f..7566903e 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift @@ -502,7 +502,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -585,7 +584,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -620,7 +618,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 60 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -655,7 +652,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 60 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -1170,7 +1166,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -1206,7 +1201,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -1851,7 +1845,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -1887,7 +1880,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -1922,7 +1914,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 1 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -1957,7 +1948,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -2156,7 +2146,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2192,7 +2181,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2227,7 +2215,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2262,7 +2249,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -2461,7 +2447,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2497,7 +2482,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2532,7 +2516,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2567,7 +2550,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -2746,7 +2728,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2782,7 +2763,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2817,7 +2797,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 1 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -2989,7 +2968,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -3025,7 +3003,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -3060,7 +3037,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 1 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -3095,7 +3071,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift index c97c95ee..9d4cea32 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift @@ -65,7 +65,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────────────┘ @@ -139,7 +138,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────────────┘ diff --git a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift index 83257f4d..8675e9e9 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift @@ -50,7 +50,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────┤ @@ -72,7 +71,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────┘ @@ -330,7 +328,6 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -352,7 +349,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ - │ isShared: false, │ │ userModificationTime: 60 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -608,7 +604,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────┤ @@ -630,7 +625,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────┘ @@ -686,7 +680,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -722,7 +715,6 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ - │ isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────┘ From a53a9f3da4103827db20d0ae36c0df46c042c320 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 12 Jan 2026 10:50:25 -0600 Subject: [PATCH 03/11] optimization --- Sources/SQLiteData/CloudKit/SyncMetadata.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SQLiteData/CloudKit/SyncMetadata.swift b/Sources/SQLiteData/CloudKit/SyncMetadata.swift index 82b011d8..91012a50 100644 --- a/Sources/SQLiteData/CloudKit/SyncMetadata.swift +++ b/Sources/SQLiteData/CloudKit/SyncMetadata.swift @@ -134,7 +134,7 @@ // NB: Workaround for https://github.com/groue/GRDB.swift/discussions/1844 public var isShared: some QueryExpression { #sql(""" - (\(QueryValue.self)."isShared" AND (\(self.share) OR 1)) + ((\(QueryValue.self)."isShared" = 1) AND (\(self.share) OR 1)) """) } } From fbf04a1b34734ade8141fd425b0279eac6047c13 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 12 Jan 2026 10:59:54 -0600 Subject: [PATCH 04/11] clean up --- Sources/SQLiteData/CloudKit/SyncMetadata.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/SQLiteData/CloudKit/SyncMetadata.swift b/Sources/SQLiteData/CloudKit/SyncMetadata.swift index 91012a50..623539e5 100644 --- a/Sources/SQLiteData/CloudKit/SyncMetadata.swift +++ b/Sources/SQLiteData/CloudKit/SyncMetadata.swift @@ -100,6 +100,9 @@ @Column(generated: .virtual) public let hasLastKnownServerRecord: Bool + @Column("isShared", generated: .virtual) + fileprivate let _isShared: Bool + /// The time the user last modified the record. public let userModificationTime: Int64 @@ -134,7 +137,7 @@ // NB: Workaround for https://github.com/groue/GRDB.swift/discussions/1844 public var isShared: some QueryExpression { #sql(""" - ((\(QueryValue.self)."isShared" = 1) AND (\(self.share) OR 1)) + (\(self._isShared) = 1) AND (\(self.share) OR 1)) """) } } @@ -170,6 +173,7 @@ self.lastKnownServerRecord = lastKnownServerRecord self._lastKnownServerRecordAllFields = _lastKnownServerRecordAllFields self.share = share + self._isShared = share != nil self.hasLastKnownServerRecord = lastKnownServerRecord != nil self.userModificationTime = userModificationTime self._isDeleted = false From 6bb47d3a05cdf88c0343b304a66c633ca16c0389 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 12 Jan 2026 11:00:49 -0600 Subject: [PATCH 05/11] clean up --- .../CloudKitTests/AccountLifecycleTests.swift | 8 ++ .../AttachedMetadatabaseTests.swift | 1 + .../FetchRecordZoneChangesTests.swift | 3 + .../CloudKitTests/MetadataTests.swift | 12 +++ .../CloudKitTests/SharingTests.swift | 95 +++++++------------ .../SyncEngineDelegateTests.swift | 2 + .../SyncEngineLifecycleTests.swift | 20 ++-- 7 files changed, 70 insertions(+), 71 deletions(-) diff --git a/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift b/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift index d77998c6..28a6097c 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift @@ -172,6 +172,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├────────────────────────────────────────────────────────────────────┤ @@ -193,6 +194,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────────────┘ @@ -256,6 +258,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -291,6 +294,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────┘ @@ -418,6 +422,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -439,6 +444,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -513,6 +519,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -548,6 +555,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift b/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift index 4c1b88f7..cfe9fd78 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift @@ -57,6 +57,7 @@ │ │ share: nil, │ │ │ _isDeleted: false, │ │ │ hasLastKnownServerRecord: true, │ + │ │ _isShared: false, │ │ │ userModificationTime: 0 │ │ │ ) │ └─────────────────────┴────────────────────────────────────────────────────────────────────┘ diff --git a/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift b/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift index 07d65e02..8d348750 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift @@ -547,6 +547,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────┘ @@ -629,6 +630,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────┘ @@ -698,6 +700,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────────┘ diff --git a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift index c4ac4b72..133a4311 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift @@ -236,6 +236,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -271,6 +272,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -301,6 +303,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -332,6 +335,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -367,6 +371,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -397,6 +402,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -428,6 +434,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -463,6 +470,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -492,6 +500,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -521,6 +530,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────┘ @@ -573,6 +583,7 @@ │ │ share: nil, │ │ │ _isDeleted: false, │ │ │ hasLastKnownServerRecord: true, │ + │ │ _isShared: false, │ │ │ userModificationTime: 0 │ │ │ ) │ ├─────────────────────┼────────────────────────────────────────────────────────────────────┤ @@ -603,6 +614,7 @@ │ │ share: nil, │ │ │ _isDeleted: false, │ │ │ hasLastKnownServerRecord: true, │ + │ │ _isShared: false, │ │ │ userModificationTime: 0 │ │ │ ) │ └─────────────────────┴────────────────────────────────────────────────────────────────────┘ diff --git a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift index 7566903e..7be0f4e4 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift @@ -502,6 +502,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -584,6 +585,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -618,6 +620,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 60 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -652,6 +655,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 60 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -1166,6 +1170,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -1201,6 +1206,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -1453,36 +1459,7 @@ ), sharedCloudDatabase: MockCloudDatabase( databaseScope: .shared, - storage: [ - [0]: CKRecord( - recordID: CKRecord.ID(1:reminders/external.zone/external.owner), - recordType: "reminders", - parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)), - share: nil, - id: 1, - isCompleted: 0, - remindersListID: 1, - title: "Get milk" - ), - [1]: CKRecord( - recordID: CKRecord.ID(2:reminders/external.zone/external.owner), - recordType: "reminders", - parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)), - share: nil, - id: 2, - isCompleted: 0, - remindersListID: 1, - title: "Take a walk" - ), - [2]: CKRecord( - recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner), - recordType: "remindersLists", - parent: nil, - share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner)), - id: 1, - title: "Personal" - ) - ] + storage: [] ) ) """ @@ -1564,33 +1541,7 @@ ), sharedCloudDatabase: MockCloudDatabase( databaseScope: .shared, - storage: [ - [0]: CKRecord( - recordID: CKRecord.ID(1:modelAs/external.zone/external.owner), - recordType: "modelAs", - parent: nil, - share: CKReference(recordID: CKRecord.ID(share-1:modelAs/external.zone/external.owner)), - count: 42 - ), - [1]: CKRecord( - recordID: CKRecord.ID(1:modelBs/external.zone/external.owner), - recordType: "modelBs", - parent: CKReference(recordID: CKRecord.ID(1:modelAs/external.zone/external.owner)), - share: nil, - id: 1, - isOn: 1, - modelAID: 1 - ), - [2]: CKRecord( - recordID: CKRecord.ID(1:modelCs/external.zone/external.owner), - recordType: "modelCs", - parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)), - share: nil, - id: 1, - modelBID: 1, - title: "Hello world!" - ) - ] + storage: [] ) ) """ @@ -1845,6 +1796,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -1880,6 +1832,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -1914,6 +1867,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 1 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -1948,6 +1902,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -2146,6 +2101,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2181,6 +2137,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2215,6 +2172,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2249,6 +2207,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -2447,6 +2406,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2482,6 +2442,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2516,6 +2477,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2550,6 +2512,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -2728,6 +2691,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2763,6 +2727,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -2797,6 +2762,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 1 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -2968,6 +2934,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -3003,6 +2970,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -3037,6 +3005,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 1 │ │ ) │ ├──────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -3071,6 +3040,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -3152,9 +3122,14 @@ assertQuery(SyncMetadata.select(\.share), database: syncEngine.metadatabase) { """ - ┌─────┐ - │ nil │ - └─────┘ + ┌────────────────────────────────────────────────────────────────────────┐ + │ CKRecord( │ + │ recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__), │ + │ recordType: "cloudkit.share", │ + │ parent: nil, │ + │ share: nil │ + │ ) │ + └────────────────────────────────────────────────────────────────────────┘ """ } assertInlineSnapshot(of: container, as: .customDump) { diff --git a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift index 9d4cea32..8828275e 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift @@ -65,6 +65,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────────────┘ @@ -138,6 +139,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └────────────────────────────────────────────────────────────────────┘ diff --git a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift index 8675e9e9..0fb2131f 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift @@ -50,6 +50,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────┤ @@ -71,6 +72,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────┘ @@ -328,6 +330,7 @@ │ ), │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────────────────┤ @@ -349,6 +352,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ + │ _isShared: false, │ │ userModificationTime: 60 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘ @@ -487,17 +491,7 @@ ), sharedCloudDatabase: MockCloudDatabase( databaseScope: .shared, - storage: [ - [0]: CKRecord( - recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner), - recordType: "remindersLists", - parent: nil, - share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner)), - id: 1, - isCompleted: 0, - title: "Personal" - ) - ] + storage: [] ) ) """ @@ -604,6 +598,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├──────────────────────────────────────────┤ @@ -625,6 +620,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: false, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └──────────────────────────────────────────┘ @@ -680,6 +676,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ ├─────────────────────────────────────────────────────────────────────────────────────────┤ @@ -715,6 +712,7 @@ │ share: nil, │ │ _isDeleted: false, │ │ hasLastKnownServerRecord: true, │ + │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ └─────────────────────────────────────────────────────────────────────────────────────────┘ From 18acc61abb7caf3bd57f2650e228d8d1e47de81a Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 12 Jan 2026 11:01:41 -0600 Subject: [PATCH 06/11] fix --- Sources/SQLiteData/CloudKit/SyncMetadata.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SQLiteData/CloudKit/SyncMetadata.swift b/Sources/SQLiteData/CloudKit/SyncMetadata.swift index 623539e5..855d4e74 100644 --- a/Sources/SQLiteData/CloudKit/SyncMetadata.swift +++ b/Sources/SQLiteData/CloudKit/SyncMetadata.swift @@ -137,7 +137,7 @@ // NB: Workaround for https://github.com/groue/GRDB.swift/discussions/1844 public var isShared: some QueryExpression { #sql(""" - (\(self._isShared) = 1) AND (\(self.share) OR 1)) + ((\(self._isShared) = 1) AND (\(self.share) OR 1)) """) } } From 6ad28c9df68b72f42abde8a8d7347ef4f6f4492a Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 12 Jan 2026 11:02:45 -0600 Subject: [PATCH 07/11] fix --- .../CloudKitTests/SharingTests.swift | 70 ++++++++++++++++--- .../SyncEngineLifecycleTests.swift | 12 +++- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift index 7be0f4e4..798a9464 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift @@ -1459,7 +1459,36 @@ ), sharedCloudDatabase: MockCloudDatabase( databaseScope: .shared, - storage: [] + storage: [ + [0]: CKRecord( + recordID: CKRecord.ID(1:reminders/external.zone/external.owner), + recordType: "reminders", + parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)), + share: nil, + id: 1, + isCompleted: 0, + remindersListID: 1, + title: "Get milk" + ), + [1]: CKRecord( + recordID: CKRecord.ID(2:reminders/external.zone/external.owner), + recordType: "reminders", + parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)), + share: nil, + id: 2, + isCompleted: 0, + remindersListID: 1, + title: "Take a walk" + ), + [2]: CKRecord( + recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner), + recordType: "remindersLists", + parent: nil, + share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner)), + id: 1, + title: "Personal" + ) + ] ) ) """ @@ -1541,7 +1570,33 @@ ), sharedCloudDatabase: MockCloudDatabase( databaseScope: .shared, - storage: [] + storage: [ + [0]: CKRecord( + recordID: CKRecord.ID(1:modelAs/external.zone/external.owner), + recordType: "modelAs", + parent: nil, + share: CKReference(recordID: CKRecord.ID(share-1:modelAs/external.zone/external.owner)), + count: 42 + ), + [1]: CKRecord( + recordID: CKRecord.ID(1:modelBs/external.zone/external.owner), + recordType: "modelBs", + parent: CKReference(recordID: CKRecord.ID(1:modelAs/external.zone/external.owner)), + share: nil, + id: 1, + isOn: 1, + modelAID: 1 + ), + [2]: CKRecord( + recordID: CKRecord.ID(1:modelCs/external.zone/external.owner), + recordType: "modelCs", + parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)), + share: nil, + id: 1, + modelBID: 1, + title: "Hello world!" + ) + ] ) ) """ @@ -3122,14 +3177,9 @@ assertQuery(SyncMetadata.select(\.share), database: syncEngine.metadatabase) { """ - ┌────────────────────────────────────────────────────────────────────────┐ - │ CKRecord( │ - │ recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__), │ - │ recordType: "cloudkit.share", │ - │ parent: nil, │ - │ share: nil │ - │ ) │ - └────────────────────────────────────────────────────────────────────────┘ + ┌─────┐ + │ nil │ + └─────┘ """ } assertInlineSnapshot(of: container, as: .customDump) { diff --git a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift index 0fb2131f..b213ad06 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift @@ -491,7 +491,17 @@ ), sharedCloudDatabase: MockCloudDatabase( databaseScope: .shared, - storage: [] + storage: [ + [0]: CKRecord( + recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner), + recordType: "remindersLists", + parent: nil, + share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner)), + id: 1, + isCompleted: 0, + title: "Personal" + ) + ] ) ) """ From d410d18d723bb297b095c5831ca2eafee119dd86 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Mon, 12 Jan 2026 11:40:24 -0600 Subject: [PATCH 08/11] update hasLastKnownServerRecord" --- .../SQLiteData/CloudKit/SyncMetadata.swift | 17 +++++-- .../CloudKitTests/AccountLifecycleTests.swift | 16 +++--- .../AttachedMetadatabaseTests.swift | 2 +- .../FetchRecordZoneChangesTests.swift | 6 +-- .../CloudKitTests/MetadataTests.swift | 24 ++++----- .../CloudKitTests/SharingTests.swift | 50 +++++++++---------- .../SyncEngineDelegateTests.swift | 4 +- .../SyncEngineLifecycleTests.swift | 16 +++--- 8 files changed, 73 insertions(+), 62 deletions(-) diff --git a/Sources/SQLiteData/CloudKit/SyncMetadata.swift b/Sources/SQLiteData/CloudKit/SyncMetadata.swift index 855d4e74..00d427d7 100644 --- a/Sources/SQLiteData/CloudKit/SyncMetadata.swift +++ b/Sources/SQLiteData/CloudKit/SyncMetadata.swift @@ -97,8 +97,8 @@ /// next batch of pending changes is processed. public let _isDeleted: Bool - @Column(generated: .virtual) - public let hasLastKnownServerRecord: Bool + @Column("hasLastKnownServerRecord", generated: .virtual) + public let _hasLastKnownServerRecord: Bool @Column("isShared", generated: .virtual) fileprivate let _isShared: Bool @@ -106,6 +106,10 @@ /// The time the user last modified the record. public let userModificationTime: Int64 + public var hasLastKnownServerRecord: Bool { + lastKnownServerRecord != nil + } + /// Determines if the record associated with this metadata is currently shared in CloudKit. /// /// This can only return `true` for root records. For example, the metadata associated with a @@ -140,6 +144,13 @@ ((\(self._isShared) = 1) AND (\(self.share) OR 1)) """) } + + // NB: Workaround for https://github.com/groue/GRDB.swift/discussions/1844 + public var hasLastKnownServerRecord: some QueryExpression { + #sql(""" + ((\(self._hasLastKnownServerRecord) = 1) AND (\(self.lastKnownServerRecord) OR 1)) + """) + } } @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) @@ -173,8 +184,8 @@ self.lastKnownServerRecord = lastKnownServerRecord self._lastKnownServerRecordAllFields = _lastKnownServerRecordAllFields self.share = share + self._hasLastKnownServerRecord = lastKnownServerRecord != nil self._isShared = share != nil - self.hasLastKnownServerRecord = lastKnownServerRecord != nil self.userModificationTime = userModificationTime self._isDeleted = false } diff --git a/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift b/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift index 28a6097c..c90130db 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift @@ -171,7 +171,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -193,7 +193,7 @@ │ _lastKnownServerRecordAllFields: nil, │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: false, │ + │ _hasLastKnownServerRecord: false, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -257,7 +257,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -293,7 +293,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -421,7 +421,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -443,7 +443,7 @@ │ _lastKnownServerRecordAllFields: nil, │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: false, │ + │ _hasLastKnownServerRecord: false, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -518,7 +518,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -554,7 +554,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ diff --git a/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift b/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift index cfe9fd78..1d13ead2 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/AttachedMetadatabaseTests.swift @@ -56,7 +56,7 @@ │ │ ), │ │ │ share: nil, │ │ │ _isDeleted: false, │ - │ │ hasLastKnownServerRecord: true, │ + │ │ _hasLastKnownServerRecord: true, │ │ │ _isShared: false, │ │ │ userModificationTime: 0 │ │ │ ) │ diff --git a/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift b/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift index 8d348750..207728c7 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift @@ -546,7 +546,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -629,7 +629,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -699,7 +699,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ diff --git a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift index 133a4311..f37dfb4c 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift @@ -235,7 +235,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -271,7 +271,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -302,7 +302,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -334,7 +334,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -370,7 +370,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -401,7 +401,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -433,7 +433,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -469,7 +469,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -499,7 +499,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -529,7 +529,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -582,7 +582,7 @@ │ │ ), │ │ │ share: nil, │ │ │ _isDeleted: false, │ - │ │ hasLastKnownServerRecord: true, │ + │ │ _hasLastKnownServerRecord: true, │ │ │ _isShared: false, │ │ │ userModificationTime: 0 │ │ │ ) │ @@ -613,7 +613,7 @@ │ │ ), │ │ │ share: nil, │ │ │ _isDeleted: false, │ - │ │ hasLastKnownServerRecord: true, │ + │ │ _hasLastKnownServerRecord: true, │ │ │ _isShared: false, │ │ │ userModificationTime: 0 │ │ │ ) │ diff --git a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift index 798a9464..4f31673a 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift @@ -501,7 +501,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -584,7 +584,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -619,7 +619,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 60 │ │ ) │ @@ -654,7 +654,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 60 │ │ ) │ @@ -1169,7 +1169,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -1205,7 +1205,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -1850,7 +1850,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -1886,7 +1886,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -1921,7 +1921,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 1 │ │ ) │ @@ -1956,7 +1956,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -2155,7 +2155,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -2191,7 +2191,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -2226,7 +2226,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -2261,7 +2261,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -2460,7 +2460,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -2496,7 +2496,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -2531,7 +2531,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -2566,7 +2566,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -2745,7 +2745,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -2781,7 +2781,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -2816,7 +2816,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 1 │ │ ) │ @@ -2988,7 +2988,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -3024,7 +3024,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -3059,7 +3059,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 1 │ │ ) │ @@ -3094,7 +3094,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ diff --git a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift index 8828275e..40c55eaf 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineDelegateTests.swift @@ -64,7 +64,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -138,7 +138,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ diff --git a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift index b213ad06..7b720c2e 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift @@ -49,7 +49,7 @@ │ _lastKnownServerRecordAllFields: nil, │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: false, │ + │ _hasLastKnownServerRecord: false, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -71,7 +71,7 @@ │ _lastKnownServerRecordAllFields: nil, │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: false, │ + │ _hasLastKnownServerRecord: false, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -329,7 +329,7 @@ │ share: nil │ │ ), │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: true, │ │ userModificationTime: 0 │ │ ) │ @@ -351,7 +351,7 @@ │ _lastKnownServerRecordAllFields: nil, │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: false, │ + │ _hasLastKnownServerRecord: false, │ │ _isShared: false, │ │ userModificationTime: 60 │ │ ) │ @@ -607,7 +607,7 @@ │ _lastKnownServerRecordAllFields: nil, │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: false, │ + │ _hasLastKnownServerRecord: false, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -629,7 +629,7 @@ │ _lastKnownServerRecordAllFields: nil, │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: false, │ + │ _hasLastKnownServerRecord: false, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -685,7 +685,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ @@ -721,7 +721,7 @@ │ ), │ │ share: nil, │ │ _isDeleted: false, │ - │ hasLastKnownServerRecord: true, │ + │ _hasLastKnownServerRecord: true, │ │ _isShared: false, │ │ userModificationTime: 0 │ │ ) │ From 2d01e9c207f17a4ee692f31003fd7af6b23f17de Mon Sep 17 00:00:00 2001 From: Brandon Williams <135203+mbrandonw@users.noreply.github.com> Date: Mon, 12 Jan 2026 15:06:42 -0600 Subject: [PATCH 09/11] Update Sources/SQLiteData/CloudKit/SyncMetadata.swift Co-authored-by: Stephen Celis --- Sources/SQLiteData/CloudKit/SyncMetadata.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SQLiteData/CloudKit/SyncMetadata.swift b/Sources/SQLiteData/CloudKit/SyncMetadata.swift index 00d427d7..783c69d2 100644 --- a/Sources/SQLiteData/CloudKit/SyncMetadata.swift +++ b/Sources/SQLiteData/CloudKit/SyncMetadata.swift @@ -116,7 +116,7 @@ /// `RemindersList` can have `isShared == true`, but a `Reminder` associated with the list /// will have `isShared == false`. public var isShared: Bool { - share != nil + _isShared } } From bf84eeadb516b83b301373eb23c497dd2298ae5f Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Mon, 12 Jan 2026 13:10:13 -0800 Subject: [PATCH 10/11] format --- Examples/SyncUps/App.swift | 2 +- Sources/SQLiteData/CloudKit/SyncEngine.swift | 8 +++++--- Sources/SQLiteData/CloudKit/SyncMetadata.swift | 16 ++++++++++------ .../CloudKitTests/MetadataTests.swift | 9 ++++----- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Examples/SyncUps/App.swift b/Examples/SyncUps/App.swift index cf6da384..fe5426f7 100644 --- a/Examples/SyncUps/App.swift +++ b/Examples/SyncUps/App.swift @@ -66,7 +66,7 @@ struct AppView: View { switch path { case .detail(let model): SyncUpDetailView(model: model) - case .meeting(let meeting, attendees: let attendees): + case .meeting(let meeting, let attendees): MeetingView(meeting: meeting, attendees: attendees) case .record(let model): RecordMeetingView(model: model) diff --git a/Sources/SQLiteData/CloudKit/SyncEngine.swift b/Sources/SQLiteData/CloudKit/SyncEngine.swift index 68bc6cf0..a6c77d35 100644 --- a/Sources/SQLiteData/CloudKit/SyncEngine.swift +++ b/Sources/SQLiteData/CloudKit/SyncEngine.swift @@ -1502,7 +1502,8 @@ } var unsyncedRecords: [CKRecord] = [] for start in stride(from: 0, to: orderedUnsyncedRecordIDs.count, by: batchSize) { - let recordIDsBatch = orderedUnsyncedRecordIDs + let recordIDsBatch = + orderedUnsyncedRecordIDs .dropFirst(start) .prefix(batchSize) let results = try await syncEngine.database.records(for: Array(recordIDsBatch)) @@ -1586,7 +1587,7 @@ return false case (_, nil): return true - case let (.some(lhs), .some(rhs)): + case (.some(let lhs), .some(let rhs)): let lhsIndex = tablesByOrder[lhs] ?? (rootFirst ? .max : .min) let rhsIndex = tablesByOrder[rhs] ?? (rootFirst ? .max : .min) guard lhsIndex != rhsIndex @@ -2328,7 +2329,8 @@ tablesByName: [String: any SynchronizableTable] ) throws -> [String: Int] { let tableDependencies = try userDatabase.read { db in - var dependencies: OrderedDictionary = [:] + var dependencies: OrderedDictionary = + [:] for table in tables { func open(_: some SynchronizableTable) throws -> [String] { try PragmaForeignKeyList diff --git a/Sources/SQLiteData/CloudKit/SyncMetadata.swift b/Sources/SQLiteData/CloudKit/SyncMetadata.swift index 783c69d2..b1a21b06 100644 --- a/Sources/SQLiteData/CloudKit/SyncMetadata.swift +++ b/Sources/SQLiteData/CloudKit/SyncMetadata.swift @@ -140,16 +140,20 @@ // NB: Workaround for https://github.com/groue/GRDB.swift/discussions/1844 public var isShared: some QueryExpression { - #sql(""" - ((\(self._isShared) = 1) AND (\(self.share) OR 1)) - """) + #sql( + """ + ((\(self._isShared) = 1) AND (\(self.share) OR 1)) + """ + ) } // NB: Workaround for https://github.com/groue/GRDB.swift/discussions/1844 public var hasLastKnownServerRecord: some QueryExpression { - #sql(""" - ((\(self._hasLastKnownServerRecord) = 1) AND (\(self.lastKnownServerRecord) OR 1)) - """) + #sql( + """ + ((\(self._hasLastKnownServerRecord) = 1) AND (\(self.lastKnownServerRecord) OR 1)) + """ + ) } } diff --git a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift index f37dfb4c..0f58f0d6 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift @@ -682,9 +682,8 @@ } } - -@Selection struct RecordNameAndIsShared: Equatable { - let recordName: String - let isShared: Bool -} + @Selection struct RecordNameAndIsShared: Equatable { + let recordName: String + let isShared: Bool + } #endif From ded055720107cb272ec34c6924b32e251d559ad9 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Mon, 12 Jan 2026 13:11:54 -0800 Subject: [PATCH 11/11] consistent order --- Sources/SQLiteData/CloudKit/SyncMetadata.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/SQLiteData/CloudKit/SyncMetadata.swift b/Sources/SQLiteData/CloudKit/SyncMetadata.swift index b1a21b06..22990098 100644 --- a/Sources/SQLiteData/CloudKit/SyncMetadata.swift +++ b/Sources/SQLiteData/CloudKit/SyncMetadata.swift @@ -139,19 +139,19 @@ } // NB: Workaround for https://github.com/groue/GRDB.swift/discussions/1844 - public var isShared: some QueryExpression { + public var hasLastKnownServerRecord: some QueryExpression { #sql( """ - ((\(self._isShared) = 1) AND (\(self.share) OR 1)) + ((\(self._hasLastKnownServerRecord) = 1) AND (\(self.lastKnownServerRecord) OR 1)) """ ) } // NB: Workaround for https://github.com/groue/GRDB.swift/discussions/1844 - public var hasLastKnownServerRecord: some QueryExpression { + public var isShared: some QueryExpression { #sql( """ - ((\(self._hasLastKnownServerRecord) = 1) AND (\(self.lastKnownServerRecord) OR 1)) + ((\(self._isShared) = 1) AND (\(self.share) OR 1)) """ ) }