diff --git a/Examples/CaseStudies/Animations.swift b/Examples/CaseStudies/Animations.swift index a32a7156..e4c75a05 100644 --- a/Examples/CaseStudies/Animations.swift +++ b/Examples/CaseStudies/Animations.swift @@ -31,7 +31,7 @@ struct AnimationsCaseStudy: SwiftUICaseStudy { number += 1 let fact = try await String( decoding: URLSession.shared - .data(from: URL(string: "http://numberapi.com/\(number)")!).0, + .data(from: URL(string: "http://number-trivia.com/\(number)")!).0, as: UTF8.self ) try await database.write { db in @@ -72,10 +72,7 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { - $0.defaultDatabase = .animationDatabase - } +#Preview(traits: .dependencies { $0.defaultDatabase = .animationDatabase }) { NavigationStack { CaseStudyView { AnimationsCaseStudy() diff --git a/Examples/CaseStudies/DynamicQuery.swift b/Examples/CaseStudies/DynamicQuery.swift index b4c25163..8d4a12c7 100644 --- a/Examples/CaseStudies/DynamicQuery.swift +++ b/Examples/CaseStudies/DynamicQuery.swift @@ -65,7 +65,7 @@ struct DynamicQueryDemo: SwiftUICaseStudy { number += 1 let fact = try await String( decoding: URLSession.shared - .data(from: URL(string: "http://numberapi.com/\(number)")!).0, + .data(from: URL(string: "http://number-trivia.com/\(number)")!).0, as: UTF8.self ) try await database.write { db in @@ -126,10 +126,7 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { - $0.defaultDatabase = .dynamicQueryDatabase - } +#Preview(traits: .dependencies { $0.defaultDatabase = .dynamicQueryDatabase }) { NavigationStack { CaseStudyView { DynamicQueryDemo() diff --git a/Examples/CaseStudies/ObservableModelDemo.swift b/Examples/CaseStudies/ObservableModelDemo.swift index 1735fbc8..e4518216 100644 --- a/Examples/CaseStudies/ObservableModelDemo.swift +++ b/Examples/CaseStudies/ObservableModelDemo.swift @@ -61,7 +61,7 @@ private class Model { await withErrorReporting { let fact = try await String( decoding: URLSession.shared - .data(from: URL(string: "http://numberapi.com/\(number)")!).0, + .data(from: URL(string: "http://number-trivia.com/\(number)")!).0, as: UTF8.self ) try await database.write { db in @@ -112,10 +112,7 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { - $0.defaultDatabase = .observableModelDatabase - } +#Preview(traits: .dependencies { $0.defaultDatabase = .observableModelDatabase }) { NavigationStack { CaseStudyView { ObservableModelDemo() diff --git a/Examples/CaseStudies/SectionedQuery.swift b/Examples/CaseStudies/SectionedQuery.swift index 85f6ad74..e8422e54 100644 --- a/Examples/CaseStudies/SectionedQuery.swift +++ b/Examples/CaseStudies/SectionedQuery.swift @@ -119,10 +119,11 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { +#Preview( + traits: .dependencies { $0.defaultDatabase = .sectionedQueryDatabase } +) { NavigationStack { CaseStudyView { SectionedQueryDemo() diff --git a/Examples/CaseStudies/SwiftDataTemplateDemo.swift b/Examples/CaseStudies/SwiftDataTemplateDemo.swift index d7afef77..dbe5799e 100644 --- a/Examples/CaseStudies/SwiftDataTemplateDemo.swift +++ b/Examples/CaseStudies/SwiftDataTemplateDemo.swift @@ -81,10 +81,7 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { - $0.defaultDatabase = .swiftDataTemplateDatabase - } +#Preview(traits: .dependencies { $0.defaultDatabase = .swiftDataTemplateDatabase }) { CaseStudyView { SwiftDataTemplateView() } diff --git a/Examples/CaseStudies/SwiftUIDemo.swift b/Examples/CaseStudies/SwiftUIDemo.swift index e986af6b..c4abc8cf 100644 --- a/Examples/CaseStudies/SwiftUIDemo.swift +++ b/Examples/CaseStudies/SwiftUIDemo.swift @@ -40,7 +40,7 @@ struct SwiftUIDemo: SwiftUICaseStudy { number += 1 let fact = try await String( decoding: URLSession.shared - .data(from: URL(string: "http://numberapi.com/\(number)")!).0, + .data(from: URL(string: "http://number-trivia.com/\(number)")!).0, as: UTF8.self ) try await database.write { db in @@ -81,10 +81,7 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { - $0.defaultDatabase = .swiftUIDatabase - } +#Preview(traits: .dependencies { $0.defaultDatabase = .swiftUIDatabase }) { NavigationStack { CaseStudyView { SwiftUIDemo() diff --git a/Examples/CaseStudies/TransactionDemo.swift b/Examples/CaseStudies/TransactionDemo.swift index 52e59300..f94c55ad 100644 --- a/Examples/CaseStudies/TransactionDemo.swift +++ b/Examples/CaseStudies/TransactionDemo.swift @@ -43,7 +43,7 @@ struct TransactionDemo: SwiftUICaseStudy { number += 1 let fact = try await String( decoding: URLSession.shared - .data(from: URL(string: "http://numberapi.com/\(number)")!).0, + .data(from: URL(string: "http://number-trivia.com/\(number)")!).0, as: UTF8.self ) try await database.write { db in @@ -98,10 +98,7 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { - $0.defaultDatabase = .transactionDemoDatabase - } +#Preview(traits: .dependencies { $0.defaultDatabase = .transactionDemoDatabase }) { NavigationStack { CaseStudyView { TransactionDemo() diff --git a/Examples/CaseStudies/UIKitDemo.swift b/Examples/CaseStudies/UIKitDemo.swift index ce169ece..0c98ec96 100644 --- a/Examples/CaseStudies/UIKitDemo.swift +++ b/Examples/CaseStudies/UIKitDemo.swift @@ -90,7 +90,7 @@ final class UIKitCaseStudyViewController: UICollectionViewController, UIKitCaseS number += 1 let fact = try? await String( decoding: URLSession.shared - .data(from: URL(string: "http://numberapi.com/\(number)")!).0, + .data(from: URL(string: "http://number-trivia.com/\(number)")!).0, as: UTF8.self ) if let fact { @@ -138,9 +138,10 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { +#Preview( + traits: .dependencies { $0.defaultDatabase = .uiKitDemoDatabase } +) { UINavigationController(caseStudy: UIKitCaseStudyViewController()) } diff --git a/Examples/CloudKitDemo/CountersListFeature.swift b/Examples/CloudKitDemo/CountersListFeature.swift index 6e16e832..90991a1b 100644 --- a/Examples/CloudKitDemo/CountersListFeature.swift +++ b/Examples/CloudKitDemo/CountersListFeature.swift @@ -138,11 +138,12 @@ struct CounterRow: View { } } -#Preview { - let _ = try! prepareDependencies { +#Preview( + traits: .dependencies { try $0.bootstrapDatabase() try? $0.defaultDatabase.seedSampleData() } +) { NavigationStack { CountersListView() } diff --git a/Examples/Examples.xcodeproj/project.pbxproj b/Examples/Examples.xcodeproj/project.pbxproj index 2c6f2d6c..55414929 100644 --- a/Examples/Examples.xcodeproj/project.pbxproj +++ b/Examples/Examples.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 77; + objectVersion = 100; objects = { /* Begin PBXBuildFile section */ @@ -1255,8 +1255,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/pointfreeco/swift-dependencies"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.7.0; + branch = "eager-preview-trait-fix"; + kind = branch; }; }; DCBE8A122D4842BF0071F499 /* XCRemoteSwiftPackageReference "swift-case-paths" */ = { diff --git a/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8bdb0fcc..3d54e060 100644 --- a/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -69,8 +69,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-dependencies", "state" : { - "revision" : "16f7dd14ee28d04617090f2a73198b8b316ffa12", - "version" : "1.13.1" + "branch" : "eager-preview-trait-fix", + "revision" : "d6b5392b6f8e4493863a5ca14092e2f8535a94fc" } }, { @@ -105,8 +105,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-sharing", "state" : { - "revision" : "e47a2f545bafa3c0c702600f3e6ce02b3d566b6f", - "version" : "2.8.2" + "revision" : "8244fe63bf43e58188ab13851ad693eecf6a9e90", + "version" : "2.9.1" } }, { diff --git a/Examples/Integration/Regression Coverage/ChildIdentityReset.swift b/Examples/Integration/Regression Coverage/ChildIdentityReset.swift index be7dc421..d78d8cc2 100644 --- a/Examples/Integration/Regression Coverage/ChildIdentityReset.swift +++ b/Examples/Integration/Regression Coverage/ChildIdentityReset.swift @@ -93,10 +93,11 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { +#Preview( + traits: .dependencies { $0.defaultDatabase = .childIdentityResetDatabase } +) { NavigationStack { CaseStudyView { ChildIdentityResetCaseStudy() diff --git a/Examples/Integration/Regression Coverage/ParentDrivenQuery.swift b/Examples/Integration/Regression Coverage/ParentDrivenQuery.swift index e6b4b855..376a5cb6 100644 --- a/Examples/Integration/Regression Coverage/ParentDrivenQuery.swift +++ b/Examples/Integration/Regression Coverage/ParentDrivenQuery.swift @@ -98,10 +98,11 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { +#Preview( + traits: .dependencies { $0.defaultDatabase = .parentDrivenQueryDatabase } +) { NavigationStack { CaseStudyView { ParentDrivenQueryCaseStudy() diff --git a/Examples/Integration/Regression Coverage/ParentRerenderAnimations.swift b/Examples/Integration/Regression Coverage/ParentRerenderAnimations.swift index 36301722..44253222 100644 --- a/Examples/Integration/Regression Coverage/ParentRerenderAnimations.swift +++ b/Examples/Integration/Regression Coverage/ParentRerenderAnimations.swift @@ -82,10 +82,11 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { +#Preview( + traits: .dependencies { $0.defaultDatabase = .parentRerenderAnimationsDatabase } +) { NavigationStack { CaseStudyView { ParentRerenderAnimationsCaseStudy() diff --git a/Examples/Integration/Regression Coverage/ParentRerenderCancellation.swift b/Examples/Integration/Regression Coverage/ParentRerenderCancellation.swift index 8bacecac..43e1083f 100644 --- a/Examples/Integration/Regression Coverage/ParentRerenderCancellation.swift +++ b/Examples/Integration/Regression Coverage/ParentRerenderCancellation.swift @@ -88,10 +88,11 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { +#Preview( + traits: .dependencies { $0.defaultDatabase = .parentRerenderCancellationDatabase } +) { NavigationStack { CaseStudyView { ParentRerenderCancellationCaseStudy() diff --git a/Examples/Integration/Regression Coverage/ParentRerenderDynamicQuery.swift b/Examples/Integration/Regression Coverage/ParentRerenderDynamicQuery.swift index 3a2af0a9..dcc324a7 100644 --- a/Examples/Integration/Regression Coverage/ParentRerenderDynamicQuery.swift +++ b/Examples/Integration/Regression Coverage/ParentRerenderDynamicQuery.swift @@ -92,10 +92,11 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { +#Preview( + traits: .dependencies { $0.defaultDatabase = .parentRerenderDynamicQueryDatabase } +) { NavigationStack { CaseStudyView { ParentRerenderDynamicQueryCaseStudy() diff --git a/Examples/Integration/Regression Coverage/ParentRerenderLoadError.swift b/Examples/Integration/Regression Coverage/ParentRerenderLoadError.swift index b156819a..b339f956 100644 --- a/Examples/Integration/Regression Coverage/ParentRerenderLoadError.swift +++ b/Examples/Integration/Regression Coverage/ParentRerenderLoadError.swift @@ -63,10 +63,11 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { +#Preview( + traits: .dependencies { $0.defaultDatabase = .parentRerenderLoadErrorDatabase } +) { NavigationStack { CaseStudyView { ParentRerenderLoadErrorCaseStudy() diff --git a/Examples/Integration/Regression Coverage/ParentRerenderLoadedData.swift b/Examples/Integration/Regression Coverage/ParentRerenderLoadedData.swift index 1c689c0f..13c6e327 100644 --- a/Examples/Integration/Regression Coverage/ParentRerenderLoadedData.swift +++ b/Examples/Integration/Regression Coverage/ParentRerenderLoadedData.swift @@ -88,10 +88,11 @@ extension DatabaseWriter where Self == DatabaseQueue { } } -#Preview { - let _ = prepareDependencies { +#Preview( + traits: .dependencies { $0.defaultDatabase = .parentRerenderLoadedDataDatabase } +) { NavigationStack { CaseStudyView { ParentRerenderLoadedDataCaseStudy() diff --git a/Examples/Reminders/ReminderForm.swift b/Examples/Reminders/ReminderForm.swift index a1566249..d13bf41c 100644 --- a/Examples/Reminders/ReminderForm.swift +++ b/Examples/Reminders/ReminderForm.swift @@ -205,14 +205,13 @@ extension Optional { struct ReminderFormPreview: PreviewProvider { static var previews: some View { - let (remindersList, reminder) = try! prepareDependencies { + let (reminder, remindersList) = try! prepareDependencies { $0.defaultDatabase = try Reminders.appDatabase() - return try $0.defaultDatabase.write { db in - let remindersList = try RemindersList.fetchOne(db)! - return ( - remindersList, - try Reminder.where { $0.remindersListID.eq(remindersList.id) }.fetchOne(db)! - ) + try? $0.defaultDatabase.seedSampleData() + return try! $0.defaultDatabase.read { db in + try Reminder + .join(RemindersList.all) { $0.remindersListID.eq($1.id) } + .fetchOne(db)! } } NavigationStack { diff --git a/Examples/Reminders/ReminderRow.swift b/Examples/Reminders/ReminderRow.swift index c112eaa3..245fb1c7 100644 --- a/Examples/Reminders/ReminderRow.swift +++ b/Examples/Reminders/ReminderRow.swift @@ -155,30 +155,29 @@ struct ReminderRow: View { } } -struct ReminderRowPreview: PreviewProvider { - static var previews: some View { - var reminder: Reminder! - var remindersList: RemindersList! - let _ = try! prepareDependencies { - $0.defaultDatabase = try Reminders.appDatabase() - try $0.defaultDatabase.read { db in - reminder = try Reminder.fetchOne(db) - remindersList = try RemindersList.fetchOne(db)! - } +#Preview( + traits: .dependencies { + $0.defaultDatabase = try Reminders.appDatabase() + try $0.defaultDatabase.seedSampleData() + } +) { + @Dependency(\.defaultDatabase) var database + let (reminder, remindersList) = { + try! database.read { db in + (try Reminder.fetchOne(db)!, try RemindersList.fetchOne(db)!) } - - NavigationStack { - List { - ReminderRow( - color: remindersList.color, - isPastDue: false, - notes: reminder.notes.replacingOccurrences(of: "\n", with: " "), - reminder: reminder, - remindersList: remindersList, - showCompleted: true, - tags: "#point-free #adulting" - ) - } + }() + NavigationStack { + List { + ReminderRow( + color: remindersList.color, + isPastDue: false, + notes: reminder.notes.replacingOccurrences(of: "\n", with: " "), + reminder: reminder, + remindersList: remindersList, + showCompleted: true, + tags: "#point-free #adulting" + ) } } } diff --git a/Examples/Reminders/RemindersDetail.swift b/Examples/Reminders/RemindersDetail.swift index a9cd8840..2cb5e8f0 100644 --- a/Examples/Reminders/RemindersDetail.swift +++ b/Examples/Reminders/RemindersDetail.swift @@ -361,27 +361,50 @@ extension RemindersDetailModel.DetailType { } } -struct RemindersDetailPreview: PreviewProvider { - static var previews: some View { - let (remindersList, tag) = try! prepareDependencies { - $0.defaultDatabase = try Reminders.appDatabase() - return try $0.defaultDatabase.read { db in - ( - try RemindersList.fetchOne(db)!, - try Tag.fetchOne(db)! - ) - } +#Preview( + "All", + traits: .dependencies { + $0.defaultDatabase = try Reminders.appDatabase() + try $0.defaultDatabase.seedSampleData() + } +) { + NavigationStack { + RemindersDetailView(model: RemindersDetailModel(detailType: .all)) + } +} + +#Preview( + "Reminders list", + traits: .dependencies { + $0.defaultDatabase = try Reminders.appDatabase() + try $0.defaultDatabase.seedSampleData() + } +) { + let remindersList = { + @Dependency(\.defaultDatabase) var database + return try! database.read { db in + try RemindersList.fetchOne(db)! } - let detailTypes: [RemindersDetailModel.DetailType] = [ - .all, - .remindersList(remindersList), - .tags([tag]), - ] - ForEach(detailTypes, id: \.self) { detailType in - NavigationStack { - RemindersDetailView(model: RemindersDetailModel(detailType: detailType)) - } - .previewDisplayName(detailType.navigationTitle) + }() + NavigationStack { + RemindersDetailView(model: RemindersDetailModel(detailType: .remindersList(remindersList))) + } +} + +#Preview( + "Tags", + traits: .dependencies { + $0.defaultDatabase = try Reminders.appDatabase() + try $0.defaultDatabase.seedSampleData() + } +) { + let tag = { + @Dependency(\.defaultDatabase) var database + return try! database.read { db in + try Tag.offset(2).fetchOne(db)! } + }() + NavigationStack { + RemindersDetailView(model: RemindersDetailModel(detailType: .tags([tag]))) } } diff --git a/Examples/Reminders/RemindersLists.swift b/Examples/Reminders/RemindersLists.swift index 11080ec3..b54d826a 100644 --- a/Examples/Reminders/RemindersLists.swift +++ b/Examples/Reminders/RemindersLists.swift @@ -433,11 +433,12 @@ private struct ReminderGridCell: View { } } -#Preview { - let _ = try! prepareDependencies { +#Preview( + traits: .dependencies { try $0.bootstrapDatabase() try? $0.defaultDatabase.seedSampleData() } +) { NavigationStack { RemindersListsView(model: RemindersListsModel()) } diff --git a/Examples/Reminders/SearchReminders.swift b/Examples/Reminders/SearchReminders.swift index 9c33dfca..43de864e 100644 --- a/Examples/Reminders/SearchReminders.swift +++ b/Examples/Reminders/SearchReminders.swift @@ -247,12 +247,13 @@ struct SearchRemindersView: View { } } -#Preview { - @Previewable @State var searchText = "take" - let _ = try! prepareDependencies { +#Preview( + traits: .dependencies { try $0.bootstrapDatabase() try? $0.defaultDatabase.seedSampleData() } +) { + @Previewable @State var searchText = "take" NavigationStack { List { if !searchText.isEmpty { diff --git a/Examples/Reminders/TagsForm.swift b/Examples/Reminders/TagsForm.swift index ae97a2b4..3e2b080b 100644 --- a/Examples/Reminders/TagsForm.swift +++ b/Examples/Reminders/TagsForm.swift @@ -164,11 +164,12 @@ private struct TagView: View { } } -#Preview { - @Previewable @State var tags: [Tag] = [] - let _ = try! prepareDependencies { +#Preview( + traits: .dependencies { try $0.bootstrapDatabase() try? $0.defaultDatabase.seedSampleData() } +) { + @Previewable @State var tags: [Tag] = [] TagsView(selectedTags: $tags) } diff --git a/Examples/SyncUps/App.swift b/Examples/SyncUps/App.swift index dffcd2bb..3e0908f1 100644 --- a/Examples/SyncUps/App.swift +++ b/Examples/SyncUps/App.swift @@ -76,10 +76,12 @@ struct AppView: View { } } -#Preview("Happy path") { - let _ = try! prepareDependencies { +#Preview( + "Happy path", + traits: .dependencies { try $0.bootstrapDatabase() try? $0.defaultDatabase.seedSampleData() } +) { AppView(model: AppModel()) } diff --git a/Examples/SyncUps/SyncUpDetail.swift b/Examples/SyncUps/SyncUpDetail.swift index 212f88cf..0e948f88 100644 --- a/Examples/SyncUps/SyncUpDetail.swift +++ b/Examples/SyncUps/SyncUpDetail.swift @@ -270,14 +270,18 @@ struct MeetingView: View { } } -#Preview { - let syncUp = try! prepareDependencies { +#Preview( + traits: .dependencies { try $0.bootstrapDatabase() try? $0.defaultDatabase.seedSampleData() - return try $0.defaultDatabase.read { db in + } +) { + let syncUp = { + @Dependency(\.defaultDatabase) var database + return try! database.read { db in try SyncUp.fetchOne(db)! } - } + }() NavigationStack { SyncUpDetailView(model: SyncUpDetailModel(syncUp: syncUp)) } diff --git a/Examples/SyncUps/SyncUpsList.swift b/Examples/SyncUps/SyncUpsList.swift index 7630c792..5a1db14b 100644 --- a/Examples/SyncUps/SyncUpsList.swift +++ b/Examples/SyncUps/SyncUpsList.swift @@ -151,11 +151,12 @@ private struct SeedDatabaseTip: Tip { } } -#Preview { - let _ = try! prepareDependencies { +#Preview( + traits: .dependencies { try $0.bootstrapDatabase() try? $0.defaultDatabase.seedSampleData() } +) { NavigationStack { SyncUpsList(model: SyncUpsListModel()) } diff --git a/Sources/SQLiteData/Documentation.docc/Articles/CloudKitSync.md b/Sources/SQLiteData/Documentation.docc/Articles/CloudKitSync.md index 7c189a6c..dfe74367 100644 --- a/Sources/SQLiteData/Documentation.docc/Articles/CloudKitSync.md +++ b/Sources/SQLiteData/Documentation.docc/Articles/CloudKitSync.md @@ -672,13 +672,14 @@ struct MySuite { } ``` -And in previews you can use it like so: +And in previews you can use it with the `.dependencies` preview trait like so: ```swift -#Preview { - try! prepareDependencies { - try! $0.bootstrapDatabase() +#Preview( + traits: .dependencies { + try $0.bootstrapDatabase() } +) { // ... } ``` diff --git a/Sources/SQLiteData/Documentation.docc/Articles/PreparingDatabase.md b/Sources/SQLiteData/Documentation.docc/Articles/PreparingDatabase.md index 7745d6ae..fa66af8d 100644 --- a/Sources/SQLiteData/Documentation.docc/Articles/PreparingDatabase.md +++ b/Sources/SQLiteData/Documentation.docc/Articles/PreparingDatabase.md @@ -279,17 +279,53 @@ class AppDelegate: NSObject, UIApplicationDelegate { And if using something besides UIKit or SwiftUI, then simply set the `defaultDatabase` as early as possible in the application's lifecycle. -It is also important to prepare the database in Xcode previews. This can be done like so: +It is also important to prepare the database in Xcode previews. This can be done using the +`.dependencies` preview trait from the +[Dependencies](https://github.com/pointfreeco/swift-dependencies) library, which is automatically +included with SQLiteData: ```swift -#Preview { - let _ = prepareDependencies { - $0.defaultDatabase = try! appDatabase() +import Dependencies +import SQLiteData + +#Preview( + traits: .dependencies { + $0.defaultDatabase = try appDatabase() } +) { // ... } ``` +> Note: The `.dependencies` preview trait requires iOS 18, macOS 15, tvOS 18, watchOS 11, or +> visionOS 2. If your deployment target is earlier than that, you can invoke +> `prepareDependencies` from the body of the preview, instead: +> +> ```swift +> #Preview { +> let _ = prepareDependencies { +> $0.defaultDatabase = try! appDatabase() +> } +> // ... +> } +> ``` + +> Important: Due to a known issue in Xcode, macro-generated members, such as a `@Table`'s `Draft` +> type or the properties of its `TableColumns` type, cannot be referenced from inside another +> macro, including `#Preview`. If your preview uses such members, define it as a `PreviewProvider` +> conformance instead, where you can prepare the database with `prepareDependencies`: +> +> ```swift +> struct FeaturePreviews: PreviewProvider { +> static var previews: some View { +> let _ = try! prepareDependencies { +> $0.defaultDatabase = try appDatabase() +> } +> FeatureView(item: Item.Draft()) +> } +> } +> ``` + And similarly, in tests, this can be done using the `.dependency` testing trait from [DependenciesTestSupport](https://github.com/pointfreeco/swift-dependencies): diff --git a/Sources/SQLiteData/StructuredQueries+GRDB/DefaultDatabase.swift b/Sources/SQLiteData/StructuredQueries+GRDB/DefaultDatabase.swift index 2f70021d..7892cbaa 100644 --- a/Sources/SQLiteData/StructuredQueries+GRDB/DefaultDatabase.swift +++ b/Sources/SQLiteData/StructuredQueries+GRDB/DefaultDatabase.swift @@ -113,12 +113,13 @@ extension DependencyValues { case .preview: return """ A blank, in-memory database is being used. To set the database that is used by \ - 'SQLiteData' in a preview, use a tool like 'prepareDependencies': + 'SQLiteData' in a preview, use the '.dependencies' preview trait: - #Preview { - let _ = prepareDependencies { - $0.defaultDatabase = try! DatabaseQueue(/* ... */) + #Preview( + traits: .dependencies { + $0.defaultDatabase = try DatabaseQueue(/* ... */) } + ) { // ... } """