Skip to content

Commit eec73fe

Browse files
authored
Merge pull request #220 from datlechin/refactor/transaction-delegation
refactor: delegate transaction handling to plugin drivers
2 parents b788097 + 41e9c1e commit eec73fe

File tree

14 files changed

+67
-128
lines changed

14 files changed

+67
-128
lines changed

Plugins/ClickHouseDriverPlugin/ClickHousePlugin.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ final class ClickHousePluginDriver: PluginDatabaseDriver, @unchecked Sendable {
6464
var serverVersion: String? { _serverVersion }
6565
var supportsSchemas: Bool { false }
6666
var supportsTransactions: Bool { false }
67+
func beginTransaction() async throws {}
68+
func commitTransaction() async throws {}
69+
func rollbackTransaction() async throws {}
6770
var currentSchema: String? { nil }
6871

6972
init(config: DriverConnectionConfig) {

Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,12 @@ final class MSSQLPluginDriver: PluginDatabaseDriver, @unchecked Sendable {
374374
_ = try await execute(query: "SELECT 1")
375375
}
376376

377+
// MARK: - Transaction Management
378+
379+
func beginTransaction() async throws {
380+
_ = try await execute(query: "BEGIN TRANSACTION")
381+
}
382+
377383
// MARK: - Query Execution
378384

379385
func execute(query: String) async throws -> PluginQueryResult {

Plugins/MongoDBDriverPlugin/MongoDBPluginDriver.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ final class MongoDBPluginDriver: PluginDatabaseDriver {
1818

1919
var serverVersion: String? { mongoConnection?.serverVersion() }
2020
var currentSchema: String? { nil }
21+
var supportsTransactions: Bool { false }
22+
func beginTransaction() async throws {}
23+
func commitTransaction() async throws {}
24+
func rollbackTransaction() async throws {}
2125

2226
init(config: DriverConnectionConfig) {
2327
self.config = config

Plugins/MySQLDriverPlugin/MySQLPluginDriver.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ final class MySQLPluginDriver: PluginDatabaseDriver, @unchecked Sendable {
6666
_ = try await execute(query: "SELECT 1")
6767
}
6868

69+
// MARK: - Transaction Management
70+
71+
func beginTransaction() async throws {
72+
_ = try await execute(query: "START TRANSACTION")
73+
}
74+
6975
// MARK: - Query Execution
7076

7177
func execute(query: String) async throws -> PluginQueryResult {

Plugins/OracleDriverPlugin/OraclePlugin.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ final class OraclePluginDriver: PluginDatabaseDriver, @unchecked Sendable {
8080
_ = try await execute(query: "SELECT 1 FROM DUAL")
8181
}
8282

83+
// MARK: - Transaction Management
84+
85+
func beginTransaction() async throws {
86+
// Oracle uses implicit transactions — no explicit BEGIN needed
87+
}
88+
8389
// MARK: - Query Execution
8490

8591
func execute(query: String) async throws -> PluginQueryResult {

TablePro/Core/Database/DatabaseDriver.swift

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -290,23 +290,6 @@ extension DatabaseDriver {
290290
.warning("Failed to set query timeout: \(error.localizedDescription)")
291291
}
292292
}
293-
294-
// MARK: - Default Transaction Implementation
295-
296-
/// Default transaction implementation using database-specific SQL
297-
func beginTransaction() async throws {
298-
let sql = connection.type.beginTransactionSQL
299-
guard !sql.isEmpty else { return }
300-
_ = try await execute(query: sql)
301-
}
302-
303-
func commitTransaction() async throws {
304-
_ = try await execute(query: "COMMIT")
305-
}
306-
307-
func rollbackTransaction() async throws {
308-
_ = try await execute(query: "ROLLBACK")
309-
}
310293
}
311294

312295
/// Factory for creating database drivers via plugin lookup

TablePro/Core/Plugins/PluginDriverAdapter.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,15 +239,15 @@ final class PluginDriverAdapter: DatabaseDriver, SchemaSwitchable {
239239
// MARK: - Transaction Management
240240

241241
func beginTransaction() async throws {
242-
_ = try await pluginDriver.execute(query: "BEGIN")
242+
try await pluginDriver.beginTransaction()
243243
}
244244

245245
func commitTransaction() async throws {
246-
_ = try await pluginDriver.execute(query: "COMMIT")
246+
try await pluginDriver.commitTransaction()
247247
}
248248

249249
func rollbackTransaction() async throws {
250-
_ = try await pluginDriver.execute(query: "ROLLBACK")
250+
try await pluginDriver.rollbackTransaction()
251251
}
252252

253253
// MARK: - Schema Switching

TablePro/Core/Services/Export/ImportService.swift

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,7 @@ final class ImportService {
133133

134134
// 5. Begin transaction (if enabled)
135135
if config.wrapInTransaction {
136-
let beginStmt = connection.type.beginTransactionSQL
137-
if !beginStmt.isEmpty {
138-
_ = try await driver.execute(query: beginStmt)
139-
}
136+
try await driver.beginTransaction()
140137
}
141138

142139
// 6. Parse and execute statements (single pass — no prior counting pass)
@@ -174,10 +171,7 @@ final class ImportService {
174171

175172
// 7. Commit transaction (if enabled)
176173
if config.wrapInTransaction {
177-
let commitStmt = commitStatement(for: connection.type)
178-
if !commitStmt.isEmpty {
179-
_ = try await driver.execute(query: commitStmt)
180-
}
174+
try await driver.commitTransaction()
181175
}
182176

183177
// 8. Re-enable FK checks (if enabled) - AFTER transaction
@@ -191,10 +185,7 @@ final class ImportService {
191185
// Rollback on error - this is CRITICAL and must not fail silently
192186
if config.wrapInTransaction {
193187
do {
194-
let rollbackStmt = rollbackStatement(for: connection.type)
195-
if !rollbackStmt.isEmpty {
196-
_ = try await driver.execute(query: rollbackStmt)
197-
}
188+
try await driver.rollbackTransaction()
198189
} catch let rollbackError {
199190
throw ImportError.rollbackFailed(rollbackError.localizedDescription)
200191
}
@@ -311,23 +302,4 @@ final class ImportService {
311302
return []
312303
}
313304
}
314-
315-
316-
private func commitStatement(for dbType: DatabaseType) -> String {
317-
switch dbType {
318-
case .mongodb, .redis, .clickhouse:
319-
return ""
320-
default:
321-
return "COMMIT"
322-
}
323-
}
324-
325-
private func rollbackStatement(for dbType: DatabaseType) -> String {
326-
switch dbType {
327-
case .mongodb, .redis, .clickhouse:
328-
return ""
329-
default:
330-
return "ROLLBACK"
331-
}
332-
}
333305
}

TablePro/Models/Connection/DatabaseConnection.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -287,16 +287,6 @@ enum DatabaseType: String, CaseIterable, Identifiable, Codable {
287287
}
288288
}
289289

290-
var beginTransactionSQL: String {
291-
switch self {
292-
case .mysql, .mariadb: return "START TRANSACTION"
293-
case .postgresql, .redshift, .sqlite: return "BEGIN"
294-
case .mssql: return "BEGIN TRANSACTION"
295-
case .oracle: return ""
296-
case .mongodb, .redis, .clickhouse: return ""
297-
}
298-
}
299-
300290
/// Whether this database type supports SQL-based schema editing (ALTER TABLE etc.)
301291
var supportsSchemaEditing: Bool {
302292
switch self {

TablePro/Views/Main/Extensions/MainContentCoordinator+Discard.swift

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,19 @@ extension MainContentCoordinator {
1616
throw DatabaseError.notConnected
1717
}
1818

19-
let dbType = connection.type
20-
let supportsTransactions = dbType != .redis && dbType != .mongodb && dbType != .clickhouse
21-
var allStatements: [ParameterizedStatement] = []
22-
23-
if supportsTransactions {
24-
allStatements.append(ParameterizedStatement(sql: dbType.beginTransactionSQL, parameters: []))
25-
}
26-
27-
allStatements.append(contentsOf: statements)
28-
29-
if supportsTransactions {
30-
allStatements.append(ParameterizedStatement(sql: "COMMIT", parameters: []))
31-
}
19+
try await driver.beginTransaction()
3220

3321
do {
34-
for stmt in allStatements {
22+
for stmt in statements {
3523
if stmt.parameters.isEmpty {
3624
_ = try await driver.execute(query: stmt.sql)
3725
} else {
3826
_ = try await driver.executeParameterized(query: stmt.sql, parameters: stmt.parameters)
3927
}
4028
}
29+
try await driver.commitTransaction()
4130
} catch {
42-
if supportsTransactions {
43-
_ = try? await driver.execute(query: "ROLLBACK")
44-
}
31+
try? await driver.rollbackTransaction()
4532
throw error
4633
}
4734
}

0 commit comments

Comments
 (0)