import Combine import Foundation import GRDB import SwiftUI // MARK: - Models protocol typealias DBStorable = Codable & FetchableRecord & Identifiable & PersistableRecord & TableRecord // MARK: - Database init final class Database { static let shared = Database() let dbQueue: DatabaseQueue private var dbPath: String private init() { do { // Create db folder if not exists let fileManager = FileManager.default let appSupportURL = try fileManager.url( for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true ) let directoryURL = appSupportURL.appendingPathComponent("ConversationsClassic", isDirectory: true) try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true) // Open or create the database let databaseURL = directoryURL.appendingPathComponent("db.sqlite") dbQueue = try DatabaseQueue(path: databaseURL.path, configuration: Database.config) dbPath = databaseURL.path // Some debug info #if DEBUG print("Database path: \(databaseURL.path)") #endif // Apply migrations try Database.migrator.migrate(dbQueue) } catch { fatalError("Database initialization failed: \(error)") } } } // MARK: - Config private extension Database { static let config: Configuration = { var config = Configuration() #if DEBUG // verbose and debugging in DEBUG builds only. config.publicStatementArguments = true config.prepareDatabase { db in db.trace { print("SQL> \($0)\n") } } #endif return config }() } // MARK: - flush all data for debug #if DEBUG extension Database { func flushAllData() { // nullable queue and remove db file do { try FileManager.default.removeItem(atPath: dbPath) } catch { print("Error: \(error)") } } } #endif