Implementation for deleteReference seems to be missing
foscomputerservices opened this issue · 1 comments
It doesn't appear that MySql is performing drop foreign key when requested to do so.
I have the following code, which is a secondary migration on a table.
struct PromoUpdate: Migration {
static let migrationName = "promotion"
typealias Database = MySQLDatabase
static func prepare(on connection: MySQLConnection) -> Future<Void> {
let update = MySQLDatabase.update(PurchaseTransaction.self, on: connection) { updater in
updater.field(for: \PurchaseTransaction.promotionId)
updater.reference(from: \PurchaseTransaction.promotionId, to: \Promotion.id, onDelete: .restrict)
}
return try! PurchaseTransaction.defaultModel(after: update, on: connection)
}
static func revert(on connection: MySQLConnection) -> Future<Void> {
return MySQLDatabase.update(PurchaseTransaction.self, on: connection) { updater in
updater.deleteReference(from: \PurchaseTransaction.promotionId, to: \Promotion.id)
updater.deleteField(for: \PurchaseTransaction.promotionId)
}
}
}
Looking at the SQL generated during revert, I see the following:
[ INFO ] Reverting migration 'promotion' (/.../.build/checkouts/fluent.git-6251908308727715749/Sources/Fluent/Migration/Migrations.swift:151)
[mysql] [2018-08-13 23:40:35 +0000] ALTER TABLE `purchase_transactions` []
[mysql] [2018-08-13 23:40:35 +0000] DELETE FROM `fluent` WHERE `fluent`.`name` = (?) [string("promotion")]
[mysql] [2018-08-13 23:40:35 +0000] SELECT * FROM `fluent` WHERE `fluent`.`name` = (?) LIMIT 1 OFFSET 0 [string("Promotion")]
When the next table, Promotion, is attempted to be deleted, I get the following and a crash: "Fatal error: 'try!' expression unexpectedly raised an error:
[ INFO ] Reverting migration 'Promotion' (/.../.build/checkouts/fluent.git-6251908308727715749/Sources/Fluent/Migration/Migrations.swift:151)
[mysql] [2018-08-13 23:40:35 +0000] DROP TABLE `promotions` []
In looking at the database, the foreign key constraint remains.
mysql> SELECT TABLE_NAME,
-> COLUMN_NAME,
-> CONSTRAINT_NAME,
-> REFERENCED_TABLE_NAME,
-> REFERENCED_COLUMN_NAME
-> FROM KEY_COLUMN_USAGE
-> WHERE TABLE_SCHEMA = "efl_test"
-> AND TABLE_NAME = "purchase_transactions"
-> AND REFERENCED_COLUMN_NAME IS NOT NULL;
+-----------------------+-------------+---------------------------------------------+-----------------------+------------------------+
| TABLE_NAME | COLUMN_NAME | CONSTRAINT_NAME | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME |
+-----------------------+-------------+---------------------------------------------+-----------------------+------------------------+
| purchase_transactions | promotionId | fk:b335393d3b362ad33aec3378c572f0ed29cb7e3c | promotions | id |
| purchase_transactions | purchaseId | fk:c2f70206d2df6cb75467a851374e05c995c1cf51 | purchases | id |
+-----------------------+-------------+---------------------------------------------+-----------------------+------------------------+
2 rows in set (0.00 sec)
The only code that I can find that has 'ALTER TABLE' in it is in MySQLAlterTable.swift, and I don't see any 'DROP' code in there at all.
public func serialize(_ binds: inout [Encodable]) -> String {
var sql: [String] = []
sql.append("ALTER TABLE")
sql.append(table.serialize(&binds))
let actions = columns.map {
let sql = "ADD COLUMN " + $0.serialize(&binds)
if let position = columnPositions[$0.column] {
return sql + " " + position.serialize(&binds)
} else {
return sql
}
} + constraints.map { "ADD " + $0.serialize(&binds) }
sql.append(actions.joined(separator: ", "))
return sql.joined(separator: " ")
}
I came across this issue as I'm attempting to implement unit tests as described in the Server Side Swift with Vapor book, where they recommend calling vapor revert --all -y to reset the database.
This has been fixed, thanks!