From 9acb0bd1a2f191c5a0332d26eb180b8833b23438 Mon Sep 17 00:00:00 2001 From: bymohamedali Date: Fri, 20 Mar 2026 19:17:38 +0400 Subject: [PATCH] Add metadatabase URL override for CloudKit sync --- .../CloudKit/Internal/Metadatabase.swift | 10 ++-- Sources/SQLiteData/CloudKit/SyncEngine.swift | 46 +++++++++++++------ 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/Sources/SQLiteData/CloudKit/Internal/Metadatabase.swift b/Sources/SQLiteData/CloudKit/Internal/Metadatabase.swift index c8efa856..4089f38f 100644 --- a/Sources/SQLiteData/CloudKit/Internal/Metadatabase.swift +++ b/Sources/SQLiteData/CloudKit/Internal/Metadatabase.swift @@ -13,10 +13,12 @@ open "\(url.path(percentEncoded: false))" """ ) - try FileManager.default.createDirectory( - at: .applicationSupportDirectory, - withIntermediateDirectories: true - ) + if !url.isInMemory { + try FileManager.default.createDirectory( + at: url.deletingLastPathComponent(), + withIntermediateDirectories: true + ) + } @Dependency(\.context) var context guard !url.isInMemory || context != .live diff --git a/Sources/SQLiteData/CloudKit/SyncEngine.swift b/Sources/SQLiteData/CloudKit/SyncEngine.swift index 871c7999..a2889196 100644 --- a/Sources/SQLiteData/CloudKit/SyncEngine.swift +++ b/Sources/SQLiteData/CloudKit/SyncEngine.swift @@ -75,6 +75,8 @@ /// you do not want to be shareable with other users. /// - containerIdentifier: The container identifier in CloudKit to synchronize to. If omitted /// the container will be determined from the entitlements of your app. + /// - metadatabaseURL: The location of the metadata database used to track CloudKit sync + /// state. If omitted, a default location is derived from the main database path. /// - defaultZone: The zone for all records to be stored in. /// - startImmediately: Determines if the sync engine starts right away or requires an /// explicit call to ``start()``. By default this argument is `true`. @@ -90,6 +92,7 @@ tables: repeat (each T1).Type, privateTables: repeat (each T2).Type, containerIdentifier: String? = nil, + metadatabaseURL: URL? = nil, defaultZone: CKRecordZone = CKRecordZone(zoneName: "co.pointfree.SQLiteData.defaultZone"), startImmediately: Bool? = nil, delegate: (any SyncEngineDelegate)? = nil, @@ -146,6 +149,7 @@ ) }, userDatabase: userDatabase, + metadatabaseURL: metadatabaseURL, logger: logger, delegate: delegate, tables: allTables, @@ -195,6 +199,7 @@ ) }, userDatabase: userDatabase, + metadatabaseURL: metadatabaseURL, logger: logger, delegate: delegate, tables: allTables, @@ -215,6 +220,7 @@ SyncEngine ) -> (private: any SyncEngineProtocol, shared: any SyncEngineProtocol), userDatabase: UserDatabase, + metadatabaseURL: URL? = nil, logger: Logger, delegate: (any SyncEngineDelegate)?, tables: [any SynchronizableTable], @@ -258,12 +264,15 @@ self.defaultSyncEngines = defaultSyncEngines self.userDatabase = userDatabase self.logger = logger - self.metadatabase = try defaultMetadatabase( - logger: logger, - url: try URL.metadatabase( + let resolvedMetadatabaseURL = + try metadatabaseURL + ?? URL.metadatabase( databasePath: userDatabase.path, containerIdentifier: container.containerIdentifier ) + self.metadatabase = try defaultMetadatabase( + logger: logger, + url: resolvedMetadatabaseURL ) self.tablesByName = Dictionary( uniqueKeysWithValues: self.tables.map { ($0.base.tableName, $0) } @@ -2211,9 +2220,15 @@ /// /// See for more information on preparing your database. /// - /// - Parameter containerIdentifier: The identifier of the CloudKit container used to - /// synchronize data. Defaults to the value set in the app's entitlements. - public func attachMetadatabase(containerIdentifier: String? = nil) throws { + /// - Parameters: + /// - containerIdentifier: The identifier of the CloudKit container used to + /// synchronize data. Defaults to the value set in the app's entitlements. + /// - metadatabaseURL: The location of the attached metadata database. If omitted, a default + /// location is derived from the main database path. + public func attachMetadatabase( + containerIdentifier: String? = nil, + metadatabaseURL: URL? = nil + ) throws { @Dependency(\.context) var context let containerIdentifier = containerIdentifier @@ -2234,15 +2249,18 @@ """ ) } - let url = try URL.metadatabase( - databasePath: databasePath, - containerIdentifier: containerIdentifier - ) + let url = try metadatabaseURL + ?? URL.metadatabase( + databasePath: databasePath, + containerIdentifier: containerIdentifier + ) let path = url.isInMemory ? url.absoluteString : url.path(percentEncoded: false) - try FileManager.default.createDirectory( - at: .applicationSupportDirectory, - withIntermediateDirectories: true - ) + if !url.isInMemory { + try FileManager.default.createDirectory( + at: url.deletingLastPathComponent(), + withIntermediateDirectories: true + ) + } let database: any DatabaseWriter = url.isInMemory ? try DatabaseQueue(path: path)