Skip to content

Commit 51b45ca

Browse files
committed
fix: show database-specific options in Create Database dialog
1 parent b0291dc commit 51b45ca

7 files changed

Lines changed: 126 additions & 47 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717

1818
### Fixed
1919

20+
- Create Database dialog showing MySQL charset/collation options for all database types; now shows database-specific options (encoding/LC_COLLATE for PostgreSQL, hidden for Redis/etcd)
2021
- SSH Tunnel not working with `~/.ssh/config` profiles (#672): added `Include` directive support, SSH token expansion (`%d`, `%h`, `%u`, `%r`), multi-word `Host` filtering, and detailed handshake error messages
2122

2223
## [0.30.1] - 2026-04-10

Plugins/MySQLDriverPlugin/MySQLPluginDriver.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,9 @@ final class MySQLPluginDriver: PluginDatabaseDriver, @unchecked Sendable {
560560
func createDatabase(name: String, charset: String, collation: String?) async throws {
561561
let escapedName = name.replacingOccurrences(of: "`", with: "``")
562562

563-
let validCharsets = ["utf8mb4", "utf8", "latin1", "ascii"]
563+
let validCharsets = ["utf8mb4", "utf8mb3", "utf8", "latin1", "ascii",
564+
"binary", "utf16", "utf32", "cp1251", "big5",
565+
"euckr", "gb2312", "gbk", "sjis"]
564566
guard validCharsets.contains(charset) else {
565567
throw MariaDBPluginError(code: 0, message: "Invalid character set: \(charset)", sqlState: nil)
566568
}

Plugins/PostgreSQLDriverPlugin/PostgreSQLPluginDriver.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,8 @@ final class PostgreSQLPluginDriver: PluginDatabaseDriver, @unchecked Sendable {
765765

766766
func createDatabase(name: String, charset: String, collation: String?) async throws {
767767
let escapedName = name.replacingOccurrences(of: "\"", with: "\"\"")
768-
let validCharsets = ["UTF8", "LATIN1", "SQL_ASCII"]
768+
let validCharsets = ["UTF8", "LATIN1", "SQL_ASCII", "WIN1252", "EUC_JP",
769+
"EUC_KR", "ISO_8859_5", "KOI8R", "SJIS", "BIG5", "GBK"]
769770
let normalizedCharset = charset.uppercased()
770771
guard validCharsets.contains(normalizedCharset) else {
771772
throw LibPQPluginError(message: "Invalid encoding: \(charset)", sqlState: nil, detail: nil)

Plugins/PostgreSQLDriverPlugin/RedshiftPluginDriver.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,8 @@ final class RedshiftPluginDriver: PluginDatabaseDriver, @unchecked Sendable {
621621

622622
func createDatabase(name: String, charset: String, collation: String?) async throws {
623623
let escapedName = name.replacingOccurrences(of: "\"", with: "\"\"")
624-
let validCharsets = ["UTF8", "LATIN1", "SQL_ASCII"]
624+
let validCharsets = ["UTF8", "LATIN1", "SQL_ASCII", "WIN1252", "EUC_JP",
625+
"EUC_KR", "ISO_8859_5", "KOI8R", "SJIS", "BIG5", "GBK"]
625626
let normalizedCharset = charset.uppercased()
626627
guard validCharsets.contains(normalizedCharset) else {
627628
throw LibPQPluginError(message: "Invalid encoding: \(charset)", sqlState: nil, detail: nil)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//
2+
// CreateDatabaseOptions.swift
3+
// TablePro
4+
//
5+
// Database-type-specific options for CREATE DATABASE dialog.
6+
//
7+
8+
import Foundation
9+
10+
struct CreateDatabaseOptions {
11+
struct Config {
12+
let charsetLabel: String
13+
let collationLabel: String
14+
let defaultCharset: String
15+
let defaultCollation: String
16+
let charsets: [String]
17+
let collations: [String: [String]]
18+
let showOptions: Bool
19+
}
20+
21+
static func config(for type: DatabaseType) -> Config {
22+
if type == .mysql || type == .mariadb {
23+
return Config(
24+
charsetLabel: "Character Set",
25+
collationLabel: "Collation",
26+
defaultCharset: "utf8mb4",
27+
defaultCollation: "utf8mb4_unicode_ci",
28+
charsets: CreateTableOptions.charsets,
29+
collations: CreateTableOptions.collations,
30+
showOptions: true
31+
)
32+
} else if type == .postgresql || type == .redshift {
33+
return Config(
34+
charsetLabel: "Encoding",
35+
collationLabel: "LC_COLLATE",
36+
defaultCharset: "UTF8",
37+
defaultCollation: "en_US.UTF-8",
38+
charsets: postgresqlEncodings,
39+
collations: postgresqlLocales,
40+
showOptions: true
41+
)
42+
} else {
43+
return Config(
44+
charsetLabel: "",
45+
collationLabel: "",
46+
defaultCharset: "",
47+
defaultCollation: "",
48+
charsets: [],
49+
collations: [:],
50+
showOptions: false
51+
)
52+
}
53+
}
54+
55+
private static let postgresqlEncodings = [
56+
"UTF8", "LATIN1", "SQL_ASCII", "WIN1252", "EUC_JP",
57+
"EUC_KR", "ISO_8859_5", "KOI8R", "SJIS", "BIG5", "GBK"
58+
]
59+
60+
// PostgreSQL LC_COLLATE is OS-locale based, not encoding-dependent
61+
private static let localeOptions = ["en_US.UTF-8", "C", "POSIX", "C.UTF-8"]
62+
63+
private static let postgresqlLocales: [String: [String]] = {
64+
var result: [String: [String]] = [:]
65+
for enc in postgresqlEncodings {
66+
result[enc] = localeOptions
67+
}
68+
return result
69+
}()
70+
}

TablePro/Views/DatabaseSwitcher/CreateDatabaseSheet.swift

Lines changed: 44 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,25 @@ import SwiftUI
1010
struct CreateDatabaseSheet: View {
1111
@Environment(\.dismiss) private var dismiss
1212

13+
let databaseType: DatabaseType
1314
let onCreate: (String, String, String?) async throws -> Void
1415

1516
@State private var databaseName = ""
16-
@State private var charset = "utf8mb4"
17-
@State private var collation = "utf8mb4_unicode_ci"
17+
@State private var charset: String
18+
@State private var collation: String
1819
@State private var isCreating = false
1920
@State private var errorMessage: String?
2021

21-
private let charsets = [
22-
"utf8mb4",
23-
"utf8",
24-
"latin1",
25-
"ascii"
26-
]
22+
private let config: CreateDatabaseOptions.Config
2723

28-
private let collations: [String: [String]] = [
29-
"utf8mb4": ["utf8mb4_unicode_ci", "utf8mb4_general_ci", "utf8mb4_bin"],
30-
"utf8": ["utf8_unicode_ci", "utf8_general_ci", "utf8_bin"],
31-
"latin1": ["latin1_swedish_ci", "latin1_general_ci", "latin1_bin"],
32-
"ascii": ["ascii_general_ci", "ascii_bin"]
33-
]
24+
init(databaseType: DatabaseType, onCreate: @escaping (String, String, String?) async throws -> Void) {
25+
self.databaseType = databaseType
26+
self.onCreate = onCreate
27+
let cfg = CreateDatabaseOptions.config(for: databaseType)
28+
self.config = cfg
29+
self._charset = State(initialValue: cfg.defaultCharset)
30+
self._collation = State(initialValue: cfg.defaultCollation)
31+
}
3432

3533
var body: some View {
3634
VStack(spacing: 0) {
@@ -54,36 +52,38 @@ struct CreateDatabaseSheet: View {
5452
.font(.system(size: ThemeEngine.shared.activeTheme.typography.body))
5553
}
5654

57-
// Charset
58-
VStack(alignment: .leading, spacing: 6) {
59-
Text("Character Set")
60-
.font(.system(size: ThemeEngine.shared.activeTheme.typography.small, weight: .medium))
61-
.foregroundStyle(.secondary)
62-
63-
Picker("", selection: $charset) {
64-
ForEach(charsets, id: \.self) { cs in
65-
Text(cs).tag(cs)
55+
if config.showOptions {
56+
// Charset / Encoding
57+
VStack(alignment: .leading, spacing: 6) {
58+
Text(config.charsetLabel)
59+
.font(.system(size: ThemeEngine.shared.activeTheme.typography.small, weight: .medium))
60+
.foregroundStyle(.secondary)
61+
62+
Picker("", selection: $charset) {
63+
ForEach(config.charsets, id: \.self) { cs in
64+
Text(cs).tag(cs)
65+
}
6666
}
67+
.labelsHidden()
68+
.pickerStyle(.menu)
69+
.font(.system(size: ThemeEngine.shared.activeTheme.typography.body))
6770
}
68-
.labelsHidden()
69-
.pickerStyle(.menu)
70-
.font(.system(size: ThemeEngine.shared.activeTheme.typography.body))
71-
}
7271

73-
// Collation
74-
VStack(alignment: .leading, spacing: 6) {
75-
Text("Collation")
76-
.font(.system(size: ThemeEngine.shared.activeTheme.typography.small, weight: .medium))
77-
.foregroundStyle(.secondary)
72+
// Collation / LC_COLLATE
73+
VStack(alignment: .leading, spacing: 6) {
74+
Text(config.collationLabel)
75+
.font(.system(size: ThemeEngine.shared.activeTheme.typography.small, weight: .medium))
76+
.foregroundStyle(.secondary)
7877

79-
Picker("", selection: $collation) {
80-
ForEach(collations[charset] ?? [], id: \.self) { col in
81-
Text(col).tag(col)
78+
Picker("", selection: $collation) {
79+
ForEach(config.collations[charset] ?? [], id: \.self) { col in
80+
Text(col).tag(col)
81+
}
8282
}
83+
.labelsHidden()
84+
.pickerStyle(.menu)
85+
.font(.system(size: ThemeEngine.shared.activeTheme.typography.body))
8386
}
84-
.labelsHidden()
85-
.pickerStyle(.menu)
86-
.font(.system(size: ThemeEngine.shared.activeTheme.typography.body))
8787
}
8888

8989
// Error message
@@ -116,14 +116,12 @@ struct CreateDatabaseSheet: View {
116116
}
117117
.frame(width: 380)
118118
.onExitCommand {
119-
// Prevent dismissing the sheet via ESC while a database is being created
120119
if !isCreating {
121120
dismiss()
122121
}
123122
}
124123
.onChange(of: charset) { _, newCharset in
125-
// Update collation when charset changes
126-
if let firstCollation = collations[newCharset]?.first {
124+
if let firstCollation = config.collations[newCharset]?.first {
127125
collation = firstCollation
128126
}
129127
}
@@ -137,7 +135,11 @@ struct CreateDatabaseSheet: View {
137135

138136
Task {
139137
do {
140-
try await onCreate(databaseName, charset, collation)
138+
if config.showOptions {
139+
try await onCreate(databaseName, charset, collation)
140+
} else {
141+
try await onCreate(databaseName, "", nil)
142+
}
141143
await MainActor.run {
142144
dismiss()
143145
}

TablePro/Views/DatabaseSwitcher/DatabaseSwitcherSheet.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ struct DatabaseSwitcherSheet: View {
116116
.defaultFocus($focus, .search)
117117
.task { await viewModel.fetchDatabases() }
118118
.sheet(isPresented: $showCreateDialog) {
119-
CreateDatabaseSheet { name, charset, collation in
119+
CreateDatabaseSheet(databaseType: databaseType) { name, charset, collation in
120120
try await viewModel.createDatabase(
121121
name: name, charset: charset, collation: collation)
122122
await viewModel.refreshDatabases()
@@ -174,7 +174,9 @@ struct DatabaseSwitcherSheet: View {
174174
.help(String(localized: "Refresh database list"))
175175

176176
// Create (only for non-SQLite)
177-
if databaseType != .sqlite && !isSchemaMode {
177+
if databaseType != .sqlite && databaseType != .redis
178+
&& databaseType != .etcd && !isSchemaMode
179+
{
178180
Button(action: { showCreateDialog = true }) {
179181
Image(systemName: "plus")
180182
.frame(width: 24, height: 24)

0 commit comments

Comments
 (0)