Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions Sources/SQLiteData/CloudKit/CloudKitSharing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,24 +118,27 @@
)
}
let recordName = record.recordName
let lastKnownServerRecord =
try await metadatabase.read { db in
let lastKnownServerRecord = try await {
let lastKnownServerRecord = try await metadatabase.read { db in
try SyncMetadata
.where { $0.recordName.eq(recordName) }
.select(\._lastKnownServerRecordAllFields)
.fetchOne(db)
} ?? nil
guard let lastKnownServerRecord
else {
throw SharingError(
recordTableName: T.tableName,
recordPrimaryKey: record.primaryKey.rawIdentifier,
reason: .recordMetadataNotFound,
debugDescription: """
guard let lastKnownServerRecord
else {
throw SharingError(
recordTableName: T.tableName,
recordPrimaryKey: record.primaryKey.rawIdentifier,
reason: .recordMetadataNotFound,
debugDescription: """
No sync metadata found for record. Has the record been saved to the database?
"""
)
}
)
}
return try await container.database(for: lastKnownServerRecord.recordID)
.record(for: lastKnownServerRecord.recordID)
}()

var existingShare: CKShare? {
get async throws {
Expand Down
12 changes: 12 additions & 0 deletions Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,18 @@
// TODO: This should merge copy's values to more accurately reflect reality
storage[recordToSave.recordID.zoneID]?.records[recordToSave.recordID] = copy
saveResults[recordToSave.recordID] = .success(copy)

// NB: "Touch" parent records when saving a child:
if let parent = recordToSave.parent,
// If the parent isn't also being saved in this batch.
!recordsToSave.contains(where: { $0.recordID == parent.recordID }),
// And if the parent is in the database.
let parentRecord = storage[parent.recordID.zoneID]?.records[parent.recordID]?.copy()
as? CKRecord
{
parentRecord._recordChangeTag = UUID().uuidString
storage[parent.recordID.zoneID]?.records[parent.recordID] = parentRecord
}
Comment on lines +193 to +203
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes the mock cloud database behave more like CloudKit. And this change alone made some tests fail.

}

switch (existingRecord, recordToSave._recordChangeTag) {
Expand Down
81 changes: 81 additions & 0 deletions Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,87 @@
}
}

/*
* Create parent record and synchronize.
* Create child record and synchronize.
* Share parent record.
*/
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
@Test(.bug("https://github.com/pointfreeco/sqlite-data/pull/363"))
func createParentThenChildThenShare() 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)

let reminder = Reminder(id: 1, title: "Groceries", remindersListID: 1)
try await userDatabase.userWrite { db in
try db.seed { reminder }
}
try await syncEngine.processPendingRecordZoneChanges(scope: .private)

let _ = try await syncEngine.share(record: remindersList, configure: { _ in })

assertQuery(
SyncMetadata.select { ($0.share, $0.userModificationTime) },
database: syncEngine.metadatabase
) {
"""
┌────────────────────────────────────────────────────────────────────────┬───┐
│ CKRecord( │ 0 │
│ recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__), │ │
│ recordType: "cloudkit.share", │ │
│ parent: nil, │ │
│ share: nil │ │
│ ) │ │
├────────────────────────────────────────────────────────────────────────┼───┤
│ nil │ 0 │
└────────────────────────────────────────────────────────────────────────┴───┘
"""
}

assertInlineSnapshot(of: container, as: .customDump) {
"""
MockCloudContainer(
privateCloudDatabase: MockCloudDatabase(
databaseScope: .private,
storage: [
[0]: CKRecord(
recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__),
recordType: "cloudkit.share",
parent: nil,
share: nil
),
[1]: CKRecord(
recordID: CKRecord.ID(1:reminders/zone/__defaultOwner__),
recordType: "reminders",
parent: CKReference(recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__)),
share: nil,
id: 1,
isCompleted: 0,
remindersListID: 1,
title: "Groceries"
),
[2]: CKRecord(
recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__),
recordType: "remindersLists",
parent: nil,
share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__)),
id: 1,
title: "Personal"
)
]
),
sharedCloudDatabase: MockCloudDatabase(
databaseScope: .shared,
storage: []
)
)
"""
}
}

@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
@Test func shareTwice() async throws {
let remindersList = RemindersList(id: 1, title: "Personal")
Expand Down