我从 Vapor 4 开始,在旅程的一开始就卡住了。
我知道 JavaScript 中的 Promises,并且我想我对 Swift 的 Futures 有所了解。我认为我的问题是事实,可悲的是,大多数教程都使用wait()
它们来保持他们的例子简短而简单。在 Vapor 中,我遇到了 EventLoopwait()
并被禁止进入。
我正在尝试做的事情
我正在尝试对 MySQL 数据库执行一些查询,这些查询需要串行执行:
- 两个表被截断。
- 然后我将第三个表中的所有行复制到一个截断表中。
- 最后,我正在查询该填充表,尝试遍历每个匹配的结果并将其插入到另一个截断表中。
出了什么问题/我需要帮助的地方
- 经过几天难以理解的编译错误,它现在正在运行。第一部分正在执行,但它缺少某些回调的正确实现。我正在考虑JavaScript 中的Promise.all([])之类的东西。我不想嵌套这两个查询,因为我认为拥有一个表名数组并为每个查询执行查询会更干净。这是我不知道该怎么做的第一件小事。
- 最重要的是:第二步,将匹配的行插入到另一个表中,失败了。在 Xcode 的控制台中,它会打印很多次:
[ ERROR ] Connection request timed out. This might indicate a connection deadlock in your application. If you're running long running requests, consider increasing your connection timeout. [database-id: mysql, request-id: F159E838-0E90-4025-929E-596A6A66A502]
我想有几种更好的方法可以解决这个问题,但是因为我想学习和思考一些我想尝试实现的其他任务,我想通过串行执行这些查询来解决它。
我的代码
Controllers/RubricsTreeController.swift
import Fluent
import FluentMySQLDriver
import MySQLNIO
import Vapor
struct RubricsTreeController: RouteCollection {
func rebuild(req: Request) throws -> EventLoopFuture<[Rubric]> {
let mysql = req.db as? MySQLDatabase
// Clear database tables
let tables = ["rubrics", "rubrics_tree"]
for table in tables {
mysql!.simpleQuery("TRUNCATE TABLE `\(table)`") // <-- HERE …
// … I´d like to somehow collect each returned Future in an Array …
}
// … and wait for all Futures to finish
// Copy contents from imported `import` into table `rubrics`
mysql!.simpleQuery("INSERT INTO `rubrics` SELECT * FROM `import`")
// Iterate over all Rubrics and build the Tree by inserting each as a Node into the Nested Set
let nestedSet = NestedSet(database: mysql!, table: "rubrics_tree")
var nestedSetRootId = 1;
let rubrics = Rubric.query(on: mysql as! Database)
.filter(\.$level == 0)
.sort(\.$level)
.sort(\.$parentId)
.sort(\.$sorting)
.sort(\.$id)
.all()
.flatMapEachThrowing { rubric -> Rubric in
try? nestedSet.newRoot(rootId: UInt16(nestedSetRootId), foreignId: UInt64(rubric.id!))
nestedSetRootId += 1
return rubric
}
return rubrics
}
}
Helpers/NestedSet.swift
import Fluent
import FluentMySQLDriver
import Vapor
class NestedSet {
var database: MySQLDatabase
var table: String
init(database: MySQLDatabase, table: String) {
self.database = database
self.table = table
}
func newRoot(id: UUID? = nil, rootId: UInt16, foreignId: UInt64? = nil) throws -> EventLoopFuture<Bool> {
return database
.simpleQuery("INSERT INTO `\(table)`(rootId, leftValue, rightValue, nodeLevel, nodeMoved, foreignId) VALUES(\(rootId), 1, 2, 0, 0, \(foreignId ?? 0)")
.map { _ -> Bool in
true
}
}
// func newRoot(id: UUID? = nil, foreignId: UInt64? = nil) throws -> EventLoopFuture<EventLoopFuture<Bool>> {
// return database
// .simpleQuery("SELECT COALESCE(MAX(rootId), 0) AS highestRootId FROM `\(table)`")
// .flatMapThrowing { (results: [MySQLRow]) in
// let highestRootId = (results[0].column("highestRootId")?.uint64)!
// let rootId = UInt16(highestRootId + 1)
// return try self.newRoot(id: id, rootId: rootId, foreignId: foreignId)
// }
// }
}
我很好奇你的想法和改进!:)