From 3814a36c22e766e11f97e9306bf989d6cd255415 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 10 Sep 2025 09:52:34 -0500 Subject: [PATCH 1/7] Bring back other demo apps. --- .../AppIcon.appiconset/Contents.json | 50 ----- .../CloudKitDemo/CloudKitDemo.entitlements | 8 +- Examples/CloudKitDemo/CloudKitDemoApp.swift | 100 ++++----- .../CloudKitDemo/CountersListFeature.swift | 74 ++++--- Examples/CloudKitDemo/Info.plist | 9 - Examples/CloudKitDemo/Schema.swift | 77 ++++--- .../CloudKitDemoTests/CloudKitDemoTests.swift | 16 -- .../AccentColor.colorset/Contents.json | 11 - .../AppIcon.appiconset/Contents.json | 35 --- .../Assets.xcassets/Contents.json | 6 - .../CloudKitPlayground.entitlements | 16 -- .../CloudKitPlaygroundApp.swift | 78 ------- Examples/CloudKitPlayground/ContentView.swift | 24 --- Examples/CloudKitPlayground/Info.plist | 12 -- Examples/CloudKitPlayground/ModelAView.swift | 71 ------- Examples/CloudKitPlayground/ModelBView.swift | 73 ------- Examples/CloudKitPlayground/ModelCView.swift | 52 ----- Examples/CloudKitPlayground/Schema.swift | 88 -------- Examples/Examples.xcodeproj/project.pbxproj | 199 +++++++++++++++--- .../xcschemes/CloudKitDemo.xcscheme | 91 -------- 20 files changed, 295 insertions(+), 795 deletions(-) delete mode 100644 Examples/CloudKitDemoTests/CloudKitDemoTests.swift delete mode 100644 Examples/CloudKitPlayground/Assets.xcassets/AccentColor.colorset/Contents.json delete mode 100644 Examples/CloudKitPlayground/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 Examples/CloudKitPlayground/Assets.xcassets/Contents.json delete mode 100644 Examples/CloudKitPlayground/CloudKitPlayground.entitlements delete mode 100644 Examples/CloudKitPlayground/CloudKitPlaygroundApp.swift delete mode 100644 Examples/CloudKitPlayground/ContentView.swift delete mode 100644 Examples/CloudKitPlayground/Info.plist delete mode 100644 Examples/CloudKitPlayground/ModelAView.swift delete mode 100644 Examples/CloudKitPlayground/ModelBView.swift delete mode 100644 Examples/CloudKitPlayground/ModelCView.swift delete mode 100644 Examples/CloudKitPlayground/Schema.swift delete mode 100644 Examples/Examples.xcodeproj/xcshareddata/xcschemes/CloudKitDemo.xcscheme diff --git a/Examples/CloudKitDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/Examples/CloudKitDemo/Assets.xcassets/AppIcon.appiconset/Contents.json index ffdfe150..23058801 100644 --- a/Examples/CloudKitDemo/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Examples/CloudKitDemo/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -26,56 +26,6 @@ "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "16x16" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "32x32" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "128x128" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "256x256" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "256x256" - }, - { - "idiom" : "mac", - "scale" : "1x", - "size" : "512x512" - }, - { - "idiom" : "mac", - "scale" : "2x", - "size" : "512x512" } ], "info" : { diff --git a/Examples/CloudKitDemo/CloudKitDemo.entitlements b/Examples/CloudKitDemo/CloudKitDemo.entitlements index 5df5b1b1..d013bfc9 100644 --- a/Examples/CloudKitDemo/CloudKitDemo.entitlements +++ b/Examples/CloudKitDemo/CloudKitDemo.entitlements @@ -4,19 +4,13 @@ aps-environment development - com.apple.developer.aps-environment - development com.apple.developer.icloud-container-identifiers - iCloud.co.pointfree.SQLiteData.demos.CloudKitDemo + iCloud.co.pointfree.SQLiteData.CloudKitDemo com.apple.developer.icloud-services CloudKit - com.apple.security.app-sandbox - - com.apple.security.files.user-selected.read-only - diff --git a/Examples/CloudKitDemo/CloudKitDemoApp.swift b/Examples/CloudKitDemo/CloudKitDemoApp.swift index 40b628ce..aef2e449 100644 --- a/Examples/CloudKitDemo/CloudKitDemoApp.swift +++ b/Examples/CloudKitDemo/CloudKitDemoApp.swift @@ -2,15 +2,16 @@ import CloudKit import SQLiteData import SwiftUI -#if canImport - import UIKit -#endif - @main struct CloudKitDemoApp: App { - #if canImport(UIKit) - @UIApplicationDelegateAdaptor private var appDelegate: AppDelegate - #endif + @UIApplicationDelegateAdaptor private var appDelegate: AppDelegate + + init() { + try! prepareDependencies { + try $0.bootstrapDatabase() + } + } + var body: some Scene { WindowGroup { NavigationStack { @@ -20,62 +21,43 @@ struct CloudKitDemoApp: App { } } -#if canImport(UIKit) - class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject { - func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication - .LaunchOptionsKey: Any]? = nil - ) -> Bool { - try! prepareDependencies { - $0.defaultDatabase = try appDatabase() - $0.defaultSyncEngine = try SyncEngine( - for: $0.defaultDatabase, - tables: Counter.self - ) - } - return true - } - - func application( - _ application: UIApplication, - configurationForConnecting connectingSceneSession: UISceneSession, - options: UIScene.ConnectionOptions - ) -> UISceneConfiguration { - let configuration = UISceneConfiguration( - name: "Default Configuration", - sessionRole: connectingSceneSession.role - ) - configuration.delegateClass = SceneDelegate.self - return configuration - } +class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject { + func application( + _ application: UIApplication, + configurationForConnecting connectingSceneSession: UISceneSession, + options: UIScene.ConnectionOptions + ) -> UISceneConfiguration { + let configuration = UISceneConfiguration( + name: "Default Configuration", + sessionRole: connectingSceneSession.role + ) + configuration.delegateClass = SceneDelegate.self + return configuration } +} - class SceneDelegate: UIResponder, UIWindowSceneDelegate { - @Dependency(\.defaultSyncEngine) var syncEngine - var window: UIWindow? +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + @Dependency(\.defaultSyncEngine) var syncEngine + var window: UIWindow? - func windowScene( - _ windowScene: UIWindowScene, - userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata - ) { - Task { - try await syncEngine.acceptShare(metadata: cloudKitShareMetadata) - } + func windowScene( + _ windowScene: UIWindowScene, + userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata + ) { + Task { + try await syncEngine.acceptShare(metadata: cloudKitShareMetadata) } + } - func scene( - _ scene: UIScene, - willConnectTo session: UISceneSession, - options connectionOptions: UIScene.ConnectionOptions - ) { - guard let cloudKitShareMetadata = connectionOptions.cloudKitShareMetadata - else { - return - } - Task { - try await syncEngine.acceptShare(metadata: cloudKitShareMetadata) - } + func scene( + _ scene: UIScene, + willConnectTo session: UISceneSession, + options connectionOptions: UIScene.ConnectionOptions + ) { + guard let cloudKitShareMetadata = connectionOptions.cloudKitShareMetadata + else { return } + Task { + try await syncEngine.acceptShare(metadata: cloudKitShareMetadata) } } -#endif +} diff --git a/Examples/CloudKitDemo/CountersListFeature.swift b/Examples/CloudKitDemo/CountersListFeature.swift index a356784d..98b904e2 100644 --- a/Examples/CloudKitDemo/CountersListFeature.swift +++ b/Examples/CloudKitDemo/CountersListFeature.swift @@ -16,14 +16,7 @@ struct CountersListView: View { .buttonStyle(.borderless) } .onDelete { indexSet in - withErrorReporting { - try database.write { db in - for index in indexSet { - try Counter.find(counters[index].id).delete() - .execute(db) - } - } - } + deleteRows(at: indexSet) } } } @@ -42,6 +35,17 @@ struct CountersListView: View { } } } + + func deleteRows(at indexSet: IndexSet) { + withErrorReporting { + try database.write { db in + for index in indexSet { + try Counter.find(counters[index].id).delete() + .execute(db) + } + } + } + } } struct CounterRow: View { @@ -55,32 +59,14 @@ struct CounterRow: View { HStack { Text("\(counter.count)") Button("-") { - withErrorReporting { - try database.write { db in - try Counter.find(counter.id).update { - $0.count -= 1 - } - .execute(db) - } - } + decrementButtonTapped() } Button("+") { - withErrorReporting { - try database.write { db in - try Counter.find(counter.id).update { - $0.count += 1 - } - .execute(db) - } - } + incrementButtonTapped() } Spacer() Button { - Task { - sharedRecord = try await syncEngine.share(record: counter) { share in - share[CKShare.SystemFieldKey.title] = "Join my counter!" - } - } + shareButtonTapped() } label: { Image(systemName: "square.and.arrow.up") } @@ -90,4 +76,34 @@ struct CounterRow: View { CloudSharingView(sharedRecord: sharedRecord) } } + + func shareButtonTapped() { + Task { + sharedRecord = try await syncEngine.share(record: counter) { share in + share[CKShare.SystemFieldKey.title] = "Join my counter!" + } + } + } + + func decrementButtonTapped() { + withErrorReporting { + try database.write { db in + try Counter.find(counter.id).update { + $0.count -= 1 + } + .execute(db) + } + } + } + + func incrementButtonTapped() { + withErrorReporting { + try database.write { db in + try Counter.find(counter.id).update { + $0.count += 1 + } + .execute(db) + } + } + } } diff --git a/Examples/CloudKitDemo/Info.plist b/Examples/CloudKitDemo/Info.plist index 16fd2333..ca9a074a 100644 --- a/Examples/CloudKitDemo/Info.plist +++ b/Examples/CloudKitDemo/Info.plist @@ -2,15 +2,6 @@ - CKSharingSupported - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIBackgroundModes remote-notification diff --git a/Examples/CloudKitDemo/Schema.swift b/Examples/CloudKitDemo/Schema.swift index ca892d0d..f3e5fa87 100644 --- a/Examples/CloudKitDemo/Schema.swift +++ b/Examples/CloudKitDemo/Schema.swift @@ -8,57 +8,52 @@ struct Counter: Identifiable { var count = 0 } -func appDatabase() throws -> any DatabaseWriter { - @Dependency(\.context) var context - let database: any DatabaseWriter - var configuration = Configuration() - configuration.prepareDatabase { db in - try db.attachMetadatabase( - containerIdentifier: "iCloud.co.pointfree.SQLiteData.demos.CloudKitDemo") - #if DEBUG - db.trace(options: .profile) { - if context == .live { - logger.debug("\($0.expandedDescription)") - } else { - print("\($0.expandedDescription)") +extension DependencyValues { + mutating func bootstrapDatabase() throws { + @Dependency(\.context) var context + var configuration = Configuration() + configuration.prepareDatabase { db in + try db.attachMetadatabase() + #if DEBUG + db.trace(options: .profile) { + if context == .live { + logger.debug("\($0.expandedDescription)") + } else { + print("\($0.expandedDescription)") + } } - } - #endif - } - if context == .preview { - database = try DatabaseQueue(configuration: configuration) - } else { - let path = - context == .live - ? URL.documentsDirectory.appending(component: "db.sqlite").path() - : URL.temporaryDirectory.appending(component: "\(UUID().uuidString)-db.sqlite").path() + #endif + } + let database = try SQLiteData.defaultDatabase(configuration: configuration) logger.debug( """ App database - open "\(path)" + open "\(database.path)" """ ) - database = try DatabasePool(path: path, configuration: configuration) - } - var migrator = DatabaseMigrator() - #if DEBUG - migrator.eraseDatabaseOnSchemaChange = true - #endif - migrator.registerMigration("Create tables") { db in - try #sql( - """ - CREATE TABLE "counters" ( - "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), - "count" INT NOT NULL DEFAULT 0 + var migrator = DatabaseMigrator() + #if DEBUG + migrator.eraseDatabaseOnSchemaChange = true + #endif + migrator.registerMigration("Create tables") { db in + try #sql( + """ + CREATE TABLE "counters" ( + "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), + "count" INT NOT NULL ON CONFLICT REPLACE DEFAULT 0 + ) + """ ) - """ + .execute(db) + } + try migrator.migrate(database) + defaultDatabase = database + defaultSyncEngine = try SyncEngine( + for: defaultDatabase, + tables: Counter.self ) - .execute(db) } - try migrator.migrate(database) - - return database } private let logger = Logger(subsystem: "CloudKitDemo", category: "Database") diff --git a/Examples/CloudKitDemoTests/CloudKitDemoTests.swift b/Examples/CloudKitDemoTests/CloudKitDemoTests.swift deleted file mode 100644 index 76468d0e..00000000 --- a/Examples/CloudKitDemoTests/CloudKitDemoTests.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// CloudKitDemoTests.swift -// CloudKitDemoTests -// -// Created by Brandon Williams on 6/6/25. -// - -import Testing - -struct CloudKitDemoTests { - - @Test func example() async throws { - // Write your test here and use APIs like `#expect(...)` to check expected conditions. - } - -} diff --git a/Examples/CloudKitPlayground/Assets.xcassets/AccentColor.colorset/Contents.json b/Examples/CloudKitPlayground/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/Examples/CloudKitPlayground/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Examples/CloudKitPlayground/Assets.xcassets/AppIcon.appiconset/Contents.json b/Examples/CloudKitPlayground/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 23058801..00000000 --- a/Examples/CloudKitPlayground/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "tinted" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Examples/CloudKitPlayground/Assets.xcassets/Contents.json b/Examples/CloudKitPlayground/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/Examples/CloudKitPlayground/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Examples/CloudKitPlayground/CloudKitPlayground.entitlements b/Examples/CloudKitPlayground/CloudKitPlayground.entitlements deleted file mode 100644 index 97100297..00000000 --- a/Examples/CloudKitPlayground/CloudKitPlayground.entitlements +++ /dev/null @@ -1,16 +0,0 @@ - - - - - aps-environment - development - com.apple.developer.icloud-container-identifiers - - iCloud.co.pointfree.SQLiteData.demos.CloudKitPlayground - - com.apple.developer.icloud-services - - CloudKit - - - diff --git a/Examples/CloudKitPlayground/CloudKitPlaygroundApp.swift b/Examples/CloudKitPlayground/CloudKitPlaygroundApp.swift deleted file mode 100644 index c4ee8a3b..00000000 --- a/Examples/CloudKitPlayground/CloudKitPlaygroundApp.swift +++ /dev/null @@ -1,78 +0,0 @@ -import CloudKit -import SQLiteData -import SwiftUI -import UIKit - -@main -struct CloudKitPlaygroundApp: App { - @UIApplicationDelegateAdaptor var delegate: AppDelegate - - init() { - prepareDependencies { - $0.defaultDatabase = try! appDatabase() - $0.defaultSyncEngine = try! SyncEngine( - for: $0.defaultDatabase, - tables: ModelA.self, - ModelB.self, - ModelC.self - ) - } - } - var body: some Scene { - WindowGroup { - NavigationStack { - ModelAView() - } - } - } -} - -class AppDelegate: UIResponder, UIApplicationDelegate { - func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - return true - } - - func application( - _ application: UIApplication, - configurationForConnecting connectingSceneSession: UISceneSession, - options: UIScene.ConnectionOptions - ) -> UISceneConfiguration { - let configuration = UISceneConfiguration( - name: "Default Configuration", - sessionRole: connectingSceneSession.role - ) - configuration.delegateClass = SceneDelegate.self - return configuration - } -} - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - @Dependency(\.defaultSyncEngine) var syncEngine - var window: UIWindow? - - func windowScene( - _ windowScene: UIWindowScene, - userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata - ) { - Task { - try await syncEngine.acceptShare(metadata: cloudKitShareMetadata) - } - } - - func scene( - _ scene: UIScene, - willConnectTo session: UISceneSession, - options connectionOptions: UIScene.ConnectionOptions - ) { - guard let cloudKitShareMetadata = connectionOptions.cloudKitShareMetadata - else { - return - } - Task { - try await syncEngine.acceptShare(metadata: cloudKitShareMetadata) - } - } -} diff --git a/Examples/CloudKitPlayground/ContentView.swift b/Examples/CloudKitPlayground/ContentView.swift deleted file mode 100644 index 4503945e..00000000 --- a/Examples/CloudKitPlayground/ContentView.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ContentView.swift -// CloudKitPlayground -// -// Created by Brandon Williams on 7/9/25. -// - -import SwiftUI - -struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundStyle(.tint) - Text("Hello, world!") - } - .padding() - } -} - -#Preview { - ContentView() -} diff --git a/Examples/CloudKitPlayground/Info.plist b/Examples/CloudKitPlayground/Info.plist deleted file mode 100644 index 9ef96ef8..00000000 --- a/Examples/CloudKitPlayground/Info.plist +++ /dev/null @@ -1,12 +0,0 @@ - - - - - CKSharingSupported - - UIBackgroundModes - - remote-notification - - - diff --git a/Examples/CloudKitPlayground/ModelAView.swift b/Examples/CloudKitPlayground/ModelAView.swift deleted file mode 100644 index 3835281d..00000000 --- a/Examples/CloudKitPlayground/ModelAView.swift +++ /dev/null @@ -1,71 +0,0 @@ -import CloudKit -import SQLiteData -import SwiftUI - -struct ModelAView: View { - @FetchAll var models: [ModelA] - @Dependency(\.defaultDatabase) var database - @Dependency(\.defaultSyncEngine) var syncEngine - - @State var sharedRecord: SharedRecord? - - var body: some View { - List { - ForEach(models) { model in - HStack { - Button("-") { - withErrorReporting { - try database.write { db in - try ModelA.find(model.id).update { $0.count -= 1 }.execute(db) - } - } - } - Text("\(model.count)") - Button("+") { - withErrorReporting { - try database.write { db in - try ModelA.find(model.id).update { $0.count += 1 }.execute(db) - } - } - } - Spacer() - NavigationLink("Go") { - ModelBView(modelA: model) - } - Spacer() - Button { - Task { - sharedRecord = try await syncEngine.share(record: model) { share in - share[CKShare.SystemFieldKey.title] = "Join my ModelA(\(model.count))" - } - } - } label: { - Image(systemName: "square.and.arrow.up") - } - } - .buttonStyle(.plain) - } - .onDelete { indexSet in - for index in indexSet { - withErrorReporting { - try database.write { db in - try ModelA.find(models[index].id).delete().execute(db) - } - } - } - } - } - .sheet(item: $sharedRecord) { sharedRecord in - CloudSharingView(sharedRecord: sharedRecord) - } - .toolbar { - Button("Add") { - withErrorReporting { - try database.write { db in - try ModelA.insert { ModelA.Draft() }.execute(db) - } - } - } - } - } -} diff --git a/Examples/CloudKitPlayground/ModelBView.swift b/Examples/CloudKitPlayground/ModelBView.swift deleted file mode 100644 index 0587fbd8..00000000 --- a/Examples/CloudKitPlayground/ModelBView.swift +++ /dev/null @@ -1,73 +0,0 @@ -import SQLiteData -import SwiftUI - -struct ModelBView: View { - let modelA: ModelA - @FetchAll var models: [ModelB] - @Dependency(\.defaultDatabase) var database - - init(modelA: ModelA) { - self.modelA = modelA - _models = FetchAll(ModelB.where { $0.modelAID.eq(modelA.id) }) - } - - var body: some View { - List { - ForEach(models) { model in - HStack { - Toggle( - "On? \(model.isOn ? "YES" : "NO")", - isOn: Binding { - model.isOn - } set: { newValue in - withErrorReporting { - try database.write { db in - try ModelB.find(model.id).update { $0.isOn = newValue }.execute(db) - } - } - }) - - Spacer() - NavigationLink("Go") { - ModelCView(modelB: model) - } - } - .buttonStyle(.plain) - } - .onDelete { indexSet in - for index in indexSet { - withErrorReporting { - try database.write { db in - try ModelB.find(models[index].id).delete().execute(db) - } - } - } - } - } - .toolbar { - Button("Add") { - withErrorReporting { - try database.write { db in - try ModelB.insert { ModelB.Draft(modelAID: modelA.id) }.execute(db) - } - } - } - Button("Special") { - withErrorReporting { - try database.write { db in - let modelB = try ModelB.insert { ModelB.Draft(modelAID: modelA.id) }.returning(\.self) - .fetchOne(db) - guard let modelB - else { return } - - for index in 1...5 { - try ModelC - .insert { ModelC.Draft.init(title: index.description, modelBID: modelB.id) } - .execute(db) - } - } - } - } - } - } -} diff --git a/Examples/CloudKitPlayground/ModelCView.swift b/Examples/CloudKitPlayground/ModelCView.swift deleted file mode 100644 index 51b9546c..00000000 --- a/Examples/CloudKitPlayground/ModelCView.swift +++ /dev/null @@ -1,52 +0,0 @@ -import SQLiteData -import SwiftUI - -struct ModelCView: View { - let modelB: ModelB - @FetchAll var models: [ModelC] - @Dependency(\.defaultDatabase) var database - - init(modelB: ModelB) { - self.modelB = modelB - _models = FetchAll(ModelC.where { $0.modelBID.eq(modelB.id) }) - } - - var body: some View { - List { - ForEach(models) { model in - HStack { - TextField( - "Title", - text: Binding { - model.title - } set: { newValue in - withErrorReporting { - try database.write { db in - try ModelC.find(model.id).update { $0.title = newValue }.execute(db) - } - } - }) - } - .buttonStyle(.plain) - } - .onDelete { indexSet in - for index in indexSet { - withErrorReporting { - try database.write { db in - try ModelC.find(models[index].id).delete().execute(db) - } - } - } - } - } - .toolbar { - Button("Add") { - withErrorReporting { - try database.write { db in - try ModelC.insert { ModelC.Draft(modelBID: modelB.id) }.execute(db) - } - } - } - } - } -} diff --git a/Examples/CloudKitPlayground/Schema.swift b/Examples/CloudKitPlayground/Schema.swift deleted file mode 100644 index 57489dfc..00000000 --- a/Examples/CloudKitPlayground/Schema.swift +++ /dev/null @@ -1,88 +0,0 @@ -import Foundation -import SQLiteData -import os - -@Table struct ModelA: Identifiable { - let id: UUID - var count = 0 -} -@Table struct ModelB: Identifiable { - let id: UUID - var isOn = false - var modelAID: ModelA.ID -} -@Table struct ModelC: Identifiable { - let id: UUID - var title = "" - var modelBID: ModelB.ID -} - -func appDatabase() throws -> any DatabaseWriter { - @Dependency(\.context) var context - let database: any DatabaseWriter - var configuration = Configuration() - configuration.prepareDatabase { db in - try db.attachMetadatabase() - #if DEBUG - db.trace(options: .profile) { - if context == .live { - logger.debug("\($0.expandedDescription)") - } else { - print("\($0.expandedDescription)") - } - } - #endif - } - if context == .preview { - database = try DatabaseQueue(configuration: configuration) - } else { - let path = - context == .live - ? URL.documentsDirectory.appending(component: "db.sqlite").path() - : URL.temporaryDirectory.appending(component: "\(UUID().uuidString)-db.sqlite").path() - logger.debug( - """ - App database - open "\(path)" - """ - ) - database = try DatabasePool(path: path, configuration: configuration) - } - var migrator = DatabaseMigrator() - migrator.registerMigration("Create tables") { db in - try #sql( - """ - CREATE TABLE "modelAs" ( - "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), - "count" INTEGER NOT NULL - ) - """ - ) - .execute(db) - try #sql( - """ - CREATE TABLE "modelBs" ( - "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), - "isOn" INTEGER NOT NULL, - "modelAID" INTEGER NOT NULL REFERENCES "modelAs"("id") ON DELETE CASCADE - ) - """ - ) - .execute(db) - try #sql( - """ - CREATE TABLE "modelCs" ( - "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), - "title" TEXT NOT NULL, - "modelBID" INTEGER NOT NULL REFERENCES "modelBs"("id") ON DELETE CASCADE - ) - """ - ) - .execute(db) - } - try migrator.migrate(database) - - return database -} - -let logger = Logger(subsystem: "CloudKitPlayground", category: "Database") diff --git a/Examples/Examples.xcodeproj/project.pbxproj b/Examples/Examples.xcodeproj/project.pbxproj index a7d7bc4c..8428b36c 100644 --- a/Examples/Examples.xcodeproj/project.pbxproj +++ b/Examples/Examples.xcodeproj/project.pbxproj @@ -9,15 +9,16 @@ /* Begin PBXBuildFile section */ CA14DBC92DA884C400E36852 /* CasePaths in Frameworks */ = {isa = PBXBuildFile; productRef = CA14DBC82DA884C400E36852 /* CasePaths */; }; CA2908C92D4AF70E003F165F /* UIKitNavigation in Frameworks */ = {isa = PBXBuildFile; productRef = CA2908C82D4AF70E003F165F /* UIKitNavigation */; }; + CA2BDE2A2E71C469000974D3 /* SQLiteData in Frameworks */ = {isa = PBXBuildFile; productRef = CA2BDE292E71C469000974D3 /* SQLiteData */; }; + CA2BDE2C2E71C472000974D3 /* SQLiteData in Frameworks */ = {isa = PBXBuildFile; productRef = CA2BDE2B2E71C472000974D3 /* SQLiteData */; }; + CA2BDE2E2E71C479000974D3 /* SQLiteData in Frameworks */ = {isa = PBXBuildFile; productRef = CA2BDE2D2E71C479000974D3 /* SQLiteData */; }; + CA2BDE302E71C480000974D3 /* SQLiteData in Frameworks */ = {isa = PBXBuildFile; productRef = CA2BDE2F2E71C480000974D3 /* SQLiteData */; }; CA5E46912DEBB8570069E0F8 /* SwiftUINavigation in Frameworks */ = {isa = PBXBuildFile; productRef = CA5E46902DEBB8570069E0F8 /* SwiftUINavigation */; }; CA5E47072DECEF0F0069E0F8 /* InlineSnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = CA5E47062DECEF0F0069E0F8 /* InlineSnapshotTesting */; }; CA5E47092DECEFC80069E0F8 /* SnapshotTestingCustomDump in Frameworks */ = {isa = PBXBuildFile; productRef = CA5E47082DECEFC80069E0F8 /* SnapshotTestingCustomDump */; }; CA5E470B2DECF0280069E0F8 /* DependenciesTestSupport in Frameworks */ = {isa = PBXBuildFile; productRef = CA5E470A2DECF0280069E0F8 /* DependenciesTestSupport */; }; - CA6A1D242E68A0A600604D6A /* SQLiteData in Frameworks */ = {isa = PBXBuildFile; productRef = CA6A1D232E68A0A600604D6A /* SQLiteData */; }; CAD001872D874F1F00FA977A /* DependenciesTestSupport in Frameworks */ = {isa = PBXBuildFile; productRef = CAD001862D874F1F00FA977A /* DependenciesTestSupport */; }; DC5FA7482D4C63D60082743E /* DependenciesMacros in Frameworks */ = {isa = PBXBuildFile; productRef = DC5FA7472D4C63D60082743E /* DependenciesMacros */; }; - DC9A3DDE2E6A280700DE41FB /* SQLiteData in Frameworks */ = {isa = PBXBuildFile; productRef = DC9A3DDD2E6A280700DE41FB /* SQLiteData */; }; - DC9A3DE02E6A280F00DE41FB /* SQLiteData in Frameworks */ = {isa = PBXBuildFile; productRef = DC9A3DDF2E6A280F00DE41FB /* SQLiteData */; }; DCBE8A142D4842BF0071F499 /* CasePaths in Frameworks */ = {isa = PBXBuildFile; productRef = DCBE8A132D4842BF0071F499 /* CasePaths */; }; DCF267392D48437300B680BE /* SwiftUINavigation in Frameworks */ = {isa = PBXBuildFile; productRef = DCF267382D48437300B680BE /* SwiftUINavigation */; }; /* End PBXBuildFile section */ @@ -47,6 +48,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + CA2BDD9D2E71C30B000974D3 /* CloudKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CloudKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + CA2BDE272E71C42B000974D3 /* sharing-grdb */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "sharing-grdb"; path = "/Users/brandon/projects/sharing-grdb"; sourceTree = ""; }; CA5E46962DEBFE410069E0F8 /* RemindersTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RemindersTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CA5F37542D5AFBBC002E1A9E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; CAD0017D2D874E6F00FA977A /* SyncUpTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SyncUpTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -57,6 +60,13 @@ /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + CA2BDE332E71C578000974D3 /* Exceptions for "CloudKitDemo" folder in "CloudKitDemo" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = CA2BDD9C2E71C30B000974D3 /* CloudKitDemo */; + }; CAD4819A2D584B510004799A /* Exceptions for "CaseStudies" folder in "CaseStudies" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( @@ -83,6 +93,14 @@ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ + CA2BDD9E2E71C30B000974D3 /* CloudKitDemo */ = { + isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + CA2BDE332E71C578000974D3 /* Exceptions for "CloudKitDemo" folder in "CloudKitDemo" target */, + ); + path = CloudKitDemo; + sourceTree = ""; + }; CA5E46972DEBFE410069E0F8 /* RemindersTests */ = { isa = PBXFileSystemSynchronizedRootGroup; path = RemindersTests; @@ -125,6 +143,14 @@ /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ + CA2BDD9A2E71C30B000974D3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CA2BDE2A2E71C469000974D3 /* SQLiteData in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CA5E46932DEBFE410069E0F8 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -147,7 +173,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DC9A3DDE2E6A280700DE41FB /* SQLiteData in Frameworks */, + CA2BDE302E71C480000974D3 /* SQLiteData in Frameworks */, CA2908C92D4AF70E003F165F /* UIKitNavigation in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -163,7 +189,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CA6A1D242E68A0A600604D6A /* SQLiteData in Frameworks */, + CA2BDE2E2E71C479000974D3 /* SQLiteData in Frameworks */, CA14DBC92DA884C400E36852 /* CasePaths in Frameworks */, CA5E46912DEBB8570069E0F8 /* SwiftUINavigation in Frameworks */, ); @@ -175,7 +201,7 @@ files = ( DCF267392D48437300B680BE /* SwiftUINavigation in Frameworks */, DC5FA7482D4C63D60082743E /* DependenciesMacros in Frameworks */, - DC9A3DE02E6A280F00DE41FB /* SQLiteData in Frameworks */, + CA2BDE2C2E71C472000974D3 /* SQLiteData in Frameworks */, DCBE8A142D4842BF0071F499 /* CasePaths in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -193,6 +219,7 @@ CA5E46972DEBFE410069E0F8 /* RemindersTests */, DCBE89CD2D483FB90071F499 /* SyncUps */, CAD0017E2D874E6F00FA977A /* SyncUpTests */, + CA2BDD9E2E71C30B000974D3 /* CloudKitDemo */, CAF837022D4735C00047AEB5 /* Frameworks */, CAF836992D4735620047AEB5 /* Products */, ); @@ -207,6 +234,7 @@ DCBE89CC2D483FB90071F499 /* SyncUps.app */, CAD0017D2D874E6F00FA977A /* SyncUpTests.xctest */, CA5E46962DEBFE410069E0F8 /* RemindersTests.xctest */, + CA2BDD9D2E71C30B000974D3 /* CloudKitDemo.app */, ); name = Products; sourceTree = ""; @@ -214,6 +242,7 @@ CAF837022D4735C00047AEB5 /* Frameworks */ = { isa = PBXGroup; children = ( + CA2BDE272E71C42B000974D3 /* sharing-grdb */, ); name = Frameworks; sourceTree = ""; @@ -221,6 +250,29 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + CA2BDD9C2E71C30B000974D3 /* CloudKitDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = CA2BDDA72E71C30D000974D3 /* Build configuration list for PBXNativeTarget "CloudKitDemo" */; + buildPhases = ( + CA2BDD992E71C30B000974D3 /* Sources */, + CA2BDD9A2E71C30B000974D3 /* Frameworks */, + CA2BDD9B2E71C30B000974D3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + CA2BDD9E2E71C30B000974D3 /* CloudKitDemo */, + ); + name = CloudKitDemo; + packageProductDependencies = ( + CA2BDE292E71C469000974D3 /* SQLiteData */, + ); + productName = CloudKitDemo; + productReference = CA2BDD9D2E71C30B000974D3 /* CloudKitDemo.app */; + productType = "com.apple.product-type.application"; + }; CA5E46952DEBFE410069E0F8 /* RemindersTests */ = { isa = PBXNativeTarget; buildConfigurationList = CA5E469C2DEBFE420069E0F8 /* Build configuration list for PBXNativeTarget "RemindersTests" */; @@ -289,7 +341,7 @@ name = CaseStudies; packageProductDependencies = ( CA2908C82D4AF70E003F165F /* UIKitNavigation */, - DC9A3DDD2E6A280700DE41FB /* SQLiteData */, + CA2BDE2F2E71C480000974D3 /* SQLiteData */, ); productName = Examples; productReference = CAF836982D4735620047AEB5 /* CaseStudies.app */; @@ -337,7 +389,7 @@ packageProductDependencies = ( CA14DBC82DA884C400E36852 /* CasePaths */, CA5E46902DEBB8570069E0F8 /* SwiftUINavigation */, - CA6A1D232E68A0A600604D6A /* SQLiteData */, + CA2BDE2D2E71C479000974D3 /* SQLiteData */, ); productName = Reminders; productReference = CAF836D82D4735AB0047AEB5 /* Reminders.app */; @@ -363,7 +415,7 @@ DCBE8A132D4842BF0071F499 /* CasePaths */, DCF267382D48437300B680BE /* SwiftUINavigation */, DC5FA7472D4C63D60082743E /* DependenciesMacros */, - DC9A3DDF2E6A280F00DE41FB /* SQLiteData */, + CA2BDE2B2E71C472000974D3 /* SQLiteData */, ); productName = SyncUps; productReference = DCBE89CC2D483FB90071F499 /* SyncUps.app */; @@ -379,6 +431,9 @@ LastSwiftUpdateCheck = 1640; LastUpgradeCheck = 1620; TargetAttributes = { + CA2BDD9C2E71C30B000974D3 = { + CreatedOnToolsVersion = 16.4; + }; CA5E46952DEBFE410069E0F8 = { CreatedOnToolsVersion = 16.4; TestTargetID = CAF836D72D4735AB0047AEB5; @@ -416,7 +471,7 @@ DCF267372D48437300B680BE /* XCRemoteSwiftPackageReference "swift-navigation" */, DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */, CA5E47052DECEF0F0069E0F8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, - DCD9AC892E02176700FB20F8 /* XCLocalSwiftPackageReference ".." */, + CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sharing-grdb" */, ); preferredProjectObjectVersion = 77; productRefGroup = CAF836992D4735620047AEB5 /* Products */; @@ -429,11 +484,19 @@ CA5E46952DEBFE410069E0F8 /* RemindersTests */, DCBE89CB2D483FB90071F499 /* SyncUps */, CAD0017C2D874E6F00FA977A /* SyncUpTests */, + CA2BDD9C2E71C30B000974D3 /* CloudKitDemo */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + CA2BDD9B2E71C30B000974D3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; CA5E46942DEBFE410069E0F8 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -479,6 +542,13 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + CA2BDD992E71C30B000974D3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; CA5E46922DEBFE410069E0F8 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -542,6 +612,68 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + CA2BDDA52E71C30D000974D3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = CloudKitDemo/CloudKitDemo.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = VFRXY8HC3H; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = CloudKitDemo/Info.plist; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 18.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.SQLiteData.CloudKitDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + CA2BDDA62E71C30D000974D3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = CloudKitDemo/CloudKitDemo.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = VFRXY8HC3H; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = CloudKitDemo/Info.plist; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 18.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.SQLiteData.CloudKitDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; CA5E469D2DEBFE420069E0F8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -938,6 +1070,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + CA2BDDA72E71C30D000974D3 /* Build configuration list for PBXNativeTarget "CloudKitDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CA2BDDA52E71C30D000974D3 /* Debug */, + CA2BDDA62E71C30D000974D3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; CA5E469C2DEBFE420069E0F8 /* Build configuration list for PBXNativeTarget "RemindersTests" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -1004,9 +1145,9 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - DCD9AC892E02176700FB20F8 /* XCLocalSwiftPackageReference ".." */ = { + CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sharing-grdb" */ = { isa = XCLocalSwiftPackageReference; - relativePath = ".."; + relativePath = "../../sharing-grdb"; }; /* End XCLocalSwiftPackageReference section */ @@ -1056,6 +1197,25 @@ package = DCF267372D48437300B680BE /* XCRemoteSwiftPackageReference "swift-navigation" */; productName = UIKitNavigation; }; + CA2BDE292E71C469000974D3 /* SQLiteData */ = { + isa = XCSwiftPackageProductDependency; + productName = SQLiteData; + }; + CA2BDE2B2E71C472000974D3 /* SQLiteData */ = { + isa = XCSwiftPackageProductDependency; + package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sharing-grdb" */; + productName = SQLiteData; + }; + CA2BDE2D2E71C479000974D3 /* SQLiteData */ = { + isa = XCSwiftPackageProductDependency; + package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sharing-grdb" */; + productName = SQLiteData; + }; + CA2BDE2F2E71C480000974D3 /* SQLiteData */ = { + isa = XCSwiftPackageProductDependency; + package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sharing-grdb" */; + productName = SQLiteData; + }; CA5E46902DEBB8570069E0F8 /* SwiftUINavigation */ = { isa = XCSwiftPackageProductDependency; package = DCF267372D48437300B680BE /* XCRemoteSwiftPackageReference "swift-navigation" */; @@ -1076,11 +1236,6 @@ package = DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */; productName = DependenciesTestSupport; }; - CA6A1D232E68A0A600604D6A /* SQLiteData */ = { - isa = XCSwiftPackageProductDependency; - package = DCD9AC892E02176700FB20F8 /* XCLocalSwiftPackageReference ".." */; - productName = SQLiteData; - }; CAD001862D874F1F00FA977A /* DependenciesTestSupport */ = { isa = XCSwiftPackageProductDependency; package = DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */; @@ -1091,16 +1246,6 @@ package = DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */; productName = DependenciesMacros; }; - DC9A3DDD2E6A280700DE41FB /* SQLiteData */ = { - isa = XCSwiftPackageProductDependency; - package = DCD9AC892E02176700FB20F8 /* XCLocalSwiftPackageReference ".." */; - productName = SQLiteData; - }; - DC9A3DDF2E6A280F00DE41FB /* SQLiteData */ = { - isa = XCSwiftPackageProductDependency; - package = DCD9AC892E02176700FB20F8 /* XCLocalSwiftPackageReference ".." */; - productName = SQLiteData; - }; DCBE8A132D4842BF0071F499 /* CasePaths */ = { isa = XCSwiftPackageProductDependency; package = DCBE8A122D4842BF0071F499 /* XCRemoteSwiftPackageReference "swift-case-paths" */; diff --git a/Examples/Examples.xcodeproj/xcshareddata/xcschemes/CloudKitDemo.xcscheme b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/CloudKitDemo.xcscheme deleted file mode 100644 index 46a630af..00000000 --- a/Examples/Examples.xcodeproj/xcshareddata/xcschemes/CloudKitDemo.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 6df86ca2c1147ada303e69a48d7404a7972863a3 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 10 Sep 2025 09:56:46 -0500 Subject: [PATCH 2/7] wip --- Examples/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Examples/README.md b/Examples/README.md index 26b2754f..50d85ea4 100644 --- a/Examples/README.md +++ b/Examples/README.md @@ -7,6 +7,14 @@ with [SQLiteData](http://github.com/pointfreeco/sqlite-data).
Demonstrates how to solve some common application problems in an isolated environment, in both SwiftUI and UIKit. Things like animations, dynamic queries, database transactions, and more. +* **CloudKitDemo** +
A simplified demo that shows how to synchronize a SQLite database to CloudKit and how to + share records with other iCloud users. See our dedicated articles on [CloudKit Synchronization] + and [CloudKit Sharing] for more information. + + [CloudKit Synchronization]: https://swiftpackageindex.com/pointfreeco/sqlite-data/main/documentation/sqlitedata/cloudkit + [CloudKit Sharing]: https://swiftpackageindex.com/pointfreeco/sqlite-data/main/documentation/sqlitedata/cloudkitsharing + * **Reminders**
A rebuild of Apple's [Reminders][reminders-app-store] app that uses a SQLite database to model the reminders, lists and tags. It features many advanced queries, such as searching, stats @@ -15,6 +23,8 @@ with [SQLiteData](http://github.com/pointfreeco/sqlite-data). * **SyncUps**
This application is a faithful reconstruction of one of Apple's more interesting sample projects, called [Scrumdinger][scrumdinger], and uses SQLite to persist the data for meetings. + We have also added CloudKit synchronization so that all changes are automatically made available + on all of the user's devices. [scrumdinger]: https://developer.apple.com/tutorials/app-dev-training/getting-started-with-scrumdinger [reminders-app-store]: https://apps.apple.com/us/app/reminders/id1108187841 From 38feacb4f16debb2441f39091cdadf65e5856ae6 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 10 Sep 2025 09:59:52 -0500 Subject: [PATCH 3/7] Rename more references to sqlite-data --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/workflows/release.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 2f399dee..25fda7cf 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -27,7 +27,7 @@ body: required: false - label: If possible, I've reproduced the issue using the `main` branch of this package. required: false - - label: This issue hasn't been addressed in an [existing GitHub issue](https://github.com/pointfreeco/sharing-grdb/issues) or [discussion](https://github.com/pointfreeco/sharing-grdb/discussions). + - label: This issue hasn't been addressed in an [existing GitHub issue](https://github.com/pointfreeco/sqlite-data/issues) or [discussion](https://github.com/pointfreeco/sqlite-data/discussions). required: true - type: textarea attributes: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 45dce330..030e709c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,14 +17,14 @@ jobs: env: INCOMING_WEBHOOK_URL: ${{ secrets.SLACK_PROJECT_CHANNEL_WEBHOOK_URL }} with: - text: sharing-grdb ${{ github.event.release.tag_name }} has been released. + text: sqlite-data ${{ github.event.release.tag_name }} has been released. blocks: | [ { "type": "header", "text": { "type": "plain_text", - "text": "sharing-grdb ${{ github.event.release.tag_name}}" + "text": "sqlite-data ${{ github.event.release.tag_name}}" } }, { @@ -56,14 +56,14 @@ jobs: env: INCOMING_WEBHOOK_URL: ${{ secrets.SLACK_RELEASES_WEBHOOK_URL }} with: - text: sharing-grdb ${{ github.event.release.tag_name }} has been released. + text: sqlite-data ${{ github.event.release.tag_name }} has been released. blocks: | [ { "type": "header", "text": { "type": "plain_text", - "text": "sharing-grdb ${{ github.event.release.tag_name}}" + "text": "sqlite-data ${{ github.event.release.tag_name}}" } }, { From 034db5231d3b6b6ac0a527091580307efe2e3f8a Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 10 Sep 2025 11:23:26 -0500 Subject: [PATCH 4/7] wip --- .../xcshareddata/swiftpm/Package.resolved | 20 +++++++++++- README.md | 32 +++++++++++++------ 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index f68ebba6..e7386aee 100644 --- a/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "22fb924569f92610b5675a628f98b8864244fe7f2f1702deb956f693c2598118", + "originHash" : "3c33240501a0679d36175ebd2f677189bf28a044e6a74e224c59f016319f653e", "pins" : [ { "identity" : "combine-schedulers", @@ -73,6 +73,24 @@ "version" : "1.9.4" } }, + { + "identity" : "swift-docc-plugin", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-docc-plugin", + "state" : { + "revision" : "3e4f133a77e644a5812911a0513aeb7288b07d06", + "version" : "1.4.5" + } + }, + { + "identity" : "swift-docc-symbolkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swiftlang/swift-docc-symbolkit", + "state" : { + "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34", + "version" : "1.0.0" + } + }, { "identity" : "swift-identified-collections", "kind" : "remoteSourceControl", diff --git a/README.md b/README.md index 24180b55..29898d0e 100644 --- a/README.md +++ b/README.md @@ -346,16 +346,28 @@ for data and keep your views up-to-date when data in the database changes, and y This repo comes with _lots_ of examples to demonstrate how to solve common and complex problems with SQLiteData. Check out [this](./Examples) directory to see them all, including: - * [Case Studies](./Examples/CaseStudies): A number of case studies demonstrating the built-in - features of the library. - - * [SyncUps](./Examples/SyncUps): We also rebuilt Apple's [Scrumdinger][] demo application using - modern, best practices for SwiftUI development, including using this library to query and - persist state using SQLite. - - * [Reminders](./Examples/Reminders): A rebuild of Apple's [Reminders][reminders-app-store] app - that uses a SQLite database to model the reminders, lists and tags. It features many advanced - queries, such as searching, and stats aggregation. +* [**Case Studies**](./Examples/CaseStudies) +
Demonstrates how to solve some common application problems in an isolated environment, in + both SwiftUI and UIKit. Things like animations, dynamic queries, database transactions, and more. + +* [**CloudKitDemo**](./Examples/CloudKitDemo) +
A simplified demo that shows how to synchronize a SQLite database to CloudKit and how to + share records with other iCloud users. See our dedicated articles on [CloudKit Synchronization] + and [CloudKit Sharing] for more information. + + [CloudKit Synchronization]: https://swiftpackageindex.com/pointfreeco/sqlite-data/main/documentation/sqlitedata/cloudkit + [CloudKit Sharing]: https://swiftpackageindex.com/pointfreeco/sqlite-data/main/documentation/sqlitedata/cloudkitsharing + +* [**Reminders**](./Examples/Reminders) +
A rebuild of Apple's [Reminders][reminders-app-store] app that uses a SQLite database to + model the reminders, lists and tags. It features many advanced queries, such as searching, stats + aggregation, and multi-table joins. It also features CloudKit synchronization and sharing. + +* [**SyncUps**](./Examples/SyncUps) +
This application is a faithful reconstruction of one of Apple's more interesting sample + projects, called [Scrumdinger][scrumdinger], and uses SQLite to persist the data for meetings. + We have also added CloudKit synchronization so that all changes are automatically made available + on all of the user's devices. [Scrumdinger]: https://developer.apple.com/tutorials/app-dev-training/getting-started-with-scrumdinger [reminders-app-store]: https://apps.apple.com/us/app/reminders/id1108187841 From 667eb96c95da1c31492ff8738478336e00f1b71b Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 10 Sep 2025 13:02:11 -0500 Subject: [PATCH 5/7] wip --- Examples/Examples.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Examples/Examples.xcodeproj/project.pbxproj b/Examples/Examples.xcodeproj/project.pbxproj index 8428b36c..5341890d 100644 --- a/Examples/Examples.xcodeproj/project.pbxproj +++ b/Examples/Examples.xcodeproj/project.pbxproj @@ -49,7 +49,7 @@ /* Begin PBXFileReference section */ CA2BDD9D2E71C30B000974D3 /* CloudKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CloudKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - CA2BDE272E71C42B000974D3 /* sharing-grdb */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "sharing-grdb"; path = "/Users/brandon/projects/sharing-grdb"; sourceTree = ""; }; + CA2BDE272E71C42B000974D3 /* sqlite-data */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "sqlite-data"; path = "/Users/brandon/projects/sqlite-data"; sourceTree = ""; }; CA5E46962DEBFE410069E0F8 /* RemindersTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RemindersTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CA5F37542D5AFBBC002E1A9E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; CAD0017D2D874E6F00FA977A /* SyncUpTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SyncUpTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -242,7 +242,7 @@ CAF837022D4735C00047AEB5 /* Frameworks */ = { isa = PBXGroup; children = ( - CA2BDE272E71C42B000974D3 /* sharing-grdb */, + CA2BDE272E71C42B000974D3 /* sqlite-data */, ); name = Frameworks; sourceTree = ""; @@ -471,7 +471,7 @@ DCF267372D48437300B680BE /* XCRemoteSwiftPackageReference "swift-navigation" */, DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */, CA5E47052DECEF0F0069E0F8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, - CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sharing-grdb" */, + CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sqlite-data" */, ); preferredProjectObjectVersion = 77; productRefGroup = CAF836992D4735620047AEB5 /* Products */; @@ -1145,9 +1145,9 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sharing-grdb" */ = { + CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sqlite-data" */ = { isa = XCLocalSwiftPackageReference; - relativePath = "../../sharing-grdb"; + relativePath = "../../sqlite-data"; }; /* End XCLocalSwiftPackageReference section */ @@ -1203,17 +1203,17 @@ }; CA2BDE2B2E71C472000974D3 /* SQLiteData */ = { isa = XCSwiftPackageProductDependency; - package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sharing-grdb" */; + package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sqlite-data" */; productName = SQLiteData; }; CA2BDE2D2E71C479000974D3 /* SQLiteData */ = { isa = XCSwiftPackageProductDependency; - package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sharing-grdb" */; + package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sqlite-data" */; productName = SQLiteData; }; CA2BDE2F2E71C480000974D3 /* SQLiteData */ = { isa = XCSwiftPackageProductDependency; - package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sharing-grdb" */; + package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sqlite-data" */; productName = SQLiteData; }; CA5E46902DEBB8570069E0F8 /* SwiftUINavigation */ = { From f56c12d320484dabc38420f9c6120bacd261ea7d Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 10 Sep 2025 13:11:01 -0500 Subject: [PATCH 6/7] wip --- Examples/Examples.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Examples/Examples.xcodeproj/project.pbxproj b/Examples/Examples.xcodeproj/project.pbxproj index 5341890d..893f15a6 100644 --- a/Examples/Examples.xcodeproj/project.pbxproj +++ b/Examples/Examples.xcodeproj/project.pbxproj @@ -471,7 +471,7 @@ DCF267372D48437300B680BE /* XCRemoteSwiftPackageReference "swift-navigation" */, DC5FA7462D4C63D60082743E /* XCRemoteSwiftPackageReference "swift-dependencies" */, CA5E47052DECEF0F0069E0F8 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, - CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sqlite-data" */, + CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference ".." */, ); preferredProjectObjectVersion = 77; productRefGroup = CAF836992D4735620047AEB5 /* Products */; @@ -1145,9 +1145,9 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sqlite-data" */ = { + CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference ".." */ = { isa = XCLocalSwiftPackageReference; - relativePath = "../../sqlite-data"; + relativePath = ..; }; /* End XCLocalSwiftPackageReference section */ @@ -1203,17 +1203,17 @@ }; CA2BDE2B2E71C472000974D3 /* SQLiteData */ = { isa = XCSwiftPackageProductDependency; - package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sqlite-data" */; + package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference ".." */; productName = SQLiteData; }; CA2BDE2D2E71C479000974D3 /* SQLiteData */ = { isa = XCSwiftPackageProductDependency; - package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sqlite-data" */; + package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference ".." */; productName = SQLiteData; }; CA2BDE2F2E71C480000974D3 /* SQLiteData */ = { isa = XCSwiftPackageProductDependency; - package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference "../../sqlite-data" */; + package = CA2BDE282E71C469000974D3 /* XCLocalSwiftPackageReference ".." */; productName = SQLiteData; }; CA5E46902DEBB8570069E0F8 /* SwiftUINavigation */ = { From cf4c8fe21fc9b904045d09585f24e452fb60f506 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 10 Sep 2025 13:23:14 -0500 Subject: [PATCH 7/7] go back to getting cloudkit container identifier from swiftdata --- Sources/SQLiteData/CloudKit/SyncEngine.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/SQLiteData/CloudKit/SyncEngine.swift b/Sources/SQLiteData/CloudKit/SyncEngine.swift index a828ab90..a203ec61 100644 --- a/Sources/SQLiteData/CloudKit/SyncEngine.swift +++ b/Sources/SQLiteData/CloudKit/SyncEngine.swift @@ -89,7 +89,9 @@ repeat (each T1).PrimaryKey.QueryOutput: IdentifierStringConvertible, repeat (each T2).PrimaryKey.QueryOutput: IdentifierStringConvertible { - let containerIdentifier = containerIdentifier ?? CKContainer.default().containerIdentifier + let containerIdentifier = + containerIdentifier + ?? ModelConfiguration(groupContainer: .automatic).cloudKitContainerIdentifier var allTables: [any PrimaryKeyedTable.Type] = [] var allPrivateTables: [any PrimaryKeyedTable.Type] = [] @@ -1808,7 +1810,7 @@ public func attachMetadatabase(containerIdentifier: String? = nil) throws { let containerIdentifier = containerIdentifier - ?? CKContainer.default().containerIdentifier + ?? ModelConfiguration(groupContainer: .automatic).cloudKitContainerIdentifier guard let containerIdentifier else { throw SyncEngine.SchemaError(