Skip to content

Commit e64d353

Browse files
authored
Fetch current record before sharing. (#363)
* Fetch current record before sharing. * add an explicit test * wip * Move bug url to bug trait.
1 parent b206f0b commit e64d353

3 files changed

Lines changed: 107 additions & 11 deletions

File tree

Sources/SQLiteData/CloudKit/CloudKitSharing.swift

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,24 +118,27 @@
118118
)
119119
}
120120
let recordName = record.recordName
121-
let lastKnownServerRecord =
122-
try await metadatabase.read { db in
121+
let lastKnownServerRecord = try await {
122+
let lastKnownServerRecord = try await metadatabase.read { db in
123123
try SyncMetadata
124124
.where { $0.recordName.eq(recordName) }
125125
.select(\._lastKnownServerRecordAllFields)
126126
.fetchOne(db)
127127
} ?? nil
128-
guard let lastKnownServerRecord
129-
else {
130-
throw SharingError(
131-
recordTableName: T.tableName,
132-
recordPrimaryKey: record.primaryKey.rawIdentifier,
133-
reason: .recordMetadataNotFound,
134-
debugDescription: """
128+
guard let lastKnownServerRecord
129+
else {
130+
throw SharingError(
131+
recordTableName: T.tableName,
132+
recordPrimaryKey: record.primaryKey.rawIdentifier,
133+
reason: .recordMetadataNotFound,
134+
debugDescription: """
135135
No sync metadata found for record. Has the record been saved to the database?
136136
"""
137-
)
138-
}
137+
)
138+
}
139+
return try await container.database(for: lastKnownServerRecord.recordID)
140+
.record(for: lastKnownServerRecord.recordID)
141+
}()
139142

140143
var existingShare: CKShare? {
141144
get async throws {

Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,18 @@
189189
// TODO: This should merge copy's values to more accurately reflect reality
190190
storage[recordToSave.recordID.zoneID]?.records[recordToSave.recordID] = copy
191191
saveResults[recordToSave.recordID] = .success(copy)
192+
193+
// NB: "Touch" parent records when saving a child:
194+
if let parent = recordToSave.parent,
195+
// If the parent isn't also being saved in this batch.
196+
!recordsToSave.contains(where: { $0.recordID == parent.recordID }),
197+
// And if the parent is in the database.
198+
let parentRecord = storage[parent.recordID.zoneID]?.records[parent.recordID]?.copy()
199+
as? CKRecord
200+
{
201+
parentRecord._recordChangeTag = UUID().uuidString
202+
storage[parent.recordID.zoneID]?.records[parent.recordID] = parentRecord
203+
}
192204
}
193205

194206
switch (existingRecord, recordToSave._recordChangeTag) {

Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,87 @@
847847
}
848848
}
849849

850+
/*
851+
* Create parent record and synchronize.
852+
* Create child record and synchronize.
853+
* Share parent record.
854+
*/
855+
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
856+
@Test(.bug("https://github.com/pointfreeco/sqlite-data/pull/363"))
857+
func createParentThenChildThenShare() async throws {
858+
let remindersList = RemindersList(id: 1, title: "Personal")
859+
try await userDatabase.userWrite { db in
860+
try db.seed { remindersList }
861+
}
862+
try await syncEngine.processPendingRecordZoneChanges(scope: .private)
863+
864+
let reminder = Reminder(id: 1, title: "Groceries", remindersListID: 1)
865+
try await userDatabase.userWrite { db in
866+
try db.seed { reminder }
867+
}
868+
try await syncEngine.processPendingRecordZoneChanges(scope: .private)
869+
870+
let _ = try await syncEngine.share(record: remindersList, configure: { _ in })
871+
872+
assertQuery(
873+
SyncMetadata.select { ($0.share, $0.userModificationTime) },
874+
database: syncEngine.metadatabase
875+
) {
876+
"""
877+
┌────────────────────────────────────────────────────────────────────────┬───┐
878+
│ CKRecord( │ 0 │
879+
│ recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__), │ │
880+
│ recordType: "cloudkit.share", │ │
881+
│ parent: nil, │ │
882+
│ share: nil │ │
883+
│ ) │ │
884+
├────────────────────────────────────────────────────────────────────────┼───┤
885+
│ nil │ 0 │
886+
└────────────────────────────────────────────────────────────────────────┴───┘
887+
"""
888+
}
889+
890+
assertInlineSnapshot(of: container, as: .customDump) {
891+
"""
892+
MockCloudContainer(
893+
privateCloudDatabase: MockCloudDatabase(
894+
databaseScope: .private,
895+
storage: [
896+
[0]: CKRecord(
897+
recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__),
898+
recordType: "cloudkit.share",
899+
parent: nil,
900+
share: nil
901+
),
902+
[1]: CKRecord(
903+
recordID: CKRecord.ID(1:reminders/zone/__defaultOwner__),
904+
recordType: "reminders",
905+
parent: CKReference(recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__)),
906+
share: nil,
907+
id: 1,
908+
isCompleted: 0,
909+
remindersListID: 1,
910+
title: "Groceries"
911+
),
912+
[2]: CKRecord(
913+
recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__),
914+
recordType: "remindersLists",
915+
parent: nil,
916+
share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__)),
917+
id: 1,
918+
title: "Personal"
919+
)
920+
]
921+
),
922+
sharedCloudDatabase: MockCloudDatabase(
923+
databaseScope: .shared,
924+
storage: []
925+
)
926+
)
927+
"""
928+
}
929+
}
930+
850931
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
851932
@Test func shareTwice() async throws {
852933
let remindersList = RemindersList(id: 1, title: "Personal")

0 commit comments

Comments
 (0)