-
Notifications
You must be signed in to change notification settings - Fork 113
Use metadatabase to query sync metadata. #270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d198f7f
96b85de
891aa58
e28d9da
cab921b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #if canImport(CloudKit) | ||
| import CloudKit | ||
| import ConcurrencyExtras | ||
| import CustomDump | ||
| import InlineSnapshotTesting | ||
| import OrderedCollections | ||
| import SQLiteData | ||
| import SQLiteDataTestSupport | ||
| import SnapshotTestingCustomDump | ||
| import Testing | ||
|
|
||
| extension BaseCloudKitTests { | ||
| @MainActor | ||
| @Suite(.attachMetadatabase(true)) | ||
| final class AttachedMetadatabaseTests: BaseCloudKitTests, @unchecked Sendable { | ||
| @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) | ||
| @Test func basics() 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) | ||
|
|
||
| assertQuery( | ||
| RemindersList | ||
| .leftJoin(SyncMetadata.all) { $0.syncMetadataID.eq($1.id) }, | ||
| database: userDatabase.database | ||
| ) { | ||
| """ | ||
| ┌─────────────────────┬────────────────────────────────────────────────────────────────────┐ | ||
| │ RemindersList( │ SyncMetadata( │ | ||
| │ id: 1, │ id: SyncMetadata.ID( │ | ||
| │ title: "Personal" │ recordPrimaryKey: "1", │ | ||
| │ ) │ recordType: "remindersLists" │ | ||
| │ │ ), │ | ||
| │ │ zoneName: "zone", │ | ||
| │ │ ownerName: "__defaultOwner__", │ | ||
| │ │ recordName: "1:remindersLists", │ | ||
| │ │ parentRecordID: nil, │ | ||
| │ │ parentRecordName: nil, │ | ||
| │ │ lastKnownServerRecord: CKRecord( │ | ||
| │ │ recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__), │ | ||
| │ │ recordType: "remindersLists", │ | ||
| │ │ parent: nil, │ | ||
| │ │ share: nil │ | ||
| │ │ ), │ | ||
| │ │ _lastKnownServerRecordAllFields: CKRecord( │ | ||
| │ │ recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__), │ | ||
| │ │ recordType: "remindersLists", │ | ||
| │ │ parent: nil, │ | ||
| │ │ share: nil, │ | ||
| │ │ id: 1, │ | ||
| │ │ title: "Personal" │ | ||
| │ │ ), │ | ||
| │ │ share: nil, │ | ||
| │ │ _isDeleted: false, │ | ||
| │ │ hasLastKnownServerRecord: true, │ | ||
| │ │ isShared: false, │ | ||
| │ │ userModificationTime: 0 │ | ||
| │ │ ) │ | ||
| └─────────────────────┴────────────────────────────────────────────────────────────────────┘ | ||
| """ | ||
| } | ||
| } | ||
| } | ||
| } | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2753,6 +2753,52 @@ | |
| """ | ||
| } | ||
| } | ||
|
|
||
| @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) | ||
| @Test func deleteShare() async throws { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test was failing prior to the change made in this PR. |
||
| let remindersList = RemindersList(id: 1, title: "Personal") | ||
| try await userDatabase.userWrite { db in | ||
| try db.seed { | ||
| remindersList | ||
| } | ||
| } | ||
| try await syncEngine.processPendingRecordZoneChanges(scope: .private) | ||
|
|
||
| let sharedRecord = try await syncEngine.share(record: remindersList, configure: { _ in }) | ||
|
|
||
| try await syncEngine | ||
| .modifyRecords(scope: .private, deleting: [sharedRecord.share.recordID]) | ||
| .notify() | ||
|
|
||
| assertQuery(SyncMetadata.select(\.share), database: syncEngine.metadatabase) { | ||
| """ | ||
| ┌─────┐ | ||
| │ nil │ | ||
| └─────┘ | ||
| """ | ||
| } | ||
| assertInlineSnapshot(of: container, as: .customDump) { | ||
| """ | ||
| MockCloudContainer( | ||
| privateCloudDatabase: MockCloudDatabase( | ||
| databaseScope: .private, | ||
| storage: [ | ||
| [0]: CKRecord( | ||
| recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__), | ||
| recordType: "remindersLists", | ||
| parent: nil, | ||
| share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__)) | ||
| ) | ||
| ] | ||
| ), | ||
| sharedCloudDatabase: MockCloudDatabase( | ||
| databaseScope: .shared, | ||
| storage: [] | ||
| ) | ||
| ) | ||
| """ | ||
| } | ||
| } | ||
| } | ||
| } | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,8 @@ import os | |
| .dependencies { | ||
| $0.currentTime.now = 0 | ||
| $0.dataManager = InMemoryDataManager() | ||
| } | ||
| }, | ||
| .attachMetadatabase(false) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's not attach the metadatabase in tests by default, and instead opt into it explicitly. |
||
| ) | ||
| class BaseCloudKitTests: @unchecked Sendable { | ||
| let userDatabase: UserDatabase | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,9 +20,10 @@ extension PrimaryKeyedTable where PrimaryKey.QueryOutput: IdentifierStringConver | |
|
|
||
| @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) | ||
| extension SyncEngine { | ||
| struct ModifyRecordsCallback { | ||
| fileprivate let operation: @Sendable () async -> Void | ||
| func notify() async { | ||
| struct ModifyRecordsCallback<ReturnValue> { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently when we invoke |
||
| fileprivate let operation: @Sendable () async -> ReturnValue | ||
| @discardableResult | ||
| func notify() async -> ReturnValue { | ||
| await operation() | ||
| } | ||
| } | ||
|
|
@@ -31,7 +32,12 @@ extension SyncEngine { | |
| scope: CKDatabase.Scope, | ||
| saving recordZonesToSave: [CKRecordZone] = [], | ||
| deleting recordZoneIDsToDelete: [CKRecordZone.ID] = [] | ||
| ) throws -> ModifyRecordsCallback { | ||
| ) throws -> ModifyRecordsCallback< | ||
| ( | ||
| saveResults: [CKRecordZone.ID: Result<CKRecordZone, any Error>], | ||
| deleteResults: [CKRecordZone.ID: Result<Void, any Error>] | ||
| ) | ||
| > { | ||
| let syncEngine = syncEngine(for: scope) | ||
|
|
||
| let (saveResults, deleteResults) = try syncEngine.database.modifyRecordZones( | ||
|
|
@@ -52,14 +58,20 @@ extension SyncEngine { | |
| ), | ||
| syncEngine: syncEngine | ||
| ) | ||
| return (saveResults, deleteResults) | ||
| } | ||
| } | ||
|
|
||
| func modifyRecords( | ||
| scope: CKDatabase.Scope, | ||
| saving recordsToSave: [CKRecord] = [], | ||
| deleting recordIDsToDelete: [CKRecord.ID] = [] | ||
| ) throws -> ModifyRecordsCallback { | ||
| ) throws -> ModifyRecordsCallback< | ||
| ( | ||
| saveResults: [CKRecord.ID: Result<CKRecord, any Error>], | ||
| deleteResults: [CKRecord.ID: Result<Void, any Error>] | ||
| ) | ||
| > { | ||
| let syncEngine = syncEngine(for: scope) | ||
| let recordsToDeleteByID = Dictionary( | ||
| grouping: syncEngine.database.storage.withValue { storage in | ||
|
|
@@ -90,6 +102,7 @@ extension SyncEngine { | |
| ), | ||
| syncEngine: syncEngine | ||
| ) | ||
| return (saveResults, deleteResults) | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a new test suite to specifically test joining to the metadatabase when it is attached.