Skip to content

Commit 20e9cd6

Browse files
authored
Improve SyncEngine.init (#113)
* Improve `SyncEngine.init` - Infer default cloud container using SwiftData - Statically require string identifier primary keyed tables * wip * wip
1 parent 939bf67 commit 20e9cd6

File tree

13 files changed

+138
-155
lines changed

13 files changed

+138
-155
lines changed

Examples/CloudKitDemo/CloudKitDemoApp.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,8 @@ struct CloudKitDemoApp: App {
3030
try! prepareDependencies {
3131
$0.defaultDatabase = try appDatabase()
3232
$0.defaultSyncEngine = try SyncEngine(
33-
container: CKContainer(identifier: "iCloud.co.pointfree.SQLiteData.demos.CloudKitDemo"),
34-
database: $0.defaultDatabase,
35-
tables: [
36-
Counter.self
37-
]
33+
for: $0.defaultDatabase,
34+
tables: Counter.self
3835
)
3936
}
4037
return true

Examples/CloudKitPlayground/CloudKitPlaygroundApp.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@ struct CloudKitPlaygroundApp: App {
1111
prepareDependencies {
1212
$0.defaultDatabase = try! appDatabase()
1313
$0.defaultSyncEngine = try! SyncEngine(
14-
container: CKContainer(
15-
identifier: "iCloud.co.pointfree.SQLiteData.demos.CloudKitPlayground"
16-
),
17-
database: $0.defaultDatabase,
18-
tables: [ModelA.self, ModelB.self, ModelC.self]
14+
for: $0.defaultDatabase,
15+
tables: ModelA.self, ModelB.self, ModelC.self
1916
)
2017
}
2118
}

Examples/CloudKitPlayground/Schema.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ func appDatabase() throws -> any DatabaseWriter {
2222
let database: any DatabaseWriter
2323
var configuration = Configuration()
2424
configuration.prepareDatabase { db in
25-
try db.attachMetadatabase(
26-
containerIdentifier: "iCloud.co.pointfree.SQLiteData.demos.CloudKitPlayground"
27-
)
25+
try db.attachMetadatabase()
2826
#if DEBUG
2927
db.trace(options: .profile) {
3028
if context == .live {

Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 10 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Examples/Reminders/RemindersApp.swift

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import CloudKit
22
import SharingGRDB
33
import SwiftUI
4+
import UIKit
45

56
@main
67
struct RemindersApp: App {
@@ -13,17 +14,12 @@ struct RemindersApp: App {
1314
try! prepareDependencies {
1415
$0.defaultDatabase = try Reminders.appDatabase()
1516
$0.defaultSyncEngine = try SyncEngine(
16-
container: CKContainer(
17-
identifier: "iCloud.co.pointfree.SQLiteData.demos.field-timestamps-2.Reminders"
18-
),
19-
database: $0.defaultDatabase,
20-
tables: [
21-
RemindersList.self,
22-
RemindersListAsset.self,
23-
Reminder.self,
24-
Tag.self,
25-
ReminderTag.self,
26-
]
17+
for: $0.defaultDatabase,
18+
tables: RemindersList.self,
19+
RemindersListAsset.self,
20+
Reminder.self,
21+
Tag.self,
22+
ReminderTag.self
2723
)
2824
}
2925
}
@@ -40,9 +36,6 @@ struct RemindersApp: App {
4036
}
4137
}
4238

43-
44-
import UIKit
45-
4639
class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject {
4740
func application(
4841
_ application: UIApplication,

Examples/Reminders/Schema.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,7 @@ func appDatabase() throws -> any DatabaseWriter {
105105
let database: any DatabaseWriter
106106
var configuration = Configuration()
107107
configuration.prepareDatabase { db in
108-
try db.attachMetadatabase(
109-
containerIdentifier: "iCloud.co.pointfree.SQLiteData.demos.field-timestamps-2.Reminders"
110-
)
108+
try db.attachMetadatabase()
111109
#if DEBUG
112110
db.trace(options: .profile) {
113111
if context == .live {

README.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,8 @@ struct MyApp: App {
260260
prepareDependencies {
261261
$0.defaultDatabase = try! appDatabase()
262262
$0.defaultSyncEngine = SyncEngine(
263-
container: CKContainer(
264-
identifier: "iCloud.co.mycompany.MyApp"
265-
),
266-
database: $0.defaultDatabase,
267-
tables: [
268-
Item.self,
269-
]
263+
for: $0.defaultDatabase,
264+
tables: Item.self
270265
)
271266
}
272267
}
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
#if canImport(CloudKit)
2-
import CloudKit
3-
import Dependencies
4-
import GRDB
2+
import CloudKit
3+
import Dependencies
4+
import GRDB
55

6-
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
7-
extension DependencyValues {
8-
public var defaultSyncEngine: SyncEngine {
9-
get { self[SyncEngine.self] }
10-
set { self[SyncEngine.self] = newValue }
6+
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
7+
extension DependencyValues {
8+
public var defaultSyncEngine: SyncEngine {
9+
get { self[SyncEngine.self] }
10+
set { self[SyncEngine.self] = newValue }
11+
}
1112
}
12-
}
1313

14-
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
15-
extension SyncEngine: TestDependencyKey {
16-
public static var testValue: SyncEngine {
17-
try! SyncEngine(container: .default(), database: DatabaseQueue(), tables: [])
14+
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
15+
extension SyncEngine: TestDependencyKey {
16+
public static var testValue: SyncEngine {
17+
try! SyncEngine(for: DatabaseQueue())
18+
}
1819
}
19-
}
2020
#endif

Sources/SharingGRDBCore/CloudKit/SyncEngine.swift

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import CustomDump
55
import OrderedCollections
66
import OSLog
7+
import StructuredQueriesCore
8+
import SwiftData
79

810
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
911
public final class SyncEngine: Sendable {
@@ -24,14 +26,41 @@
2426

2527
let dataManager = Dependency(\.dataManager)
2628

27-
public convenience init(
28-
container: CKContainer,
29+
public convenience init<each T1: PrimaryKeyedTable, each T2: PrimaryKeyedTable>(
30+
for database: any DatabaseWriter,
31+
tables: repeat (each T1).Type,
32+
privateTables: repeat (each T2).Type,
33+
containerIdentifier: String? = nil,
2934
defaultZone: CKRecordZone = CKRecordZone(zoneName: "co.pointfree.SQLiteData.defaultZone"),
30-
database: any DatabaseWriter,
31-
logger: Logger = Logger(subsystem: "SQLiteData", category: "CloudKit"),
32-
tables: [any PrimaryKeyedTable.Type],
33-
privateTables: [any PrimaryKeyedTable.Type] = []
34-
) throws {
35+
logger: Logger = Logger(subsystem: "SQLiteData", category: "CloudKit")
36+
) throws
37+
where
38+
repeat (each T1).PrimaryKey.QueryOutput: IdentifierStringConvertible,
39+
repeat (each T2).PrimaryKey.QueryOutput: IdentifierStringConvertible
40+
{
41+
let containerIdentifier = containerIdentifier
42+
?? ModelConfiguration(groupContainer: .automatic).cloudKitContainerIdentifier
43+
44+
guard let containerIdentifier else {
45+
throw SchemaError(
46+
reason: .noCloudKitContainer,
47+
debugDescription: """
48+
No default CloudKit container found. Please add a container identifier to your app's \
49+
entitlements.
50+
"""
51+
)
52+
}
53+
54+
let container = CKContainer(identifier: containerIdentifier)
55+
var allTables: [any PrimaryKeyedTable.Type] = []
56+
var allPrivateTables: [any PrimaryKeyedTable.Type] = []
57+
for table in repeat each tables {
58+
allTables.append(table)
59+
}
60+
for privateTable in repeat each privateTables {
61+
allPrivateTables.append(privateTable)
62+
}
63+
3564
let userDatabase = UserDatabase(database: database)
3665
try self.init(
3766
container: container,
@@ -66,8 +95,8 @@
6695
},
6796
userDatabase: userDatabase,
6897
logger: logger,
69-
tables: tables,
70-
privateTables: privateTables
98+
tables: allTables,
99+
privateTables: allPrivateTables
71100
)
72101
_ = try setUpSyncEngine(
73102
userDatabase: userDatabase,
@@ -1483,7 +1512,7 @@
14831512
/// func appDatabase() -> any DatabaseWriter {
14841513
/// var configuration = Configuration()
14851514
/// configuration.prepareDatabase = { db in
1486-
/// db.attachMetadatabase(containerIdentifier: "iCloud.my.company.MyApp")
1515+
/// db.attachMetadatabase()
14871516
/// …
14881517
/// }
14891518
/// }
@@ -1493,7 +1522,20 @@
14931522
///
14941523
/// - Parameter containerIdentifier: The identifier of the CloudKit container used to synchronize
14951524
/// data.
1496-
public func attachMetadatabase(containerIdentifier: String) throws {
1525+
public func attachMetadatabase(containerIdentifier: String? = nil) throws {
1526+
let containerIdentifier = containerIdentifier
1527+
?? ModelConfiguration(groupContainer: .automatic).cloudKitContainerIdentifier
1528+
1529+
guard let containerIdentifier else {
1530+
throw SyncEngine.SchemaError(
1531+
reason: .noCloudKitContainer,
1532+
debugDescription: """
1533+
No default CloudKit container found. Please add a container identifier to your app's \
1534+
entitlements.
1535+
"""
1536+
)
1537+
}
1538+
14971539
let databasePath = try SQLQueryExpression(
14981540
"""
14991541
SELECT "file" FROM pragma_database_list()
@@ -1539,6 +1581,7 @@
15391581
case invalidForeignKeyAction(ForeignKey)
15401582
case invalidTableName(String)
15411583
case metadatabaseMismatch(attachedPath: String, syncEngineConfiguredPath: String)
1584+
case noCloudKitContainer
15421585
case nonNullColumnsWithoutDefault(tableName: String, columnNames: [String])
15431586
case triggersWithoutSynchronizationCheck([String])
15441587
case unknown

0 commit comments

Comments
 (0)