Skip to content

Commit ccf10a1

Browse files
authored
feat: replace hardcoded DatabaseType switches with dynamic plugin metadata lookups (#307) (#307)
1 parent 69d0634 commit ccf10a1

25 files changed

Lines changed: 166 additions & 149 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020
- `FilterSQLGenerator` now uses `SQLDialectDescriptor` data (regex syntax, boolean literals, LIKE escape style, pagination style) instead of `DatabaseType` switch statements
2121
- Moved identifier quoting, autocomplete statement completions, view templates, and FK disable/enable into plugin system
2222
- Removed `DatabaseType` switches from `FilterSQLGenerator`, `SQLCompletionProvider`, `ImportDataSinkAdapter`, and `MainContentCoordinator+SidebarActions`
23+
- Replaced hardcoded `DatabaseType` switches in ExportDialog, DataChangeManager, SafeModeGuard, ExportService, DataGridView, HighlightedSQLTextView, ForeignKeyPopoverContentView, QueryTab, SQLRowToStatementConverter, SessionStateFactory, ConnectionToolbarState, and DatabaseSwitcherSheet with dynamic plugin lookups (`databaseGroupingStrategy`, `immutableColumns`, `supportsReadOnlyMode`, `paginationStyle`, `editorLanguage`, `connectionMode`, `supportsSchemaSwitching`)
2324

2425
### Added
2526

Plugins/ClickHouseDriverPlugin/ClickHousePlugin.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ final class ClickHousePlugin: NSObject, TableProPlugin, DriverPlugin {
9191
regexSyntax: .match,
9292
booleanLiteralStyle: .numeric,
9393
likeEscapeStyle: .implicit,
94-
paginationStyle: .limit
94+
paginationStyle: .limit,
95+
requiresBackslashEscaping: true
9596
)
9697

9798
func createDriver(config: DriverConnectionConfig) -> any PluginDatabaseDriver {

Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ final class MSSQLPlugin: NSObject, TableProPlugin, DriverPlugin {
2626

2727
static let brandColorHex = "#E34517"
2828
static let systemDatabaseNames: [String] = ["master", "tempdb", "model", "msdb"]
29+
static let defaultSchemaName = "dbo"
2930
static let databaseGroupingStrategy: GroupingStrategy = .bySchema
3031
static let columnTypesByCategory: [String: [String]] = [
3132
"Integer": ["TINYINT", "SMALLINT", "INT", "BIGINT"],

Plugins/MongoDBDriverPlugin/MongoDBPlugin.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ final class MongoDBPlugin: NSObject, TableProPlugin, DriverPlugin {
5555
static let systemDatabaseNames: [String] = ["admin", "local", "config"]
5656
static let tableEntityName = "Collections"
5757
static let supportsForeignKeyDisable = false
58+
static let immutableColumns: [String] = ["_id"]
59+
static let supportsReadOnlyMode = false
5860
static let databaseGroupingStrategy: GroupingStrategy = .flat
5961
static let columnTypesByCategory: [String: [String]] = [
6062
"String": ["string", "objectId", "regex"],

Plugins/MySQLDriverPlugin/MySQLPlugin.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ final class MySQLPlugin: NSObject, TableProPlugin, DriverPlugin {
8181
regexSyntax: .regexp,
8282
booleanLiteralStyle: .numeric,
8383
likeEscapeStyle: .implicit,
84-
paginationStyle: .limit
84+
paginationStyle: .limit,
85+
requiresBackslashEscaping: true
8586
)
8687

8788
func createDriver(config: DriverConnectionConfig) -> any PluginDatabaseDriver {

Plugins/PostgreSQLDriverPlugin/PostgreSQLPlugin.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ final class PostgreSQLPlugin: NSObject, TableProPlugin, DriverPlugin {
2929
static let urlSchemes: [String] = ["postgresql", "postgres"]
3030
static let brandColorHex = "#336791"
3131
static let systemDatabaseNames: [String] = ["postgres", "template0", "template1"]
32+
static let supportsSchemaSwitching = true
3233
static let databaseGroupingStrategy: GroupingStrategy = .bySchema
3334
static let columnTypesByCategory: [String: [String]] = [
3435
"Integer": ["SMALLINT", "INTEGER", "BIGINT", "SERIAL", "BIGSERIAL", "SMALLSERIAL"],

Plugins/RedisDriverPlugin/RedisPlugin.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ final class RedisPlugin: NSObject, TableProPlugin, DriverPlugin {
4444
static let supportsImport = false
4545
static let tableEntityName = "Keys"
4646
static let supportsForeignKeyDisable = false
47+
static let supportsReadOnlyMode = false
4748
static let databaseGroupingStrategy: GroupingStrategy = .flat
4849
static let defaultGroupName = "db0"
4950
static let columnTypesByCategory: [String: [String]] = [

Plugins/TableProPluginKit/DriverPlugin.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ public protocol DriverPlugin: TableProPlugin {
3939
static var tableEntityName: String { get }
4040
static var supportsCascadeDrop: Bool { get }
4141
static var supportsForeignKeyDisable: Bool { get }
42+
static var immutableColumns: [String] { get }
43+
static var supportsReadOnlyMode: Bool { get }
44+
static var defaultSchemaName: String { get }
4245
}
4346

4447
public extension DriverPlugin {
@@ -82,4 +85,7 @@ public extension DriverPlugin {
8285
static var tableEntityName: String { "Tables" }
8386
static var supportsCascadeDrop: Bool { false }
8487
static var supportsForeignKeyDisable: Bool { true }
88+
static var immutableColumns: [String] { [] }
89+
static var supportsReadOnlyMode: Bool { true }
90+
static var defaultSchemaName: String { "public" }
8591
}

Plugins/TableProPluginKit/SQLDialectDescriptor.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public struct SQLDialectDescriptor: Sendable {
2222
public let likeEscapeStyle: LikeEscapeStyle
2323
public let paginationStyle: PaginationStyle
2424
public let offsetFetchOrderBy: String
25+
public let requiresBackslashEscaping: Bool
2526

2627
public enum RegexSyntax: String, Sendable {
2728
case regexp // MySQL: column REGEXP 'pattern'
@@ -57,7 +58,8 @@ public struct SQLDialectDescriptor: Sendable {
5758
booleanLiteralStyle: BooleanLiteralStyle = .numeric,
5859
likeEscapeStyle: LikeEscapeStyle = .explicit,
5960
paginationStyle: PaginationStyle = .limit,
60-
offsetFetchOrderBy: String = "ORDER BY (SELECT NULL)"
61+
offsetFetchOrderBy: String = "ORDER BY (SELECT NULL)",
62+
requiresBackslashEscaping: Bool = false
6163
) {
6264
self.identifierQuote = identifierQuote
6365
self.keywords = keywords
@@ -69,5 +71,6 @@ public struct SQLDialectDescriptor: Sendable {
6971
self.likeEscapeStyle = likeEscapeStyle
7072
self.paginationStyle = paginationStyle
7173
self.offsetFetchOrderBy = offsetFetchOrderBy
74+
self.requiresBackslashEscaping = requiresBackslashEscaping
7275
}
7376
}

TablePro/Core/ChangeTracking/DataChangeManager.swift

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -647,24 +647,12 @@ final class DataChangeManager {
647647
deletedRowIndices: deletedRowIndices,
648648
insertedRowIndices: insertedRowIndices
649649
) {
650-
// Validate MongoDB _id requirement
651-
if databaseType == .mongodb {
652-
let expectedUpdates = changes.count(where: { $0.type == .update })
653-
let actualUpdates = statements.count(where: { $0.statement.contains("updateOne(") || $0.statement.contains("updateMany(") })
654-
655-
if expectedUpdates > 0 && actualUpdates < expectedUpdates {
656-
throw DatabaseError.queryFailed(
657-
"Cannot save UPDATE changes to collection '\(tableName)' without an _id field. " +
658-
"Please ensure the collection has _id values."
659-
)
660-
}
661-
}
662650
return statements.map { ParameterizedStatement(sql: $0.statement, parameters: $0.parameters) }
663651
}
664652
}
665653

666654
// Safety: prevent SQL generation for NoSQL databases if plugin driver is unavailable
667-
if databaseType == .mongodb || databaseType == .redis {
655+
if PluginManager.shared.editorLanguage(for: databaseType) != .sql {
668656
throw DatabaseError.queryFailed(
669657
"Cannot generate statements for \(databaseType.rawValue) — plugin driver not initialized"
670658
)

0 commit comments

Comments
 (0)