Files
iOS/Sources/Shared/Database/GRDB+Initialization.swift
Bruno Pantaleão Gonçalves 3e82dd7aa7 Persist HA Areas in App database (#3942)
Introduces the AppArea model, its database table, and related query
utilities for managing Home Assistant areas and their entities. Updates
the database initialization and updater logic to support caching and
persisting areas per server, including migration and fetch helpers.

<!-- Thank you for submitting a Pull Request and helping to improve Home
Assistant. Please complete the following sections to help the processing
and review of your changes. Please do not delete anything from this
template. -->

## Summary
<!-- Provide a brief summary of the changes you have made and most
importantly what they aim to achieve -->

## Screenshots
<!-- If this is a user-facing change not in the frontend, please include
screenshots in light and dark mode. -->

## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a
corresponding pull request in the Companion App Documentation repository
(https://github.com/home-assistant/companion.home-assistant). Please add
the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#

## Any other notes
<!-- If there is any other information of note, like if this Pull
Request is part of a bigger change, please include it here. -->

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-07 12:57:07 +01:00

79 lines
2.9 KiB
Swift

import Foundation
import GRDB
public extension DatabaseQueue {
// Following GRDB cocnurrency rules, we have just one database instance
// https://swiftpackageindex.com/groue/grdb.swift/v6.29.3/documentation/grdb/concurrency#Concurrency-Rules
static var appDatabase: DatabaseQueue = {
do {
let database = try DatabaseQueue(path: databasePath())
// Create tables if needed
for table in DatabaseQueue.tables() {
do {
try table.createIfNeeded(database: database)
} catch {
let className = String(describing: type(of: table))
let errorMessage = "Failed create GRDB table \(className), error: \(error.localizedDescription)"
Current.clientEventStore.addEvent(ClientEvent(text: errorMessage, type: .database))
}
}
DatabaseQueue.deleteOldTables(database: database)
#if targetEnvironment(simulator)
print("GRDB App database is stored at \(AppConstants.appGRDBFile.description)")
#endif
return database
} catch {
let errorMessage = "Failed to initialize GRDB, error: \(error.localizedDescription)"
Current.Log.error(errorMessage)
fatalError(errorMessage)
}
}()
static func databasePath() -> String {
// Path for tests
if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil {
let tempDirectory = NSTemporaryDirectory()
return (tempDirectory as NSString).appendingPathComponent("test_database.sqlite")
} else {
// Path for App use
return AppConstants.appGRDBFile.path
}
}
internal static func tables() -> [DatabaseTableProtocol] {
[
HAppEntityTable(),
WatchConfigTable(),
CarPlayConfigTable(),
AssistPipelinesTable(),
AppEntityRegistryListForDisplayTable(),
AppPanelTable(),
CustomWidgetTable(),
AppAreaTable(),
]
}
internal static func deleteOldTables(database: DatabaseQueue) {
do {
/*
ClientEvent used to be saved in GRDB, but because of a problem of one process holding
lock on the database and causing crash 0xdead10cc now it is saved as a json file
More information: https://github.com/groue/GRDB.swift/issues/1626#issuecomment-2623927815
*/
try database.write { db in
try db.drop(table: GRDBDatabaseTable.clientEvent.rawValue)
}
} catch {
let errorMessage =
"Failed or not needed delete client event GRDB info, error: \(error.localizedDescription)"
Current.Log.verbose(errorMessage)
}
}
}
protocol DatabaseTableProtocol {
func createIfNeeded(database: DatabaseQueue) throws
}