From e87e42db7ed69567ea75ae8e967109b44ec4c54b Mon Sep 17 00:00:00 2001 From: gjeck Date: Thu, 23 Jan 2020 11:41:58 -0800 Subject: [PATCH] Add support for renaming columns within a table SQLite introduced enhancements to the `ALTER TABLE` command in 3.25.0. iOS 13.0+, macOS 10.15+, tvOS 13.0+, and watchOS 6.0+ have a SQLite library bundled higher than 3.25.0. For more information see https://www.sqlite.org/lang_altertable.html --- .../Schema/TableDefinition.swift | 34 +++++++++++++++++++ Tests/GRDBTests/TableDefinitionTests.swift | 21 ++++++++++++ 2 files changed, 55 insertions(+) diff --git a/GRDB/QueryInterface/Schema/TableDefinition.swift b/GRDB/QueryInterface/Schema/TableDefinition.swift index 10a18d68b8..e95f7960d9 100644 --- a/GRDB/QueryInterface/Schema/TableDefinition.swift +++ b/GRDB/QueryInterface/Schema/TableDefinition.swift @@ -657,6 +657,7 @@ public final class TableDefinition { public final class TableAlteration { private let name: String private var addedColumns: [ColumnDefinition] = [] + private var renamedColumns: [(oldColumn: ColumnDefinition, newColumn: ColumnDefinition)] = [] init(name: String) { self.name = name @@ -680,9 +681,42 @@ public final class TableAlteration { addedColumns.append(column) return column } + + #if !os(OSX) + /// Renames a column in a table. + /// + /// try db.alter(table: "player") { t in + /// t.rename(column: "url", to: "home_url") + /// } + /// + /// See https://www.sqlite.org/lang_altertable.html + /// + /// - parameter name: the column name to rename. + /// - parameter newName: the new name of the column. + @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *) + public func rename(column name: String, to newName: String) { + let old = ColumnDefinition(name: name, type: nil) + let new = ColumnDefinition(name: newName, type: nil) + renamedColumns.append((oldColumn: old, newColumn: new)) + } + #endif fileprivate func sql(_ db: Database) throws -> String { var statements: [String] = [] + + #if !os(OSX) + for (oldColumn, newColumn) in renamedColumns { + var chunks: [String] = [] + chunks.append("ALTER TABLE") + chunks.append(name.quotedDatabaseIdentifier) + chunks.append("RENAME COLUMN") + chunks.append(oldColumn.name.quotedDatabaseIdentifier) + chunks.append("TO") + chunks.append(newColumn.name.quotedDatabaseIdentifier) + let statement = chunks.joined(separator: " ") + statements.append(statement) + } + #endif for column in addedColumns { var chunks: [String] = [] diff --git a/Tests/GRDBTests/TableDefinitionTests.swift b/Tests/GRDBTests/TableDefinitionTests.swift index 0f7d84afaf..6176c7b437 100644 --- a/Tests/GRDBTests/TableDefinitionTests.swift +++ b/Tests/GRDBTests/TableDefinitionTests.swift @@ -495,6 +495,27 @@ class TableDefinitionTests: GRDBTestCase { assertEqualSQL(sqlQueries[sqlQueries.count - 1], "ALTER TABLE \"test\" ADD COLUMN \"e\"") } } + + #if !os(OSX) + @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *) + func testAlterTableRenameColumn() throws { + let dbQueue = try makeDatabaseQueue() + try dbQueue.inDatabase { db in + try db.create(table: "test") { t in + t.column("a", .text) + } + + sqlQueries.removeAll() + try db.alter(table: "test") { t in + t.rename(column: "a", to: "b") + t.add(column: "e") + } + + assertEqualSQL(sqlQueries[sqlQueries.count - 2], "ALTER TABLE \"test\" RENAME COLUMN \"a\" TO \"b\"") + assertEqualSQL(sqlQueries[sqlQueries.count - 1], "ALTER TABLE \"test\" ADD COLUMN \"e\"") + } + } + #endif func testDropTable() throws { let dbQueue = try makeDatabaseQueue()