connection updates
This commit is contained in:
@@ -362,6 +362,8 @@ final class DatabaseModel: ObservableObject {
|
||||
}
|
||||
|
||||
@Published var selectedID: UUID?
|
||||
// Invalidate in-flight UI updates when a connection is switched or edited.
|
||||
private var connectionEpoch: UInt64 = 0
|
||||
@Published var queryTabs: [WorkbenchQueryTab] = [
|
||||
WorkbenchQueryTab(
|
||||
title: "Query 1",
|
||||
@@ -641,7 +643,7 @@ final class DatabaseModel: ObservableObject {
|
||||
activateQuery(tab.id)
|
||||
recordRecentSQLScript(url)
|
||||
NotificationCenter.default.post(name: .workbenchRevealSQLEditor, object: nil)
|
||||
status = "Opened \\(url.lastPathComponent)"
|
||||
status = "Opened \(url.lastPathComponent)"
|
||||
}
|
||||
|
||||
func saveSQLScript(asNewFile: Bool = false) {
|
||||
@@ -669,9 +671,9 @@ final class DatabaseModel: ObservableObject {
|
||||
queryTabs[index].fileURL = url
|
||||
queryTabs[index].title = url.lastPathComponent
|
||||
recordRecentSQLScript(url)
|
||||
status = "Saved \\(url.lastPathComponent)"
|
||||
status = "Saved \(url.lastPathComponent)"
|
||||
} catch {
|
||||
status = "Save failed: \\(error.localizedDescription)"
|
||||
status = "Save failed: \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,6 +683,7 @@ final class DatabaseModel: ObservableObject {
|
||||
guard let profile = profiles.first(where: { $0.id == id }) else { return }
|
||||
guard selectedID != id else { return }
|
||||
saveActiveQuery()
|
||||
connectionEpoch &+= 1
|
||||
if let oldID = selectedID { NativeMySQLRunner.disconnect(profileID: oldID) }
|
||||
result = QueryResult()
|
||||
isRunning = false
|
||||
@@ -702,6 +705,7 @@ final class DatabaseModel: ObservableObject {
|
||||
}
|
||||
|
||||
func save(_ profile: ConnectionProfile, password: String) {
|
||||
connectionEpoch &+= 1
|
||||
if let i = profiles.firstIndex(where: { $0.id == profile.id }) { profiles[i] = profile }
|
||||
else { profiles.append(profile) }
|
||||
PasswordStore.save(password, id: profile.id)
|
||||
@@ -734,6 +738,7 @@ final class DatabaseModel: ObservableObject {
|
||||
)
|
||||
|
||||
status = "Loading tables from \(database)…"
|
||||
let epoch = connectionEpoch
|
||||
|
||||
Task {
|
||||
do {
|
||||
@@ -743,6 +748,7 @@ final class DatabaseModel: ObservableObject {
|
||||
password: password,
|
||||
sql: "SHOW FULL TABLES FROM `\(escaped)`"
|
||||
)
|
||||
guard selectedID == profile.id, connectionEpoch == epoch else { return }
|
||||
|
||||
var tables: [String] = []
|
||||
var views: [String] = []
|
||||
@@ -776,6 +782,7 @@ final class DatabaseModel: ObservableObject {
|
||||
profile: profile, database: database, password: password,
|
||||
sql: "SELECT ROUTINE_NAME, ROUTINE_TYPE FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = '\(quotedSchema)' ORDER BY ROUTINE_NAME"
|
||||
)
|
||||
guard selectedID == profile.id, connectionEpoch == epoch else { return }
|
||||
schemaProcedures[database] = routineResult.rows.compactMap { row in
|
||||
row.count >= 2 && row[1].uppercased() == "PROCEDURE" ? row[0] : nil
|
||||
}
|
||||
@@ -783,6 +790,7 @@ final class DatabaseModel: ObservableObject {
|
||||
row.count >= 2 && row[1].uppercased() == "FUNCTION" ? row[0] : nil
|
||||
}
|
||||
} catch {
|
||||
guard selectedID == profile.id, connectionEpoch == epoch else { return }
|
||||
schemaProcedures[database] = []
|
||||
schemaFunctions[database] = []
|
||||
}
|
||||
@@ -798,6 +806,7 @@ final class DatabaseModel: ObservableObject {
|
||||
password: password,
|
||||
sql: "SELECT TABLE_NAME, COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '\(quotedSchema)' ORDER BY TABLE_NAME, ORDINAL_POSITION"
|
||||
)
|
||||
guard selectedID == profile.id, connectionEpoch == epoch else { return }
|
||||
var names = Set<String>()
|
||||
for row in columnResult.rows where row.count >= 2 {
|
||||
names.insert(row[1])
|
||||
@@ -805,6 +814,7 @@ final class DatabaseModel: ObservableObject {
|
||||
}
|
||||
if introspection(for: database) == nil { schemaColumns[database] = names.sorted() }
|
||||
} catch {
|
||||
guard selectedID == profile.id, connectionEpoch == epoch else { return }
|
||||
if introspection(for: database) == nil { schemaColumns[database] = [] }
|
||||
}
|
||||
|
||||
@@ -812,6 +822,7 @@ final class DatabaseModel: ObservableObject {
|
||||
// Revalidate column definitions as well as object names on reconnect/refresh.
|
||||
if introspection(for: database) != nil { introspect(database: database) }
|
||||
} catch {
|
||||
guard selectedID == profile.id, connectionEpoch == epoch else { return }
|
||||
status = "Unable to load tables: \(error.localizedDescription)"
|
||||
result = QueryResult(message: error.localizedDescription)
|
||||
}
|
||||
@@ -869,6 +880,7 @@ final class DatabaseModel: ObservableObject {
|
||||
let queryStarted = Date()
|
||||
status = "Executing…"
|
||||
let password = PasswordStore.read(profile.id)
|
||||
let epoch = connectionEpoch
|
||||
Task {
|
||||
var activeDB = listingDatabases ? "" : (selectedDatabase.isEmpty ? profile.database : selectedDatabase)
|
||||
do {
|
||||
@@ -879,6 +891,7 @@ final class DatabaseModel: ObservableObject {
|
||||
let parsed = try await NativeMySQLRunner.run(
|
||||
profile: profile, database: activeDB, password: password, sql: item
|
||||
)
|
||||
guard selectedID == profile.id, connectionEpoch == epoch else { return }
|
||||
lastResult = parsed
|
||||
if let usedSchema = SQLStatementSplitter.usedDatabase(item) {
|
||||
activeDB = usedSchema
|
||||
@@ -888,7 +901,7 @@ final class DatabaseModel: ObservableObject {
|
||||
introspect(database: usedSchema)
|
||||
}
|
||||
}
|
||||
guard selectedID == profile.id else { return }
|
||||
guard selectedID == profile.id, connectionEpoch == epoch else { return }
|
||||
if listingDatabases {
|
||||
databases = lastResult.rows.compactMap { $0.first }
|
||||
status = "Connected to \(profile.name)"
|
||||
@@ -905,7 +918,7 @@ final class DatabaseModel: ObservableObject {
|
||||
} catch {
|
||||
// An old connection must not overwrite the newly selected
|
||||
// connection's state when its request finishes later.
|
||||
guard selectedID == profile.id else { return }
|
||||
guard selectedID == profile.id, connectionEpoch == epoch else { return }
|
||||
status = "Error"
|
||||
result = QueryResult(message: error.localizedDescription)
|
||||
if !listingDatabases {
|
||||
@@ -915,7 +928,7 @@ final class DatabaseModel: ObservableObject {
|
||||
if !listingDatabases {
|
||||
queryDurationText = String(format: "%.3f s", Date().timeIntervalSince(queryStarted))
|
||||
}
|
||||
if selectedID == profile.id { isRunning = false }
|
||||
if selectedID == profile.id && connectionEpoch == epoch { isRunning = false }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user