diff --git a/Examples/Examples.xcodeproj/project.pbxproj b/Examples/Examples.xcodeproj/project.pbxproj index a7d7bc4c..dea4283b 100644 --- a/Examples/Examples.xcodeproj/project.pbxproj +++ b/Examples/Examples.xcodeproj/project.pbxproj @@ -76,6 +76,7 @@ DCA44CFB2D5D9D21008D4E76 /* Exceptions for "SyncUps" folder in "SyncUps" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( + Info.plist, README.md, ); target = DCBE89CB2D483FB90071F499 /* SyncUps */; @@ -884,11 +885,14 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = SyncUps/SyncUps.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"SyncUps/Preview Content\""; + DEVELOPMENT_TEAM = VFRXY8HC3H; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SyncUps/Info.plist; INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "To transcribe meeting notes."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; @@ -900,7 +904,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.SyncUps; + PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.SQLiteData.SyncUps; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; TARGETED_DEVICE_FAMILY = "1,2"; @@ -912,11 +916,14 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = SyncUps/SyncUps.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"SyncUps/Preview Content\""; + DEVELOPMENT_TEAM = VFRXY8HC3H; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SyncUps/Info.plist; INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "To transcribe meeting notes."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; @@ -928,7 +935,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.SyncUps; + PRODUCT_BUNDLE_IDENTIFIER = co.pointfree.SQLiteData.SyncUps; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1006,7 +1013,7 @@ /* Begin XCLocalSwiftPackageReference section */ DCD9AC892E02176700FB20F8 /* XCLocalSwiftPackageReference ".." */ = { isa = XCLocalSwiftPackageReference; - relativePath = ".."; + relativePath = ..; }; /* End XCLocalSwiftPackageReference section */ 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Examples/SyncUpTests/Internal.swift b/Examples/SyncUpTests/Internal.swift index c3d9251f..4db25057 100644 --- a/Examples/SyncUpTests/Internal.swift +++ b/Examples/SyncUpTests/Internal.swift @@ -4,7 +4,7 @@ import SQLiteData @testable import SyncUps extension Database { - func seedSyncUpFormTests() throws { + func seed() throws { try seed { SyncUp(id: UUID(1), seconds: 60, theme: .appOrange, title: "Design") SyncUp(id: UUID(2), seconds: 60 * 10, theme: .periwinkle, title: "Engineering") diff --git a/Examples/SyncUpTests/SyncUpFormTests.swift b/Examples/SyncUpTests/SyncUpFormTests.swift index a1aa462a..cc383b36 100644 --- a/Examples/SyncUpTests/SyncUpFormTests.swift +++ b/Examples/SyncUpTests/SyncUpFormTests.swift @@ -9,8 +9,10 @@ import Testing @Suite( .dependencies { - $0.defaultDatabase = try! SyncUps.appDatabase() - try! $0.defaultDatabase.write { try $0.seedSyncUpFormTests() } + try $0.bootstrapDatabase() + try $0.defaultDatabase.write { db in + try db.seed() + } $0.uuid = .incrementing } ) diff --git a/Examples/SyncUps/App.swift b/Examples/SyncUps/App.swift index bce63a1c..608046a4 100644 --- a/Examples/SyncUps/App.swift +++ b/Examples/SyncUps/App.swift @@ -77,8 +77,6 @@ struct AppView: View { } #Preview("Happy path") { - let _ = try! prepareDependencies { - $0.defaultDatabase = try SyncUps.appDatabase() - } + let _ = try! prepareDependencies { try $0.bootstrapDatabase() } AppView(model: AppModel()) } diff --git a/Examples/SyncUps/Info.plist b/Examples/SyncUps/Info.plist new file mode 100644 index 00000000..ca9a074a --- /dev/null +++ b/Examples/SyncUps/Info.plist @@ -0,0 +1,10 @@ + + + + + UIBackgroundModes + + remote-notification + + + diff --git a/Examples/SyncUps/Schema.swift b/Examples/SyncUps/Schema.swift index 8deead50..51a152f1 100644 --- a/Examples/SyncUps/Schema.swift +++ b/Examples/SyncUps/Schema.swift @@ -75,73 +75,76 @@ extension Int { } } -func appDatabase() throws -> any DatabaseWriter { - @Dependency(\.context) var context - var configuration = Configuration() - configuration.foreignKeysEnabled = true - configuration.prepareDatabase { db in - #if DEBUG - db.trace(options: .profile) { - if context == .preview { - print("\($0.expandedDescription)") - } else { - logger.debug("\($0.expandedDescription)") +extension DependencyValues { + mutating func bootstrapDatabase() throws { + @Dependency(\.context) var context + var configuration = Configuration() + configuration.foreignKeysEnabled = true + configuration.prepareDatabase { db in + #if DEBUG + db.trace(options: .profile) { + if context == .preview { + print("\($0.expandedDescription)") + } else { + logger.debug("\($0.expandedDescription)") + } } - } - #endif - } - let database = try SQLiteData.defaultDatabase(configuration: configuration) - logger.debug( - """ - App database: - open "\(database.path)" - """ - ) - var migrator = DatabaseMigrator() - #if DEBUG - migrator.eraseDatabaseOnSchemaChange = true - #endif - migrator.registerMigration("Create initial tables") { db in - try #sql( + #endif + } + let database = try SQLiteData.defaultDatabase(configuration: configuration) + logger.debug( """ - CREATE TABLE "syncUps" ( - "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), - "seconds" INTEGER NOT NULL DEFAULT 300, - "theme" TEXT NOT NULL DEFAULT \(raw: Theme.bubblegum.rawValue), - "title" TEXT NOT NULL - ) + App database: + open "\(database.path)" """ ) - .execute(db) - try #sql( - """ - CREATE TABLE "attendees" ( - "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), - "name" TEXT NOT NULL, - "syncUpID" INTEGER NOT NULL, - - FOREIGN KEY("syncUpID") REFERENCES "syncUps"("id") ON DELETE CASCADE + var migrator = DatabaseMigrator() + #if DEBUG + migrator.eraseDatabaseOnSchemaChange = true + #endif + migrator.registerMigration("Create initial tables") { db in + try #sql( + """ + CREATE TABLE "syncUps" ( + "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), + "seconds" INTEGER NOT NULL ON CONFLICT REPLACE DEFAULT 300, + "theme" TEXT NOT NULL ON CONFLICT REPLACE DEFAULT \(raw: Theme.bubblegum.rawValue), + "title" TEXT NOT NULL ON CONFLICT REPLACE DEFAULT '' + ) STRICT + """ ) - """ - ) - .execute(db) - try #sql( - """ - CREATE TABLE "meetings" ( - "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), - "date" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP UNIQUE, - "syncUpID" INTEGER NOT NULL, - "transcript" TEXT NOT NULL, - - FOREIGN KEY("syncUpID") REFERENCES "syncUps"("id") ON DELETE CASCADE + .execute(db) + try #sql( + """ + CREATE TABLE "attendees" ( + "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), + "name" TEXT NOT NULL ON CONFLICT REPLACE DEFAULT '', + "syncUpID" TEXT NOT NULL REFERENCES "syncUps"("id") ON DELETE CASCADE + ) STRICT + """ ) - """ + .execute(db) + try #sql( + """ + CREATE TABLE "meetings" ( + "id" TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE DEFAULT (uuid()), + "date" TEXT NOT NULL ON CONFLICT REPLACE DEFAULT CURRENT_TIMESTAMP, + "syncUpID" TEXT NOT NULL REFERENCES "syncUps"("id") ON DELETE CASCADE, + "transcript" TEXT NOT NULL ON CONFLICT REPLACE DEFAULT '' + ) STRICT + """ + ) + .execute(db) + } + try migrator.migrate(database) + defaultDatabase = database + defaultSyncEngine = try SyncEngine( + for: database, + tables: SyncUp.self, + Attendee.self, + Meeting.self ) - .execute(db) } - - try migrator.migrate(database) - return database } private let logger = Logger(subsystem: "SyncUps", category: "Database") diff --git a/Examples/SyncUps/SyncUpDetail.swift b/Examples/SyncUps/SyncUpDetail.swift index f1568169..50accb52 100644 --- a/Examples/SyncUps/SyncUpDetail.swift +++ b/Examples/SyncUps/SyncUpDetail.swift @@ -272,7 +272,7 @@ struct MeetingView: View { #Preview { let syncUp = try! prepareDependencies { - $0.defaultDatabase = try SyncUps.appDatabase() + try $0.bootstrapDatabase() return try $0.defaultDatabase.read { db in try SyncUp.limit(1).fetchOne(db)! } diff --git a/Examples/SyncUps/SyncUps.entitlements b/Examples/SyncUps/SyncUps.entitlements new file mode 100644 index 00000000..c54cf631 --- /dev/null +++ b/Examples/SyncUps/SyncUps.entitlements @@ -0,0 +1,16 @@ + + + + + aps-environment + development + com.apple.developer.icloud-container-identifiers + + iCloud.co.pointfree.SQLiteData.SyncUps + + com.apple.developer.icloud-services + + CloudKit + + + diff --git a/Examples/SyncUps/SyncUpsApp.swift b/Examples/SyncUps/SyncUpsApp.swift index 97e1cd4c..83abea24 100644 --- a/Examples/SyncUps/SyncUpsApp.swift +++ b/Examples/SyncUps/SyncUpsApp.swift @@ -8,7 +8,7 @@ struct SyncUpsApp: App { init() { if !isTesting { try! prepareDependencies { - $0.defaultDatabase = try SyncUps.appDatabase() + try $0.bootstrapDatabase() } } } diff --git a/Examples/SyncUps/SyncUpsList.swift b/Examples/SyncUps/SyncUpsList.swift index 8d065080..85d4bf9d 100644 --- a/Examples/SyncUps/SyncUpsList.swift +++ b/Examples/SyncUps/SyncUpsList.swift @@ -153,7 +153,7 @@ private struct SeedDatabaseTip: Tip { #Preview { let _ = try! prepareDependencies { - $0.defaultDatabase = try SyncUps.appDatabase() + try $0.bootstrapDatabase() } NavigationStack { SyncUpsList(model: SyncUpsListModel())