Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed the query result row cap returning a single row when it was set to unlimited. (#1884)
- Fixed SSH tunnels that could accept a database connection and then go quiet instead of forwarding it or failing, which showed up as MySQL and MariaDB connections timing out while reading the server greeting. A tunnel that cannot open its forwarding channel now gives up after 10 seconds, closes the connection, and logs the reason, instead of leaving the driver to wait out its own timeout with no explanation. (#1883)
- Fixed connections being reset when a single database session opened several at once through one SSH tunnel, which could happen while browsing schemas. (#1883)
- Fixed the connection form's SSH tunnel Socket Path hint always showing the PostgreSQL socket path. It now shows the right default for the database type, such as `/var/run/mysqld/mysqld.sock` for MySQL and MariaDB. (#1902)
- Per-column display formats (Display As) are now kept per table, so two tables with the same name in different databases or schemas no longer share formatting.
- Reopening a table now restores a saved filter's AND/OR match mode, instead of always resetting it to AND.

Expand Down
5 changes: 5 additions & 0 deletions TablePro/Core/Plugins/PluginManager+Registration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,11 @@ extension PluginManager {
.schema.containerEntityName ?? "Database"
}

func defaultUnixSocketPath(for databaseType: DatabaseType) -> String? {
PluginMetadataRegistry.shared.snapshot(forTypeId: databaseType.pluginTypeId)?
.connection.defaultUnixSocketPath
Comment on lines +401 to +402

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the concrete type for socket path metadata

When the connection form is opened for a PostgreSQL-backed alias such as Redshift or CockroachDB, databaseType.pluginTypeId resolves to PostgreSQL via the registry aliases, so this lookup returns /var/run/postgresql/.s.PGSQL.5432 even though those concrete snapshots do not define a Unix-socket convention. That leaves the new per-type placeholder wrong for those database types; this UI metadata should be read from the concrete type snapshot instead of the driver lookup ID.

Useful? React with 👍 / 👎.

}

func containerEntityNamePlural(for databaseType: DatabaseType) -> String {
containerEntityName(for: databaseType) + "s"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ extension PluginMetadataRegistry {
)
],
category: .keyValue,
tagline: String(localized: "In-memory data store and cache")
tagline: String(localized: "In-memory data store and cache"),
defaultUnixSocketPath: "/var/run/redis/redis.sock"
)
)),
("SQL Server", PluginMetadataSnapshot(
Expand Down
17 changes: 12 additions & 5 deletions TablePro/Core/Plugins/PluginMetadataRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,17 +171,20 @@ struct PluginMetadataSnapshot: Sendable {
let category: DatabaseCategory
let tagline: String
let hidesBuiltInPassword: Bool
let defaultUnixSocketPath: String?

init(
additionalConnectionFields: [ConnectionField] = [],
category: DatabaseCategory = .other,
tagline: String = "",
hidesBuiltInPassword: Bool = false
hidesBuiltInPassword: Bool = false,
defaultUnixSocketPath: String? = nil
) {
self.additionalConnectionFields = additionalConnectionFields
self.category = category
self.tagline = tagline
self.hidesBuiltInPassword = hidesBuiltInPassword
self.defaultUnixSocketPath = defaultUnixSocketPath
}

static let defaults = ConnectionConfig()
Expand Down Expand Up @@ -543,7 +546,8 @@ final class PluginMetadataRegistry: @unchecked Sendable {
connection: PluginMetadataSnapshot.ConnectionConfig(
additionalConnectionFields: awsIAMFields,
category: .relational,
tagline: String(localized: "Most popular open-source SQL database")
tagline: String(localized: "Most popular open-source SQL database"),
defaultUnixSocketPath: "/var/run/mysqld/mysqld.sock"
)
)),
("MariaDB", PluginMetadataSnapshot(
Expand Down Expand Up @@ -594,7 +598,8 @@ final class PluginMetadataRegistry: @unchecked Sendable {
connection: PluginMetadataSnapshot.ConnectionConfig(
additionalConnectionFields: awsIAMFields,
category: .relational,
tagline: String(localized: "Open-source fork of MySQL")
tagline: String(localized: "Open-source fork of MySQL"),
defaultUnixSocketPath: "/var/run/mysqld/mysqld.sock"
)
)),
("PostgreSQL", PluginMetadataSnapshot(
Expand Down Expand Up @@ -646,7 +651,8 @@ final class PluginMetadataRegistry: @unchecked Sendable {
connection: PluginMetadataSnapshot.ConnectionConfig(
additionalConnectionFields: [pgpassField, connectionOptionsField] + awsIAMFields,
category: .relational,
tagline: String(localized: "Advanced object-relational SQL")
tagline: String(localized: "Advanced object-relational SQL"),
defaultUnixSocketPath: "/var/run/postgresql/.s.PGSQL.5432"
)
)),
("Redshift", PluginMetadataSnapshot(
Expand Down Expand Up @@ -1023,7 +1029,8 @@ final class PluginMetadataRegistry: @unchecked Sendable {
?? Self.fallbackCategory(forTypeId: driverType.databaseTypeId),
tagline: existingSnapshot?.connection.tagline
?? Self.fallbackTagline(forTypeId: driverType.databaseTypeId),
hidesBuiltInPassword: existingSnapshot?.connection.hidesBuiltInPassword ?? false
hidesBuiltInPassword: existingSnapshot?.connection.hidesBuiltInPassword ?? false,
defaultUnixSocketPath: existingSnapshot?.connection.defaultUnixSocketPath
)
)
}
Expand Down
2 changes: 1 addition & 1 deletion TablePro/Views/ConnectionForm/Panes/GeneralPaneView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ struct GeneralPaneView: View {
TextField(
String(localized: "Socket Path"),
text: $coordinator.network.sshForwardUnixSocketPath,
prompt: Text(verbatim: "/var/run/postgresql/.s.PGSQL.5432")
prompt: Text(verbatim: coordinator.network.socketPathPrompt)
)
switch coordinator.network.socketPathIssue {
case .notAbsolute:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ final class NetworkPaneViewModel {
return port == 0 ? "" : String(port)
}

var socketPathPrompt: String {
PluginManager.shared.defaultUnixSocketPath(for: type) ?? "/path/to/database.sock"
}

var resolvedHost: String {
host.trimmingCharacters(in: .whitespaces).isEmpty ? "localhost" : host
}
Expand Down
41 changes: 41 additions & 0 deletions TableProTests/Core/Plugins/SocketPathPlaceholderTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// SocketPathPlaceholderTests.swift
// TableProTests
//

import Foundation
@testable import TablePro
import TableProPluginKit
import Testing

@MainActor
@Suite("Default Unix socket path per database type")
struct SocketPathPlaceholderTests {
@Test("MySQL and MariaDB use the mysqld socket")
func mysqlFamilyUsesMysqldSocket() {
#expect(PluginManager.shared.defaultUnixSocketPath(for: .mysql) == "/var/run/mysqld/mysqld.sock")
#expect(PluginManager.shared.defaultUnixSocketPath(for: .mariadb) == "/var/run/mysqld/mysqld.sock")
}

@Test("PostgreSQL uses the PGSQL socket")
func postgresqlUsesPgsqlSocket() {
#expect(PluginManager.shared.defaultUnixSocketPath(for: .postgresql) == "/var/run/postgresql/.s.PGSQL.5432")
}

@Test("Redis uses the redis socket")
func redisUsesRedisSocket() {
#expect(PluginManager.shared.defaultUnixSocketPath(for: .redis) == "/var/run/redis/redis.sock")
}

@Test("Types without a socket convention have no default")
func typesWithoutSocketHaveNoDefault() {
#expect(PluginManager.shared.defaultUnixSocketPath(for: .sqlite) == nil)
#expect(PluginManager.shared.defaultUnixSocketPath(for: .clickhouse) == nil)
}

@Test("Unknown type has no default")
func unknownTypeHasNoDefault() {
let unknown = DatabaseType(rawValue: "FuturePlugin")
#expect(PluginManager.shared.defaultUnixSocketPath(for: unknown) == nil)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,23 @@ struct NetworkPaneSocketForwardTests {
#expect(fields[DatabaseConnection.sshForwardUnixSocketPathKey] == nil)
#expect(viewModel.forwardsToUnixSocket == false)
}

@Test("The socket path prompt follows the database type")
func socketPromptFollowsType() {
let viewModel = NetworkPaneViewModel()

viewModel.type = .mysql
#expect(viewModel.socketPathPrompt == "/var/run/mysqld/mysqld.sock")

viewModel.type = .postgresql
#expect(viewModel.socketPathPrompt == "/var/run/postgresql/.s.PGSQL.5432")
}

@Test("A type without a socket convention falls back to a generic prompt")
func socketPromptFallsBackForSocketlessType() {
let viewModel = NetworkPaneViewModel()
viewModel.type = .clickhouse

#expect(viewModel.socketPathPrompt == "/path/to/database.sock")
}
}
Loading